Print this page
12721 would like svcadm disable -c
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
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
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 - * Copyright 2019 Joyent, Inc.
24 + * Copyright 2020 Joyent, Inc.
25 25 * Copyright 2012 Milan Jurik. All rights reserved.
26 26 * Copyright 2017 RackTop Systems.
27 27 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
28 28 */
29 29
30 30
31 31 #include <alloca.h>
32 32 #include <assert.h>
33 33 #include <ctype.h>
34 34 #include <door.h>
35 35 #include <errno.h>
36 36 #include <fcntl.h>
37 37 #include <fnmatch.h>
38 38 #include <inttypes.h>
39 39 #include <libintl.h>
40 40 #include <libnvpair.h>
41 41 #include <libscf.h>
42 42 #include <libscf_priv.h>
43 43 #include <libtecla.h>
44 44 #include <libuutil.h>
45 45 #include <limits.h>
46 46 #include <locale.h>
47 47 #include <stdarg.h>
48 48 #include <string.h>
49 49 #include <strings.h>
50 50 #include <time.h>
51 51 #include <unistd.h>
52 52 #include <wait.h>
53 53 #include <poll.h>
54 54
55 55 #include <libxml/tree.h>
56 56
57 57 #include <sys/param.h>
58 58
59 59 #include <sys/stat.h>
60 60 #include <sys/mman.h>
61 61
62 62 #include "svccfg.h"
63 63 #include "notify_params.h"
64 64 #include "manifest_hash.h"
65 65 #include "manifest_find.h"
66 66
67 67 /* The colon namespaces in each entity (each followed by a newline). */
68 68 #define COLON_NAMESPACES ":properties\n"
69 69
70 70 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX"
71 71
72 72 /* These are characters which the lexer requires to be in double-quotes. */
73 73 #define CHARS_TO_QUOTE " \t\n\\>=\"()"
74 74
75 75 #define HASH_SIZE 16
76 76 #define HASH_PG_TYPE "framework"
77 77 #define HASH_PG_FLAGS 0
78 78 #define HASH_PROP "md5sum"
79 79
80 80 /*
81 81 * Indentation used in the output of the describe subcommand.
82 82 */
83 83 #define TMPL_VALUE_INDENT " "
84 84 #define TMPL_INDENT " "
85 85 #define TMPL_INDENT_2X " "
86 86 #define TMPL_CHOICE_INDENT " "
87 87
88 88 /*
89 89 * Directory locations for manifests
90 90 */
91 91 #define VARSVC_DIR "/var/svc/manifest"
92 92 #define LIBSVC_DIR "/lib/svc/manifest"
93 93 #define VARSVC_PR "var_svc_manifest"
94 94 #define LIBSVC_PR "lib_svc_manifest"
95 95 #define MFSTFILEPR "manifestfile"
96 96
97 97 #define SUPPORTPROP "support"
98 98
99 99 #define MFSTHISTFILE "/lib/svc/share/mfsthistory"
100 100
101 101 #define MFSTFILE_MAX 16
102 102
103 103 /*
104 104 * These are the classes of elements which may appear as children of service
105 105 * or instance elements in XML manifests.
106 106 */
107 107 struct entity_elts {
108 108 xmlNodePtr create_default_instance;
109 109 xmlNodePtr single_instance;
110 110 xmlNodePtr restarter;
111 111 xmlNodePtr dependencies;
112 112 xmlNodePtr dependents;
113 113 xmlNodePtr method_context;
114 114 xmlNodePtr exec_methods;
115 115 xmlNodePtr notify_params;
116 116 xmlNodePtr property_groups;
117 117 xmlNodePtr instances;
118 118 xmlNodePtr stability;
119 119 xmlNodePtr template;
120 120 };
121 121
122 122 /*
123 123 * Likewise for property_group elements.
124 124 */
125 125 struct pg_elts {
126 126 xmlNodePtr stability;
127 127 xmlNodePtr propvals;
128 128 xmlNodePtr properties;
129 129 };
130 130
131 131 /*
132 132 * Likewise for template elements.
133 133 */
134 134 struct template_elts {
135 135 xmlNodePtr common_name;
136 136 xmlNodePtr description;
137 137 xmlNodePtr documentation;
138 138 };
139 139
140 140 /*
141 141 * Likewise for type (for notification parameters) elements.
142 142 */
143 143 struct params_elts {
144 144 xmlNodePtr paramval;
145 145 xmlNodePtr parameter;
146 146 };
147 147
148 148 /*
149 149 * This structure is for snaplevel lists. They are convenient because libscf
150 150 * only allows traversing snaplevels in one direction.
151 151 */
152 152 struct snaplevel {
153 153 uu_list_node_t list_node;
154 154 scf_snaplevel_t *sl;
155 155 };
156 156
157 157 /*
158 158 * This is used for communication between lscf_service_export and
159 159 * export_callback.
160 160 */
161 161 struct export_args {
162 162 const char *filename;
163 163 int flags;
164 164 };
165 165
166 166 /*
167 167 * The service_manifest structure is used by the upgrade process
168 168 * to create a list of service to manifest linkages from the manifests
169 169 * in a set of given directories.
170 170 */
171 171 typedef struct service_manifest {
172 172 const char *servicename;
173 173 uu_list_t *mfstlist;
174 174 size_t mfstlist_sz;
175 175
176 176 uu_avl_node_t svcmfst_node;
177 177 } service_manifest_t;
178 178
179 179 /*
180 180 * Structure to track the manifest file property group
181 181 * and the manifest file associated with that property
182 182 * group. Also, a flag to keep the access once it has
183 183 * been checked.
184 184 */
185 185 struct mpg_mfile {
186 186 char *mpg;
187 187 char *mfile;
188 188 int access;
189 189 };
190 190
191 191 const char * const scf_pg_general = SCF_PG_GENERAL;
192 192 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
193 193 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
194 194 const char * const scf_property_external = "external";
195 195
196 196 const char * const snap_initial = "initial";
197 197 const char * const snap_lastimport = "last-import";
198 198 const char * const snap_previous = "previous";
199 199 const char * const snap_running = "running";
200 200
201 201 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */
202 202
203 203 ssize_t max_scf_fmri_len;
204 204 ssize_t max_scf_name_len;
205 205 ssize_t max_scf_pg_type_len;
206 206 ssize_t max_scf_value_len;
207 207 static size_t max_scf_len;
208 208
209 209 static scf_scope_t *cur_scope;
210 210 static scf_service_t *cur_svc = NULL;
211 211 static scf_instance_t *cur_inst = NULL;
212 212 static scf_snapshot_t *cur_snap = NULL;
213 213 static scf_snaplevel_t *cur_level = NULL;
214 214
215 215 static uu_list_pool_t *snaplevel_pool;
216 216 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
217 217 static uu_list_t *cur_levels;
218 218 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */
219 219
220 220 static FILE *tempfile = NULL;
221 221 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
222 222
223 223 static const char *emsg_entity_not_selected;
224 224 static const char *emsg_permission_denied;
225 225 static const char *emsg_create_xml;
226 226 static const char *emsg_cant_modify_snapshots;
227 227 static const char *emsg_invalid_for_snapshot;
228 228 static const char *emsg_read_only;
229 229 static const char *emsg_deleted;
230 230 static const char *emsg_invalid_pg_name;
231 231 static const char *emsg_invalid_prop_name;
232 232 static const char *emsg_no_such_pg;
233 233 static const char *emsg_fmri_invalid_pg_name;
234 234 static const char *emsg_fmri_invalid_pg_name_type;
235 235 static const char *emsg_pg_added;
236 236 static const char *emsg_pg_changed;
237 237 static const char *emsg_pg_deleted;
238 238 static const char *emsg_pg_mod_perm;
239 239 static const char *emsg_pg_add_perm;
240 240 static const char *emsg_pg_del_perm;
241 241 static const char *emsg_snap_perm;
242 242 static const char *emsg_dpt_dangling;
243 243 static const char *emsg_dpt_no_dep;
244 244
245 245 static int li_only = 0;
246 246 static int no_refresh = 0;
247 247
248 248 /* how long in ns we should wait between checks for a pg */
249 249 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
250 250
251 251 /* import globals, to minimize allocations */
252 252 static scf_scope_t *imp_scope = NULL;
253 253 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
254 254 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
255 255 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
256 256 static scf_snapshot_t *imp_rsnap = NULL;
257 257 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
258 258 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
259 259 static scf_property_t *imp_prop = NULL;
260 260 static scf_iter_t *imp_iter = NULL;
261 261 static scf_iter_t *imp_rpg_iter = NULL;
262 262 static scf_iter_t *imp_up_iter = NULL;
263 263 static scf_transaction_t *imp_tx = NULL; /* always reset this */
264 264 static char *imp_str = NULL;
265 265 static size_t imp_str_sz;
266 266 static char *imp_tsname = NULL;
267 267 static char *imp_fe1 = NULL; /* for fmri_equal() */
268 268 static char *imp_fe2 = NULL;
269 269 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */
270 270
271 271 /* upgrade_dependents() globals */
272 272 static scf_instance_t *ud_inst = NULL;
273 273 static scf_snaplevel_t *ud_snpl = NULL;
274 274 static scf_propertygroup_t *ud_pg = NULL;
275 275 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
276 276 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
277 277 static int ud_run_dpts_pg_set = 0;
278 278 static scf_property_t *ud_prop = NULL;
279 279 static scf_property_t *ud_dpt_prop = NULL;
280 280 static scf_value_t *ud_val = NULL;
281 281 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
282 282 static scf_transaction_t *ud_tx = NULL;
283 283 static char *ud_ctarg = NULL;
284 284 static char *ud_oldtarg = NULL;
285 285 static char *ud_name = NULL;
286 286
287 287 /* export globals */
288 288 static scf_instance_t *exp_inst;
289 289 static scf_propertygroup_t *exp_pg;
290 290 static scf_property_t *exp_prop;
291 291 static scf_value_t *exp_val;
292 292 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
293 293 static char *exp_str;
294 294 static size_t exp_str_sz;
295 295
296 296 /* cleanup globals */
297 297 static uu_avl_pool_t *service_manifest_pool = NULL;
298 298 static uu_avl_t *service_manifest_tree = NULL;
299 299
300 300 static void scfdie_lineno(int lineno) __NORETURN;
301 301
302 302 static char *start_method_names[] = {
303 303 "start",
304 304 "inetd_start",
305 305 NULL
306 306 };
307 307
308 308 static struct uri_scheme {
309 309 const char *scheme;
310 310 const char *protocol;
311 311 } uri_scheme[] = {
312 312 { "mailto", "smtp" },
313 313 { "snmp", "snmp" },
314 314 { "syslog", "syslog" },
315 315 { NULL, NULL }
316 316 };
317 317 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
318 318 sizeof (struct uri_scheme)) - 1)
319 319
320 320 static int
321 321 check_uri_scheme(const char *scheme)
322 322 {
323 323 int i;
324 324
325 325 for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
326 326 if (strcmp(scheme, uri_scheme[i].scheme) == 0)
327 327 return (i);
328 328 }
329 329
330 330 return (-1);
331 331 }
332 332
333 333 static int
334 334 check_uri_protocol(const char *p)
335 335 {
336 336 int i;
337 337
338 338 for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
339 339 if (strcmp(p, uri_scheme[i].protocol) == 0)
340 340 return (i);
341 341 }
342 342
343 343 return (-1);
344 344 }
345 345
346 346 /*
347 347 * For unexpected libscf errors.
348 348 */
349 349 #ifdef NDEBUG
350 350
351 351 static void scfdie(void) __NORETURN;
352 352
353 353 static void
354 354 scfdie(void)
355 355 {
356 356 scf_error_t err = scf_error();
357 357
358 358 if (err == SCF_ERROR_CONNECTION_BROKEN)
359 359 uu_die(gettext("Repository connection broken. Exiting.\n"));
360 360
361 361 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"),
362 362 scf_strerror(err));
363 363 }
364 364
365 365 #else
366 366
367 367 #define scfdie() scfdie_lineno(__LINE__)
368 368
369 369 static void
370 370 scfdie_lineno(int lineno)
371 371 {
372 372 scf_error_t err = scf_error();
373 373
374 374 if (err == SCF_ERROR_CONNECTION_BROKEN)
375 375 uu_die(gettext("Repository connection broken. Exiting.\n"));
376 376
377 377 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
378 378 ": %s.\n"), lineno, scf_strerror(err));
379 379 }
380 380
381 381 #endif
382 382
383 383 static void
384 384 scfwarn(void)
385 385 {
386 386 warn(gettext("Unexpected libscf error: %s.\n"),
387 387 scf_strerror(scf_error()));
388 388 }
389 389
390 390 /*
391 391 * Clear a field of a structure.
392 392 */
393 393 static int
394 394 clear_int(void *a, void *b)
395 395 {
396 396 /* LINTED */
397 397 *(int *)((char *)a + (size_t)b) = 0;
398 398
399 399 return (UU_WALK_NEXT);
400 400 }
401 401
402 402 static int
403 403 scferror2errno(scf_error_t err)
404 404 {
405 405 switch (err) {
406 406 case SCF_ERROR_BACKEND_ACCESS:
407 407 return (EACCES);
408 408
409 409 case SCF_ERROR_BACKEND_READONLY:
410 410 return (EROFS);
411 411
412 412 case SCF_ERROR_CONNECTION_BROKEN:
413 413 return (ECONNABORTED);
414 414
415 415 case SCF_ERROR_CONSTRAINT_VIOLATED:
416 416 case SCF_ERROR_INVALID_ARGUMENT:
417 417 return (EINVAL);
418 418
419 419 case SCF_ERROR_DELETED:
420 420 return (ECANCELED);
421 421
422 422 case SCF_ERROR_EXISTS:
423 423 return (EEXIST);
424 424
425 425 case SCF_ERROR_NO_MEMORY:
426 426 return (ENOMEM);
427 427
428 428 case SCF_ERROR_NO_RESOURCES:
429 429 return (ENOSPC);
430 430
431 431 case SCF_ERROR_NOT_FOUND:
432 432 return (ENOENT);
433 433
434 434 case SCF_ERROR_PERMISSION_DENIED:
435 435 return (EPERM);
436 436
437 437 default:
438 438 #ifndef NDEBUG
439 439 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
440 440 __FILE__, __LINE__, err);
441 441 #else
442 442 (void) fprintf(stderr, "Unknown libscf error %d.\n", err);
443 443 #endif
444 444 abort();
445 445 /* NOTREACHED */
446 446 }
447 447 }
448 448
449 449 static int
450 450 entity_get_pg(void *ent, int issvc, const char *name,
451 451 scf_propertygroup_t *pg)
452 452 {
453 453 if (issvc)
454 454 return (scf_service_get_pg(ent, name, pg));
455 455 else
456 456 return (scf_instance_get_pg(ent, name, pg));
457 457 }
458 458
459 459 static void
460 460 entity_destroy(void *ent, int issvc)
461 461 {
462 462 if (issvc)
463 463 scf_service_destroy(ent);
464 464 else
465 465 scf_instance_destroy(ent);
466 466 }
467 467
468 468 static int
469 469 get_pg(const char *pg_name, scf_propertygroup_t *pg)
470 470 {
471 471 int ret;
472 472
473 473 if (cur_level != NULL)
474 474 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
475 475 else if (cur_inst != NULL)
476 476 ret = scf_instance_get_pg(cur_inst, pg_name, pg);
477 477 else
478 478 ret = scf_service_get_pg(cur_svc, pg_name, pg);
479 479
480 480 return (ret);
481 481 }
482 482
483 483 /*
484 484 * Find a snaplevel in a snapshot. If get_svc is true, find the service
485 485 * snaplevel. Otherwise find the instance snaplevel.
486 486 *
487 487 * Returns
488 488 * 0 - success
489 489 * ECONNABORTED - repository connection broken
490 490 * ECANCELED - instance containing snap was deleted
491 491 * ENOENT - snap has no snaplevels
492 492 * - requested snaplevel not found
493 493 */
494 494 static int
495 495 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
496 496 {
497 497 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
498 498 switch (scf_error()) {
499 499 case SCF_ERROR_CONNECTION_BROKEN:
500 500 case SCF_ERROR_DELETED:
501 501 case SCF_ERROR_NOT_FOUND:
502 502 return (scferror2errno(scf_error()));
503 503
504 504 case SCF_ERROR_HANDLE_MISMATCH:
505 505 case SCF_ERROR_NOT_BOUND:
506 506 case SCF_ERROR_NOT_SET:
507 507 default:
508 508 bad_error("scf_snapshot_get_base_snaplevel",
509 509 scf_error());
510 510 }
511 511 }
512 512
513 513 for (;;) {
514 514 ssize_t ssz;
515 515
516 516 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
517 517 if (ssz >= 0) {
518 518 if (!get_svc)
519 519 return (0);
520 520 } else {
521 521 switch (scf_error()) {
522 522 case SCF_ERROR_CONSTRAINT_VIOLATED:
523 523 if (get_svc)
524 524 return (0);
525 525 break;
526 526
527 527 case SCF_ERROR_DELETED:
528 528 case SCF_ERROR_CONNECTION_BROKEN:
529 529 return (scferror2errno(scf_error()));
530 530
531 531 case SCF_ERROR_NOT_SET:
532 532 case SCF_ERROR_NOT_BOUND:
533 533 default:
534 534 bad_error("scf_snaplevel_get_instance_name",
535 535 scf_error());
536 536 }
537 537 }
538 538
539 539 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
540 540 switch (scf_error()) {
541 541 case SCF_ERROR_NOT_FOUND:
542 542 case SCF_ERROR_CONNECTION_BROKEN:
543 543 case SCF_ERROR_DELETED:
544 544 return (scferror2errno(scf_error()));
545 545
546 546 case SCF_ERROR_HANDLE_MISMATCH:
547 547 case SCF_ERROR_NOT_BOUND:
548 548 case SCF_ERROR_NOT_SET:
549 549 case SCF_ERROR_INVALID_ARGUMENT:
550 550 default:
551 551 bad_error("scf_snaplevel_get_next_snaplevel",
552 552 scf_error());
553 553 }
554 554 }
555 555 }
556 556 }
557 557
558 558 /*
559 559 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has
560 560 * a running snapshot, and that snapshot has an instance snaplevel, set pg to
561 561 * the property group named name in it. If it doesn't have a running
562 562 * snapshot, set pg to the instance's current property group named name.
563 563 *
564 564 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
565 565 * its instances. If one has a running snapshot with a service snaplevel, set
566 566 * pg to the property group named name in it. If no such snaplevel could be
567 567 * found, set pg to the service's current property group named name.
568 568 *
569 569 * iter, inst, snap, and snpl are required scratch objects.
570 570 *
571 571 * Returns
572 572 * 0 - success
573 573 * ECONNABORTED - repository connection broken
574 574 * ECANCELED - ent was deleted
575 575 * ENOENT - no such property group
576 576 * EINVAL - name is an invalid property group name
577 577 * EBADF - found running snapshot is missing a snaplevel
578 578 */
579 579 static int
580 580 entity_get_running_pg(void *ent, int issvc, const char *name,
581 581 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
582 582 scf_snapshot_t *snap, scf_snaplevel_t *snpl)
583 583 {
584 584 int r;
585 585
586 586 if (issvc) {
587 587 /* Search for an instance with a running snapshot. */
588 588 if (scf_iter_service_instances(iter, ent) != 0) {
589 589 switch (scf_error()) {
590 590 case SCF_ERROR_DELETED:
591 591 case SCF_ERROR_CONNECTION_BROKEN:
592 592 return (scferror2errno(scf_error()));
593 593
594 594 case SCF_ERROR_NOT_SET:
595 595 case SCF_ERROR_NOT_BOUND:
596 596 case SCF_ERROR_HANDLE_MISMATCH:
597 597 default:
598 598 bad_error("scf_iter_service_instances",
599 599 scf_error());
600 600 }
601 601 }
602 602
603 603 for (;;) {
604 604 r = scf_iter_next_instance(iter, inst);
605 605 if (r == 0) {
606 606 if (scf_service_get_pg(ent, name, pg) == 0)
607 607 return (0);
608 608
609 609 switch (scf_error()) {
610 610 case SCF_ERROR_DELETED:
611 611 case SCF_ERROR_NOT_FOUND:
612 612 case SCF_ERROR_INVALID_ARGUMENT:
613 613 case SCF_ERROR_CONNECTION_BROKEN:
614 614 return (scferror2errno(scf_error()));
615 615
616 616 case SCF_ERROR_NOT_BOUND:
617 617 case SCF_ERROR_HANDLE_MISMATCH:
618 618 case SCF_ERROR_NOT_SET:
619 619 default:
620 620 bad_error("scf_service_get_pg",
621 621 scf_error());
622 622 }
623 623 }
624 624 if (r != 1) {
625 625 switch (scf_error()) {
626 626 case SCF_ERROR_DELETED:
627 627 case SCF_ERROR_CONNECTION_BROKEN:
628 628 return (scferror2errno(scf_error()));
629 629
630 630 case SCF_ERROR_INVALID_ARGUMENT:
631 631 case SCF_ERROR_NOT_SET:
632 632 case SCF_ERROR_NOT_BOUND:
633 633 case SCF_ERROR_HANDLE_MISMATCH:
634 634 default:
635 635 bad_error("scf_iter_next_instance",
636 636 scf_error());
637 637 }
638 638 }
639 639
640 640 if (scf_instance_get_snapshot(inst, snap_running,
641 641 snap) == 0)
642 642 break;
643 643
644 644 switch (scf_error()) {
645 645 case SCF_ERROR_NOT_FOUND:
646 646 case SCF_ERROR_DELETED:
647 647 continue;
648 648
649 649 case SCF_ERROR_CONNECTION_BROKEN:
650 650 return (ECONNABORTED);
651 651
652 652 case SCF_ERROR_HANDLE_MISMATCH:
653 653 case SCF_ERROR_INVALID_ARGUMENT:
654 654 case SCF_ERROR_NOT_SET:
655 655 case SCF_ERROR_NOT_BOUND:
656 656 default:
657 657 bad_error("scf_instance_get_snapshot",
658 658 scf_error());
659 659 }
660 660 }
661 661 } else {
662 662 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
663 663 switch (scf_error()) {
664 664 case SCF_ERROR_NOT_FOUND:
665 665 break;
666 666
667 667 case SCF_ERROR_DELETED:
668 668 case SCF_ERROR_CONNECTION_BROKEN:
669 669 return (scferror2errno(scf_error()));
670 670
671 671 case SCF_ERROR_NOT_BOUND:
672 672 case SCF_ERROR_HANDLE_MISMATCH:
673 673 case SCF_ERROR_INVALID_ARGUMENT:
674 674 case SCF_ERROR_NOT_SET:
675 675 default:
676 676 bad_error("scf_instance_get_snapshot",
677 677 scf_error());
678 678 }
679 679
680 680 if (scf_instance_get_pg(ent, name, pg) == 0)
681 681 return (0);
682 682
683 683 switch (scf_error()) {
684 684 case SCF_ERROR_DELETED:
685 685 case SCF_ERROR_NOT_FOUND:
686 686 case SCF_ERROR_INVALID_ARGUMENT:
687 687 case SCF_ERROR_CONNECTION_BROKEN:
688 688 return (scferror2errno(scf_error()));
689 689
690 690 case SCF_ERROR_NOT_BOUND:
691 691 case SCF_ERROR_HANDLE_MISMATCH:
692 692 case SCF_ERROR_NOT_SET:
693 693 default:
694 694 bad_error("scf_instance_get_pg", scf_error());
695 695 }
696 696 }
697 697 }
698 698
699 699 r = get_snaplevel(snap, issvc, snpl);
700 700 switch (r) {
701 701 case 0:
702 702 break;
703 703
704 704 case ECONNABORTED:
705 705 case ECANCELED:
706 706 return (r);
707 707
708 708 case ENOENT:
709 709 return (EBADF);
710 710
711 711 default:
712 712 bad_error("get_snaplevel", r);
713 713 }
714 714
715 715 if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
716 716 return (0);
717 717
718 718 switch (scf_error()) {
719 719 case SCF_ERROR_DELETED:
720 720 case SCF_ERROR_INVALID_ARGUMENT:
721 721 case SCF_ERROR_CONNECTION_BROKEN:
722 722 case SCF_ERROR_NOT_FOUND:
723 723 return (scferror2errno(scf_error()));
724 724
725 725 case SCF_ERROR_NOT_BOUND:
726 726 case SCF_ERROR_HANDLE_MISMATCH:
727 727 case SCF_ERROR_NOT_SET:
728 728 default:
729 729 bad_error("scf_snaplevel_get_pg", scf_error());
730 730 /* NOTREACHED */
731 731 }
732 732 }
733 733
734 734 /*
735 735 * To be registered with atexit().
736 736 */
737 737 static void
738 738 remove_tempfile(void)
739 739 {
740 740 int ret;
741 741
742 742 if (tempfile != NULL) {
743 743 if (fclose(tempfile) == EOF)
744 744 (void) warn(gettext("Could not close temporary file"));
745 745 tempfile = NULL;
746 746 }
747 747
748 748 if (tempfilename[0] != '\0') {
749 749 do {
750 750 ret = remove(tempfilename);
751 751 } while (ret == -1 && errno == EINTR);
752 752 if (ret == -1)
753 753 warn(gettext("Could not remove temporary file"));
754 754 tempfilename[0] = '\0';
755 755 }
756 756 }
757 757
758 758 /*
759 759 * Launch private svc.configd(1M) for manipulating alternate repositories.
760 760 */
761 761 static void
762 762 start_private_repository(engine_state_t *est)
763 763 {
764 764 int fd, stat;
765 765 struct door_info info;
766 766 pid_t pid;
767 767
768 768 /*
769 769 * 1. Create a temporary file for the door.
770 770 */
771 771 if (est->sc_repo_doorname != NULL)
772 772 free((void *)est->sc_repo_doorname);
773 773
774 774 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
775 775 if (est->sc_repo_doorname == NULL)
776 776 uu_die(gettext("Could not acquire temporary filename"));
777 777
778 778 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
779 779 if (fd < 0)
780 780 uu_die(gettext("Could not create temporary file for "
781 781 "repository server"));
782 782
783 783 (void) close(fd);
784 784
785 785 /*
786 786 * 2. Launch a configd with that door, using the specified
787 787 * repository.
788 788 */
789 789 if ((est->sc_repo_pid = fork()) == 0) {
790 790 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
791 791 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
792 792 NULL);
793 793 uu_die(gettext("Could not execute %s"), est->sc_repo_server);
794 794 } else if (est->sc_repo_pid == -1)
795 795 uu_die(gettext("Attempt to fork failed"));
796 796
797 797 do {
798 798 pid = waitpid(est->sc_repo_pid, &stat, 0);
799 799 } while (pid == -1 && errno == EINTR);
800 800
801 801 if (pid == -1)
802 802 uu_die(gettext("Could not waitpid() for repository server"));
803 803
804 804 if (!WIFEXITED(stat)) {
805 805 uu_die(gettext("Repository server failed (status %d).\n"),
806 806 stat);
807 807 } else if (WEXITSTATUS(stat) != 0) {
808 808 uu_die(gettext("Repository server failed (exit %d).\n"),
809 809 WEXITSTATUS(stat));
810 810 }
811 811
812 812 /*
813 813 * See if it was successful by checking if the door is a door.
814 814 */
815 815
816 816 fd = open(est->sc_repo_doorname, O_RDWR);
817 817 if (fd < 0)
818 818 uu_die(gettext("Could not open door \"%s\""),
819 819 est->sc_repo_doorname);
820 820
821 821 if (door_info(fd, &info) < 0)
822 822 uu_die(gettext("Unexpected door_info() error"));
823 823
824 824 if (close(fd) == -1)
825 825 warn(gettext("Could not close repository door"),
826 826 strerror(errno));
827 827
828 828 est->sc_repo_pid = info.di_target;
829 829 }
830 830
831 831 void
832 832 lscf_cleanup(void)
833 833 {
834 834 /*
835 835 * In the case where we've launched a private svc.configd(1M)
836 836 * instance, we must terminate our child and remove the temporary
837 837 * rendezvous point.
838 838 */
839 839 if (est->sc_repo_pid > 0) {
840 840 (void) kill(est->sc_repo_pid, SIGTERM);
841 841 (void) waitpid(est->sc_repo_pid, NULL, 0);
842 842 (void) unlink(est->sc_repo_doorname);
843 843
844 844 est->sc_repo_pid = 0;
845 845 }
846 846 }
847 847
848 848 void
849 849 unselect_cursnap(void)
850 850 {
851 851 void *cookie;
852 852
853 853 cur_level = NULL;
854 854
855 855 cookie = NULL;
856 856 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
857 857 scf_snaplevel_destroy(cur_elt->sl);
858 858 free(cur_elt);
859 859 }
860 860
861 861 scf_snapshot_destroy(cur_snap);
862 862 cur_snap = NULL;
863 863 }
864 864
865 865 void
866 866 lscf_prep_hndl(void)
867 867 {
868 868 if (g_hndl != NULL)
869 869 return;
870 870
871 871 g_hndl = scf_handle_create(SCF_VERSION);
872 872 if (g_hndl == NULL)
873 873 scfdie();
874 874
875 875 if (est->sc_repo_filename != NULL)
876 876 start_private_repository(est);
877 877
878 878 if (est->sc_repo_doorname != NULL) {
879 879 scf_value_t *repo_value;
880 880 int ret;
881 881
882 882 repo_value = scf_value_create(g_hndl);
883 883 if (repo_value == NULL)
884 884 scfdie();
885 885
886 886 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
887 887 assert(ret == SCF_SUCCESS);
888 888
889 889 if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
890 890 SCF_SUCCESS)
891 891 scfdie();
892 892
893 893 scf_value_destroy(repo_value);
894 894 }
895 895
896 896 if (scf_handle_bind(g_hndl) != 0)
897 897 uu_die(gettext("Could not connect to repository server: %s.\n"),
898 898 scf_strerror(scf_error()));
899 899
900 900 cur_scope = scf_scope_create(g_hndl);
901 901 if (cur_scope == NULL)
902 902 scfdie();
903 903
904 904 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
905 905 scfdie();
906 906 }
907 907
908 908 static void
909 909 repository_teardown(void)
910 910 {
911 911 if (g_hndl != NULL) {
912 912 if (cur_snap != NULL)
913 913 unselect_cursnap();
914 914 scf_instance_destroy(cur_inst);
915 915 scf_service_destroy(cur_svc);
916 916 scf_scope_destroy(cur_scope);
917 917 scf_handle_destroy(g_hndl);
918 918 cur_inst = NULL;
919 919 cur_svc = NULL;
920 920 cur_scope = NULL;
921 921 g_hndl = NULL;
922 922 lscf_cleanup();
923 923 }
924 924 }
925 925
926 926 void
927 927 lscf_set_repository(const char *repfile, int force)
928 928 {
929 929 repository_teardown();
930 930
931 931 if (est->sc_repo_filename != NULL) {
932 932 free((void *)est->sc_repo_filename);
933 933 est->sc_repo_filename = NULL;
934 934 }
935 935
936 936 if ((force == 0) && (access(repfile, R_OK) != 0)) {
937 937 /*
938 938 * Repository file does not exist
939 939 * or has no read permission.
940 940 */
941 941 warn(gettext("Cannot access \"%s\": %s\n"),
942 942 repfile, strerror(errno));
943 943 } else {
944 944 est->sc_repo_filename = safe_strdup(repfile);
945 945 }
946 946
947 947 lscf_prep_hndl();
948 948 }
949 949
950 950 void
951 951 lscf_init()
952 952 {
953 953 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
954 954 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
955 955 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
956 956 0 ||
957 957 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
958 958 scfdie();
959 959
960 960 max_scf_len = max_scf_fmri_len;
961 961 if (max_scf_name_len > max_scf_len)
962 962 max_scf_len = max_scf_name_len;
963 963 if (max_scf_pg_type_len > max_scf_len)
964 964 max_scf_len = max_scf_pg_type_len;
965 965 /*
966 966 * When a value of type opaque is represented as a string, the
967 967 * string contains 2 characters for every byte of data. That is
968 968 * because the string contains the hex representation of the opaque
969 969 * value.
970 970 */
971 971 if (2 * max_scf_value_len > max_scf_len)
972 972 max_scf_len = 2 * max_scf_value_len;
973 973
974 974 if (atexit(remove_tempfile) != 0)
975 975 uu_die(gettext("Could not register atexit() function"));
976 976
977 977 emsg_entity_not_selected = gettext("An entity is not selected.\n");
978 978 emsg_permission_denied = gettext("Permission denied.\n");
979 979 emsg_create_xml = gettext("Could not create XML node.\n");
980 980 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
981 981 emsg_invalid_for_snapshot =
982 982 gettext("Invalid operation on a snapshot.\n");
983 983 emsg_read_only = gettext("Backend read-only.\n");
984 984 emsg_deleted = gettext("Current selection has been deleted.\n");
985 985 emsg_invalid_pg_name =
986 986 gettext("Invalid property group name \"%s\".\n");
987 987 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
988 988 emsg_no_such_pg = gettext("No such property group \"%s\".\n");
989 989 emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
990 990 "with invalid name \"%s\".\n");
991 991 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
992 992 "group with invalid name \"%s\" or type \"%s\".\n");
993 993 emsg_pg_added = gettext("%s changed unexpectedly "
994 994 "(property group \"%s\" added).\n");
995 995 emsg_pg_changed = gettext("%s changed unexpectedly "
996 996 "(property group \"%s\" changed).\n");
997 997 emsg_pg_deleted = gettext("%s changed unexpectedly "
998 998 "(property group \"%s\" or an ancestor was deleted).\n");
999 999 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
1000 1000 "in %s (permission denied).\n");
1001 1001 emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
1002 1002 "in %s (permission denied).\n");
1003 1003 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
1004 1004 "in %s (permission denied).\n");
1005 1005 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
1006 1006 "(permission denied).\n");
1007 1007 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1008 1008 "new dependent \"%s\" because it already exists). Warning: The "
1009 1009 "current dependent's target (%s) does not exist.\n");
1010 1010 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1011 1011 "dependent \"%s\" because it already exists). Warning: The "
1012 1012 "current dependent's target (%s) does not have a dependency named "
1013 1013 "\"%s\" as expected.\n");
1014 1014
1015 1015 string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1016 1016 offsetof(string_list_t, node), NULL, 0);
1017 1017 snaplevel_pool = uu_list_pool_create("snaplevels",
1018 1018 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1019 1019 NULL, 0);
1020 1020 }
1021 1021
1022 1022
1023 1023 static const char *
1024 1024 prop_to_typestr(const scf_property_t *prop)
1025 1025 {
1026 1026 scf_type_t ty;
1027 1027
1028 1028 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1029 1029 scfdie();
1030 1030
1031 1031 return (scf_type_to_string(ty));
1032 1032 }
1033 1033
1034 1034 static scf_type_t
1035 1035 string_to_type(const char *type)
1036 1036 {
1037 1037 size_t len = strlen(type);
1038 1038 char *buf;
1039 1039
1040 1040 if (len == 0 || type[len - 1] != ':')
1041 1041 return (SCF_TYPE_INVALID);
1042 1042
1043 1043 buf = (char *)alloca(len + 1);
1044 1044 (void) strlcpy(buf, type, len + 1);
1045 1045 buf[len - 1] = 0;
1046 1046
1047 1047 return (scf_string_to_type(buf));
1048 1048 }
1049 1049
1050 1050 static scf_value_t *
1051 1051 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1052 1052 {
1053 1053 scf_value_t *v;
1054 1054 char *dup, *nstr;
1055 1055 size_t len;
1056 1056
1057 1057 v = scf_value_create(g_hndl);
1058 1058 if (v == NULL)
1059 1059 scfdie();
1060 1060
1061 1061 len = strlen(str);
1062 1062 if (require_quotes &&
1063 1063 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1064 1064 semerr(gettext("Multiple string values or string values "
1065 1065 "with spaces must be quoted with '\"'.\n"));
1066 1066 scf_value_destroy(v);
1067 1067 return (NULL);
1068 1068 }
1069 1069
1070 1070 nstr = dup = safe_strdup(str);
1071 1071 if (dup[0] == '\"') {
1072 1072 /*
1073 1073 * Strip out the first and the last quote.
1074 1074 */
1075 1075 dup[len - 1] = '\0';
1076 1076 nstr = dup + 1;
1077 1077 }
1078 1078
1079 1079 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1080 1080 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1081 1081 semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1082 1082 scf_type_to_string(ty), nstr);
1083 1083 scf_value_destroy(v);
1084 1084 v = NULL;
1085 1085 }
1086 1086 free(dup);
1087 1087 return (v);
1088 1088 }
1089 1089
1090 1090 /*
1091 1091 * Print str to strm, quoting double-quotes and backslashes with backslashes.
1092 1092 * Optionally append a comment prefix ('#') to newlines ('\n').
1093 1093 */
1094 1094 static int
1095 1095 quote_and_print(const char *str, FILE *strm, int commentnl)
1096 1096 {
1097 1097 const char *cp;
1098 1098
1099 1099 for (cp = str; *cp != '\0'; ++cp) {
1100 1100 if (*cp == '"' || *cp == '\\')
1101 1101 (void) putc('\\', strm);
1102 1102
1103 1103 (void) putc(*cp, strm);
1104 1104
1105 1105 if (commentnl && *cp == '\n') {
1106 1106 (void) putc('#', strm);
1107 1107 }
1108 1108 }
1109 1109
1110 1110 return (ferror(strm));
1111 1111 }
1112 1112
1113 1113 /*
1114 1114 * These wrappers around lowlevel functions provide consistent error checking
1115 1115 * and warnings.
1116 1116 */
1117 1117 static int
1118 1118 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1119 1119 {
1120 1120 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1121 1121 return (0);
1122 1122
1123 1123 if (scf_error() != SCF_ERROR_NOT_FOUND)
1124 1124 scfdie();
1125 1125
1126 1126 if (g_verbose) {
1127 1127 ssize_t len;
1128 1128 char *fmri;
1129 1129
1130 1130 len = scf_pg_to_fmri(pg, NULL, 0);
1131 1131 if (len < 0)
1132 1132 scfdie();
1133 1133
1134 1134 fmri = safe_malloc(len + 1);
1135 1135
1136 1136 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1137 1137 scfdie();
1138 1138
1139 1139 warn(gettext("Expected property %s of property group %s is "
1140 1140 "missing.\n"), propname, fmri);
1141 1141
1142 1142 free(fmri);
1143 1143 }
1144 1144
1145 1145 return (-1);
1146 1146 }
1147 1147
1148 1148 static int
1149 1149 prop_check_type(scf_property_t *prop, scf_type_t ty)
1150 1150 {
1151 1151 scf_type_t pty;
1152 1152
1153 1153 if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1154 1154 scfdie();
1155 1155
1156 1156 if (ty == pty)
1157 1157 return (0);
1158 1158
1159 1159 if (g_verbose) {
1160 1160 ssize_t len;
1161 1161 char *fmri;
1162 1162 const char *tystr;
1163 1163
1164 1164 len = scf_property_to_fmri(prop, NULL, 0);
1165 1165 if (len < 0)
1166 1166 scfdie();
1167 1167
1168 1168 fmri = safe_malloc(len + 1);
1169 1169
1170 1170 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1171 1171 scfdie();
1172 1172
1173 1173 tystr = scf_type_to_string(ty);
1174 1174 if (tystr == NULL)
1175 1175 tystr = "?";
1176 1176
1177 1177 warn(gettext("Property %s is not of expected type %s.\n"),
1178 1178 fmri, tystr);
1179 1179
1180 1180 free(fmri);
1181 1181 }
1182 1182
1183 1183 return (-1);
1184 1184 }
1185 1185
1186 1186 static int
1187 1187 prop_get_val(scf_property_t *prop, scf_value_t *val)
1188 1188 {
1189 1189 scf_error_t err;
1190 1190
1191 1191 if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1192 1192 return (0);
1193 1193
1194 1194 err = scf_error();
1195 1195
1196 1196 if (err != SCF_ERROR_NOT_FOUND &&
1197 1197 err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1198 1198 err != SCF_ERROR_PERMISSION_DENIED)
1199 1199 scfdie();
1200 1200
1201 1201 if (g_verbose) {
1202 1202 ssize_t len;
1203 1203 char *fmri, *emsg;
1204 1204
1205 1205 len = scf_property_to_fmri(prop, NULL, 0);
1206 1206 if (len < 0)
1207 1207 scfdie();
1208 1208
1209 1209 fmri = safe_malloc(len + 1);
1210 1210
1211 1211 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1212 1212 scfdie();
1213 1213
1214 1214 if (err == SCF_ERROR_NOT_FOUND)
1215 1215 emsg = gettext("Property %s has no values; expected "
1216 1216 "one.\n");
1217 1217 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1218 1218 emsg = gettext("Property %s has multiple values; "
1219 1219 "expected one.\n");
1220 1220 else
1221 1221 emsg = gettext("No permission to read property %s.\n");
1222 1222
1223 1223 warn(emsg, fmri);
1224 1224
1225 1225 free(fmri);
1226 1226 }
1227 1227
1228 1228 return (-1);
1229 1229 }
1230 1230
1231 1231
1232 1232 static boolean_t
1233 1233 snaplevel_is_instance(const scf_snaplevel_t *level)
1234 1234 {
1235 1235 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1236 1236 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1237 1237 scfdie();
1238 1238 return (0);
1239 1239 } else {
1240 1240 return (1);
1241 1241 }
1242 1242 }
1243 1243
1244 1244 /*
1245 1245 * Decode FMRI into a service or instance, and put the result in *ep. If
1246 1246 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is
1247 1247 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify
1248 1248 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be
1249 1249 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point
1250 1250 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1251 1251 * whether *ep is a service.
1252 1252 */
1253 1253 static scf_error_t
1254 1254 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1255 1255 {
1256 1256 char *fmri_copy;
1257 1257 const char *sstr, *istr, *pgstr;
1258 1258 scf_service_t *svc;
1259 1259 scf_instance_t *inst;
1260 1260
1261 1261 fmri_copy = strdup(fmri);
1262 1262 if (fmri_copy == NULL)
1263 1263 return (SCF_ERROR_NO_MEMORY);
1264 1264
1265 1265 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1266 1266 SCF_SUCCESS) {
1267 1267 free(fmri_copy);
1268 1268 return (SCF_ERROR_INVALID_ARGUMENT);
1269 1269 }
1270 1270
1271 1271 free(fmri_copy);
1272 1272
1273 1273 if (sstr == NULL || pgstr != NULL)
1274 1274 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1275 1275
1276 1276 if (istr == NULL) {
1277 1277 svc = scf_service_create(h);
1278 1278 if (svc == NULL)
1279 1279 return (SCF_ERROR_NO_MEMORY);
1280 1280
1281 1281 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1282 1282 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1283 1283 if (scf_error() != SCF_ERROR_NOT_FOUND)
1284 1284 scfdie();
1285 1285
1286 1286 return (SCF_ERROR_NOT_FOUND);
1287 1287 }
1288 1288
1289 1289 *ep = svc;
1290 1290 *isservice = 1;
1291 1291 } else {
1292 1292 inst = scf_instance_create(h);
1293 1293 if (inst == NULL)
1294 1294 return (SCF_ERROR_NO_MEMORY);
1295 1295
1296 1296 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1297 1297 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1298 1298 if (scf_error() != SCF_ERROR_NOT_FOUND)
1299 1299 scfdie();
1300 1300
1301 1301 return (SCF_ERROR_NOT_FOUND);
1302 1302 }
1303 1303
1304 1304 *ep = inst;
1305 1305 *isservice = 0;
1306 1306 }
1307 1307
1308 1308 return (SCF_ERROR_NONE);
1309 1309 }
1310 1310
1311 1311 /*
1312 1312 * Create the entity named by fmri. Place a pointer to its libscf handle in
1313 1313 * *ep, and set or clear *isservicep if it is a service or an instance.
1314 1314 * Returns
1315 1315 * SCF_ERROR_NONE - success
1316 1316 * SCF_ERROR_NO_MEMORY - scf_*_create() failed
1317 1317 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1318 1318 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1319 1319 * SCF_ERROR_NOT_FOUND - no such scope
1320 1320 * SCF_ERROR_PERMISSION_DENIED
1321 1321 * SCF_ERROR_BACKEND_READONLY
1322 1322 * SCF_ERROR_BACKEND_ACCESS
1323 1323 */
1324 1324 static scf_error_t
1325 1325 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1326 1326 {
1327 1327 char *fmri_copy;
1328 1328 const char *scstr, *sstr, *istr, *pgstr;
1329 1329 scf_scope_t *scope = NULL;
1330 1330 scf_service_t *svc = NULL;
1331 1331 scf_instance_t *inst = NULL;
1332 1332 scf_error_t scfe;
1333 1333
1334 1334 fmri_copy = safe_strdup(fmri);
1335 1335
1336 1336 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1337 1337 0) {
1338 1338 free(fmri_copy);
1339 1339 return (SCF_ERROR_INVALID_ARGUMENT);
1340 1340 }
1341 1341
1342 1342 if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1343 1343 free(fmri_copy);
1344 1344 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1345 1345 }
1346 1346
1347 1347 *ep = NULL;
1348 1348
1349 1349 if ((scope = scf_scope_create(h)) == NULL ||
1350 1350 (svc = scf_service_create(h)) == NULL ||
1351 1351 (inst = scf_instance_create(h)) == NULL) {
1352 1352 scfe = SCF_ERROR_NO_MEMORY;
1353 1353 goto out;
1354 1354 }
1355 1355
1356 1356 get_scope:
1357 1357 if (scf_handle_get_scope(h, scstr, scope) != 0) {
1358 1358 switch (scf_error()) {
1359 1359 case SCF_ERROR_CONNECTION_BROKEN:
1360 1360 scfdie();
1361 1361 /* NOTREACHED */
1362 1362
1363 1363 case SCF_ERROR_NOT_FOUND:
1364 1364 scfe = SCF_ERROR_NOT_FOUND;
1365 1365 goto out;
1366 1366
1367 1367 case SCF_ERROR_HANDLE_MISMATCH:
1368 1368 case SCF_ERROR_NOT_BOUND:
1369 1369 case SCF_ERROR_INVALID_ARGUMENT:
1370 1370 default:
1371 1371 bad_error("scf_handle_get_scope", scf_error());
1372 1372 }
1373 1373 }
1374 1374
1375 1375 get_svc:
1376 1376 if (scf_scope_get_service(scope, sstr, svc) != 0) {
1377 1377 switch (scf_error()) {
1378 1378 case SCF_ERROR_CONNECTION_BROKEN:
1379 1379 scfdie();
1380 1380 /* NOTREACHED */
1381 1381
1382 1382 case SCF_ERROR_DELETED:
1383 1383 goto get_scope;
1384 1384
1385 1385 case SCF_ERROR_NOT_FOUND:
1386 1386 break;
1387 1387
1388 1388 case SCF_ERROR_HANDLE_MISMATCH:
1389 1389 case SCF_ERROR_INVALID_ARGUMENT:
1390 1390 case SCF_ERROR_NOT_BOUND:
1391 1391 case SCF_ERROR_NOT_SET:
1392 1392 default:
1393 1393 bad_error("scf_scope_get_service", scf_error());
1394 1394 }
1395 1395
1396 1396 if (scf_scope_add_service(scope, sstr, svc) != 0) {
1397 1397 switch (scf_error()) {
1398 1398 case SCF_ERROR_CONNECTION_BROKEN:
1399 1399 scfdie();
1400 1400 /* NOTREACHED */
1401 1401
1402 1402 case SCF_ERROR_DELETED:
1403 1403 goto get_scope;
1404 1404
1405 1405 case SCF_ERROR_PERMISSION_DENIED:
1406 1406 case SCF_ERROR_BACKEND_READONLY:
1407 1407 case SCF_ERROR_BACKEND_ACCESS:
1408 1408 scfe = scf_error();
1409 1409 goto out;
1410 1410
1411 1411 case SCF_ERROR_HANDLE_MISMATCH:
1412 1412 case SCF_ERROR_INVALID_ARGUMENT:
1413 1413 case SCF_ERROR_NOT_BOUND:
1414 1414 case SCF_ERROR_NOT_SET:
1415 1415 default:
1416 1416 bad_error("scf_scope_get_service", scf_error());
1417 1417 }
1418 1418 }
1419 1419 }
1420 1420
1421 1421 if (istr == NULL) {
1422 1422 scfe = SCF_ERROR_NONE;
1423 1423 *ep = svc;
1424 1424 *isservicep = 1;
1425 1425 goto out;
1426 1426 }
1427 1427
1428 1428 get_inst:
1429 1429 if (scf_service_get_instance(svc, istr, inst) != 0) {
1430 1430 switch (scf_error()) {
1431 1431 case SCF_ERROR_CONNECTION_BROKEN:
1432 1432 scfdie();
1433 1433 /* NOTREACHED */
1434 1434
1435 1435 case SCF_ERROR_DELETED:
1436 1436 goto get_svc;
1437 1437
1438 1438 case SCF_ERROR_NOT_FOUND:
1439 1439 break;
1440 1440
1441 1441 case SCF_ERROR_HANDLE_MISMATCH:
1442 1442 case SCF_ERROR_INVALID_ARGUMENT:
1443 1443 case SCF_ERROR_NOT_BOUND:
1444 1444 case SCF_ERROR_NOT_SET:
1445 1445 default:
1446 1446 bad_error("scf_service_get_instance", scf_error());
1447 1447 }
1448 1448
1449 1449 if (scf_service_add_instance(svc, istr, inst) != 0) {
1450 1450 switch (scf_error()) {
1451 1451 case SCF_ERROR_CONNECTION_BROKEN:
1452 1452 scfdie();
1453 1453 /* NOTREACHED */
1454 1454
1455 1455 case SCF_ERROR_DELETED:
1456 1456 goto get_svc;
1457 1457
1458 1458 case SCF_ERROR_PERMISSION_DENIED:
1459 1459 case SCF_ERROR_BACKEND_READONLY:
1460 1460 case SCF_ERROR_BACKEND_ACCESS:
1461 1461 scfe = scf_error();
1462 1462 goto out;
1463 1463
1464 1464 case SCF_ERROR_HANDLE_MISMATCH:
1465 1465 case SCF_ERROR_INVALID_ARGUMENT:
1466 1466 case SCF_ERROR_NOT_BOUND:
1467 1467 case SCF_ERROR_NOT_SET:
1468 1468 default:
1469 1469 bad_error("scf_service_add_instance",
1470 1470 scf_error());
1471 1471 }
1472 1472 }
1473 1473 }
1474 1474
1475 1475 scfe = SCF_ERROR_NONE;
1476 1476 *ep = inst;
1477 1477 *isservicep = 0;
1478 1478
1479 1479 out:
1480 1480 if (*ep != inst)
1481 1481 scf_instance_destroy(inst);
1482 1482 if (*ep != svc)
1483 1483 scf_service_destroy(svc);
1484 1484 scf_scope_destroy(scope);
1485 1485 free(fmri_copy);
1486 1486 return (scfe);
1487 1487 }
1488 1488
1489 1489 /*
1490 1490 * Create or update a snapshot of inst. snap is a required scratch object.
1491 1491 *
1492 1492 * Returns
1493 1493 * 0 - success
1494 1494 * ECONNABORTED - repository connection broken
1495 1495 * EPERM - permission denied
1496 1496 * ENOSPC - configd is out of resources
1497 1497 * ECANCELED - inst was deleted
1498 1498 * -1 - unknown libscf error (message printed)
1499 1499 */
1500 1500 static int
1501 1501 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1502 1502 {
1503 1503 again:
1504 1504 if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1505 1505 if (_scf_snapshot_take_attach(inst, snap) != 0) {
1506 1506 switch (scf_error()) {
1507 1507 case SCF_ERROR_CONNECTION_BROKEN:
1508 1508 case SCF_ERROR_PERMISSION_DENIED:
1509 1509 case SCF_ERROR_NO_RESOURCES:
1510 1510 return (scferror2errno(scf_error()));
1511 1511
1512 1512 case SCF_ERROR_NOT_SET:
1513 1513 case SCF_ERROR_INVALID_ARGUMENT:
1514 1514 default:
1515 1515 bad_error("_scf_snapshot_take_attach",
1516 1516 scf_error());
1517 1517 }
1518 1518 }
1519 1519 } else {
1520 1520 switch (scf_error()) {
1521 1521 case SCF_ERROR_NOT_FOUND:
1522 1522 break;
1523 1523
1524 1524 case SCF_ERROR_DELETED:
1525 1525 case SCF_ERROR_CONNECTION_BROKEN:
1526 1526 return (scferror2errno(scf_error()));
1527 1527
1528 1528 case SCF_ERROR_HANDLE_MISMATCH:
1529 1529 case SCF_ERROR_NOT_BOUND:
1530 1530 case SCF_ERROR_INVALID_ARGUMENT:
1531 1531 case SCF_ERROR_NOT_SET:
1532 1532 default:
1533 1533 bad_error("scf_instance_get_snapshot", scf_error());
1534 1534 }
1535 1535
1536 1536 if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1537 1537 switch (scf_error()) {
1538 1538 case SCF_ERROR_EXISTS:
1539 1539 goto again;
1540 1540
1541 1541 case SCF_ERROR_CONNECTION_BROKEN:
1542 1542 case SCF_ERROR_NO_RESOURCES:
1543 1543 case SCF_ERROR_PERMISSION_DENIED:
1544 1544 return (scferror2errno(scf_error()));
1545 1545
1546 1546 default:
1547 1547 scfwarn();
1548 1548 return (-1);
1549 1549
1550 1550 case SCF_ERROR_NOT_SET:
1551 1551 case SCF_ERROR_INTERNAL:
1552 1552 case SCF_ERROR_INVALID_ARGUMENT:
1553 1553 case SCF_ERROR_HANDLE_MISMATCH:
1554 1554 bad_error("_scf_snapshot_take_new",
1555 1555 scf_error());
1556 1556 }
1557 1557 }
1558 1558 }
1559 1559
1560 1560 return (0);
1561 1561 }
1562 1562
1563 1563 static int
1564 1564 refresh_running_snapshot(void *entity)
1565 1565 {
1566 1566 scf_snapshot_t *snap;
1567 1567 int r;
1568 1568
1569 1569 if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1570 1570 scfdie();
1571 1571 r = take_snap(entity, snap_running, snap);
1572 1572 scf_snapshot_destroy(snap);
1573 1573
1574 1574 return (r);
1575 1575 }
1576 1576
1577 1577 /*
1578 1578 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *.
1579 1579 * Otherwise take entity to be an scf_service_t * and refresh all of its child
1580 1580 * instances. fmri is used for messages. inst, iter, and name_buf are used
1581 1581 * for scratch space. Returns
1582 1582 * 0 - success
1583 1583 * ECONNABORTED - repository connection broken
1584 1584 * ECANCELED - entity was deleted
1585 1585 * EACCES - backend denied access
1586 1586 * EPERM - permission denied
1587 1587 * ENOSPC - repository server out of resources
1588 1588 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set.
1589 1589 */
1590 1590 static int
1591 1591 refresh_entity(int isservice, void *entity, const char *fmri,
1592 1592 scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1593 1593 {
1594 1594 scf_error_t scfe;
1595 1595 int r;
1596 1596
1597 1597 if (!isservice) {
1598 1598 /*
1599 1599 * Let restarter handles refreshing and making new running
1600 1600 * snapshot only if operating on a live repository and not
1601 1601 * running in early import.
1602 1602 */
1603 1603 if (est->sc_repo_filename == NULL &&
1604 1604 est->sc_repo_doorname == NULL &&
1605 1605 est->sc_in_emi == 0) {
1606 1606 if (_smf_refresh_instance_i(entity) == 0) {
1607 1607 if (g_verbose)
1608 1608 warn(gettext("Refreshed %s.\n"), fmri);
1609 1609 return (0);
1610 1610 }
1611 1611
1612 1612 switch (scf_error()) {
1613 1613 case SCF_ERROR_BACKEND_ACCESS:
1614 1614 return (EACCES);
1615 1615
1616 1616 case SCF_ERROR_PERMISSION_DENIED:
1617 1617 return (EPERM);
1618 1618
1619 1619 default:
1620 1620 return (-1);
1621 1621 }
1622 1622 } else {
1623 1623 r = refresh_running_snapshot(entity);
1624 1624 switch (r) {
1625 1625 case 0:
1626 1626 break;
1627 1627
1628 1628 case ECONNABORTED:
1629 1629 case ECANCELED:
1630 1630 case EPERM:
1631 1631 case ENOSPC:
1632 1632 break;
1633 1633
1634 1634 default:
1635 1635 bad_error("refresh_running_snapshot",
1636 1636 scf_error());
1637 1637 }
1638 1638
1639 1639 return (r);
1640 1640 }
1641 1641 }
1642 1642
1643 1643 if (scf_iter_service_instances(iter, entity) != 0) {
1644 1644 switch (scf_error()) {
1645 1645 case SCF_ERROR_CONNECTION_BROKEN:
1646 1646 return (ECONNABORTED);
1647 1647
1648 1648 case SCF_ERROR_DELETED:
1649 1649 return (ECANCELED);
1650 1650
1651 1651 case SCF_ERROR_HANDLE_MISMATCH:
1652 1652 case SCF_ERROR_NOT_BOUND:
1653 1653 case SCF_ERROR_NOT_SET:
1654 1654 default:
1655 1655 bad_error("scf_iter_service_instances", scf_error());
1656 1656 }
1657 1657 }
1658 1658
1659 1659 for (;;) {
1660 1660 r = scf_iter_next_instance(iter, inst);
1661 1661 if (r == 0)
1662 1662 break;
1663 1663 if (r != 1) {
1664 1664 switch (scf_error()) {
1665 1665 case SCF_ERROR_CONNECTION_BROKEN:
1666 1666 return (ECONNABORTED);
1667 1667
1668 1668 case SCF_ERROR_DELETED:
1669 1669 return (ECANCELED);
1670 1670
1671 1671 case SCF_ERROR_HANDLE_MISMATCH:
1672 1672 case SCF_ERROR_NOT_BOUND:
1673 1673 case SCF_ERROR_NOT_SET:
1674 1674 case SCF_ERROR_INVALID_ARGUMENT:
1675 1675 default:
1676 1676 bad_error("scf_iter_next_instance",
1677 1677 scf_error());
1678 1678 }
1679 1679 }
1680 1680
1681 1681 /*
1682 1682 * Similarly, just take a new running snapshot if operating on
1683 1683 * a non-live repository or running during early import.
1684 1684 */
1685 1685 if (est->sc_repo_filename != NULL ||
1686 1686 est->sc_repo_doorname != NULL ||
1687 1687 est->sc_in_emi == 1) {
1688 1688 r = refresh_running_snapshot(inst);
1689 1689 switch (r) {
1690 1690 case 0:
1691 1691 continue;
1692 1692
1693 1693 case ECONNABORTED:
1694 1694 case ECANCELED:
1695 1695 case EPERM:
1696 1696 case ENOSPC:
1697 1697 break;
1698 1698 default:
1699 1699 bad_error("refresh_running_snapshot",
1700 1700 scf_error());
1701 1701 }
1702 1702
1703 1703 return (r);
1704 1704
1705 1705 }
1706 1706
1707 1707 if (_smf_refresh_instance_i(inst) == 0) {
1708 1708 if (g_verbose) {
1709 1709 if (scf_instance_get_name(inst, name_buf,
1710 1710 max_scf_name_len + 1) < 0)
1711 1711 (void) strcpy(name_buf, "?");
1712 1712
1713 1713 warn(gettext("Refreshed %s:%s.\n"),
1714 1714 fmri, name_buf);
1715 1715 }
1716 1716 } else {
1717 1717 if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1718 1718 g_verbose) {
1719 1719 scfe = scf_error();
1720 1720
1721 1721 if (scf_instance_to_fmri(inst, name_buf,
1722 1722 max_scf_name_len + 1) < 0)
1723 1723 (void) strcpy(name_buf, "?");
1724 1724
1725 1725 warn(gettext(
1726 1726 "Refresh of %s:%s failed: %s.\n"), fmri,
1727 1727 name_buf, scf_strerror(scfe));
1728 1728 }
1729 1729 }
1730 1730 }
1731 1731
1732 1732 return (0);
1733 1733 }
1734 1734
1735 1735 static void
1736 1736 private_refresh(void)
1737 1737 {
1738 1738 scf_instance_t *pinst = NULL;
1739 1739 scf_iter_t *piter = NULL;
1740 1740 ssize_t fmrilen;
1741 1741 size_t bufsz;
1742 1742 char *fmribuf;
1743 1743 void *ent;
1744 1744 int issvc;
1745 1745 int r;
1746 1746
1747 1747 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1748 1748 return;
1749 1749
1750 1750 assert(cur_svc != NULL);
1751 1751
1752 1752 bufsz = max_scf_fmri_len + 1;
1753 1753 fmribuf = safe_malloc(bufsz);
1754 1754 if (cur_inst) {
1755 1755 issvc = 0;
1756 1756 ent = cur_inst;
1757 1757 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1758 1758 } else {
1759 1759 issvc = 1;
1760 1760 ent = cur_svc;
1761 1761 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1762 1762 if ((pinst = scf_instance_create(g_hndl)) == NULL)
1763 1763 scfdie();
1764 1764
1765 1765 if ((piter = scf_iter_create(g_hndl)) == NULL)
1766 1766 scfdie();
1767 1767 }
1768 1768 if (fmrilen < 0) {
1769 1769 free(fmribuf);
1770 1770 if (scf_error() != SCF_ERROR_DELETED)
1771 1771 scfdie();
1772 1772
1773 1773 warn(emsg_deleted);
1774 1774 return;
1775 1775 }
1776 1776 assert(fmrilen < bufsz);
1777 1777
1778 1778 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1779 1779 switch (r) {
1780 1780 case 0:
1781 1781 break;
1782 1782
1783 1783 case ECONNABORTED:
1784 1784 warn(gettext("Could not refresh %s "
1785 1785 "(repository connection broken).\n"), fmribuf);
1786 1786 break;
1787 1787
1788 1788 case ECANCELED:
1789 1789 warn(emsg_deleted);
1790 1790 break;
1791 1791
1792 1792 case EPERM:
1793 1793 warn(gettext("Could not refresh %s "
1794 1794 "(permission denied).\n"), fmribuf);
1795 1795 break;
1796 1796
1797 1797 case ENOSPC:
1798 1798 warn(gettext("Could not refresh %s "
1799 1799 "(repository server out of resources).\n"),
1800 1800 fmribuf);
1801 1801 break;
1802 1802
1803 1803 case EACCES:
1804 1804 default:
1805 1805 bad_error("refresh_entity", scf_error());
1806 1806 }
1807 1807
1808 1808 if (issvc) {
1809 1809 scf_instance_destroy(pinst);
1810 1810 scf_iter_destroy(piter);
1811 1811 }
1812 1812
1813 1813 free(fmribuf);
1814 1814 }
1815 1815
1816 1816
1817 1817 static int
1818 1818 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1819 1819 {
1820 1820 cbp->sc_err = scferror2errno(err);
1821 1821 return (UU_WALK_ERROR);
1822 1822 }
1823 1823
1824 1824 static int
1825 1825 stash_scferror(scf_callback_t *cbp)
1826 1826 {
1827 1827 return (stash_scferror_err(cbp, scf_error()));
1828 1828 }
1829 1829
1830 1830 static int select_inst(const char *);
1831 1831 static int select_svc(const char *);
1832 1832
1833 1833 /*
1834 1834 * Take a property that does not have a type and check to see if a type
1835 1835 * exists or can be gleened from the current data. Set the type.
1836 1836 *
1837 1837 * Check the current level (instance) and then check the higher level
1838 1838 * (service). This could be the case for adding a new property to
1839 1839 * the instance that's going to "override" a service level property.
1840 1840 *
1841 1841 * For a property :
1842 1842 * 1. Take the type from an existing property
1843 1843 * 2. Take the type from a template entry
1844 1844 *
1845 1845 * If the type can not be found, then leave the type as is, and let the import
1846 1846 * report the problem of the missing type.
1847 1847 */
1848 1848 static int
1849 1849 find_current_prop_type(void *p, void *g)
1850 1850 {
1851 1851 property_t *prop = p;
1852 1852 scf_callback_t *lcb = g;
1853 1853 pgroup_t *pg = NULL;
1854 1854
1855 1855 const char *fmri = NULL;
1856 1856 char *lfmri = NULL;
1857 1857 char *cur_selection = NULL;
1858 1858
1859 1859 scf_propertygroup_t *sc_pg = NULL;
1860 1860 scf_property_t *sc_prop = NULL;
1861 1861 scf_pg_tmpl_t *t_pg = NULL;
1862 1862 scf_prop_tmpl_t *t_prop = NULL;
1863 1863 scf_type_t prop_type;
1864 1864
1865 1865 value_t *vp;
1866 1866 int issvc = lcb->sc_service;
1867 1867 int r = UU_WALK_ERROR;
1868 1868
1869 1869 if (prop->sc_value_type != SCF_TYPE_INVALID)
1870 1870 return (UU_WALK_NEXT);
1871 1871
1872 1872 t_prop = scf_tmpl_prop_create(g_hndl);
1873 1873 sc_prop = scf_property_create(g_hndl);
1874 1874 if (sc_prop == NULL || t_prop == NULL) {
1875 1875 warn(gettext("Unable to create the property to attempt and "
1876 1876 "find a missing type.\n"));
1877 1877
1878 1878 scf_property_destroy(sc_prop);
1879 1879 scf_tmpl_prop_destroy(t_prop);
1880 1880
1881 1881 return (UU_WALK_ERROR);
1882 1882 }
1883 1883
1884 1884 if (lcb->sc_flags == 1) {
1885 1885 pg = lcb->sc_parent;
1886 1886 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1887 1887 fmri = pg->sc_parent->sc_fmri;
1888 1888 retry_pg:
1889 1889 if (cur_svc && cur_selection == NULL) {
1890 1890 cur_selection = safe_malloc(max_scf_fmri_len + 1);
1891 1891 lscf_get_selection_str(cur_selection,
1892 1892 max_scf_fmri_len + 1);
1893 1893
1894 1894 if (strcmp(cur_selection, fmri) != 0) {
1895 1895 lscf_select(fmri);
1896 1896 } else {
1897 1897 free(cur_selection);
1898 1898 cur_selection = NULL;
1899 1899 }
1900 1900 } else {
1901 1901 lscf_select(fmri);
1902 1902 }
1903 1903
1904 1904 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1905 1905 warn(gettext("Unable to create property group to "
1906 1906 "find a missing property type.\n"));
1907 1907
1908 1908 goto out;
1909 1909 }
1910 1910
1911 1911 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1912 1912 /*
1913 1913 * If this is the sc_pg from the parent
1914 1914 * let the caller clean up the sc_pg,
1915 1915 * and just throw it away in this case.
1916 1916 */
1917 1917 if (sc_pg != lcb->sc_parent)
1918 1918 scf_pg_destroy(sc_pg);
1919 1919
1920 1920 sc_pg = NULL;
1921 1921 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1922 1922 warn(gettext("Unable to create template "
1923 1923 "property group to find a property "
1924 1924 "type.\n"));
1925 1925
1926 1926 goto out;
1927 1927 }
1928 1928
1929 1929 if (scf_tmpl_get_by_pg_name(fmri, NULL,
1930 1930 pg->sc_pgroup_name, NULL, t_pg,
1931 1931 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1932 1932 /*
1933 1933 * if instance get service and jump back
1934 1934 */
1935 1935 scf_tmpl_pg_destroy(t_pg);
1936 1936 t_pg = NULL;
1937 1937 if (issvc == 0) {
1938 1938 entity_t *e = pg->sc_parent->sc_parent;
1939 1939
1940 1940 fmri = e->sc_fmri;
1941 1941 issvc = 1;
1942 1942 goto retry_pg;
1943 1943 } else {
1944 1944 goto out;
1945 1945 }
1946 1946 }
1947 1947 }
1948 1948 } else {
1949 1949 sc_pg = lcb->sc_parent;
1950 1950 }
1951 1951
1952 1952 /*
1953 1953 * Attempt to get the type from an existing property. If the property
1954 1954 * cannot be found then attempt to get the type from a template entry
1955 1955 * for the property.
1956 1956 *
1957 1957 * Finally, if at the instance level look at the service level.
1958 1958 */
1959 1959 if (sc_pg != NULL &&
1960 1960 pg_get_prop(sc_pg, prop->sc_property_name,
1961 1961 sc_prop) == SCF_SUCCESS &&
1962 1962 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1963 1963 prop->sc_value_type = prop_type;
1964 1964
1965 1965 /*
1966 1966 * Found a type, update the value types and validate
1967 1967 * the actual value against this type.
1968 1968 */
1969 1969 for (vp = uu_list_first(prop->sc_property_values);
1970 1970 vp != NULL;
1971 1971 vp = uu_list_next(prop->sc_property_values, vp)) {
1972 1972 vp->sc_type = prop->sc_value_type;
1973 1973 lxml_store_value(vp, 0, NULL);
1974 1974 }
1975 1975
1976 1976 r = UU_WALK_NEXT;
1977 1977 goto out;
1978 1978 }
1979 1979
1980 1980 /*
1981 1981 * If we get here with t_pg set to NULL then we had to have
1982 1982 * gotten an sc_pg but that sc_pg did not have the property
1983 1983 * we are looking for. So if the t_pg is not null look up
1984 1984 * the template entry for the property.
1985 1985 *
1986 1986 * If the t_pg is null then need to attempt to get a matching
1987 1987 * template entry for the sc_pg, and see if there is a property
1988 1988 * entry for that template entry.
1989 1989 */
1990 1990 do_tmpl :
1991 1991 if (t_pg != NULL &&
1992 1992 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1993 1993 t_prop, 0) == SCF_SUCCESS) {
1994 1994 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1995 1995 prop->sc_value_type = prop_type;
1996 1996
1997 1997 /*
1998 1998 * Found a type, update the value types and validate
1999 1999 * the actual value against this type.
2000 2000 */
2001 2001 for (vp = uu_list_first(prop->sc_property_values);
2002 2002 vp != NULL;
2003 2003 vp = uu_list_next(prop->sc_property_values, vp)) {
2004 2004 vp->sc_type = prop->sc_value_type;
2005 2005 lxml_store_value(vp, 0, NULL);
2006 2006 }
2007 2007
2008 2008 r = UU_WALK_NEXT;
2009 2009 goto out;
2010 2010 }
2011 2011 } else {
2012 2012 if (t_pg == NULL && sc_pg) {
2013 2013 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2014 2014 warn(gettext("Unable to create template "
2015 2015 "property group to find a property "
2016 2016 "type.\n"));
2017 2017
2018 2018 goto out;
2019 2019 }
2020 2020
2021 2021 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2022 2022 scf_tmpl_pg_destroy(t_pg);
2023 2023 t_pg = NULL;
2024 2024 } else {
2025 2025 goto do_tmpl;
2026 2026 }
2027 2027 }
2028 2028 }
2029 2029
2030 2030 if (issvc == 0) {
2031 2031 scf_instance_t *i;
2032 2032 scf_service_t *s;
2033 2033
2034 2034 issvc = 1;
2035 2035 if (lcb->sc_flags == 1) {
2036 2036 entity_t *e = pg->sc_parent->sc_parent;
2037 2037
2038 2038 fmri = e->sc_fmri;
2039 2039 goto retry_pg;
2040 2040 }
2041 2041
2042 2042 /*
2043 2043 * because lcb->sc_flags was not set then this means
2044 2044 * the pg was not used and can be used here.
2045 2045 */
2046 2046 if ((pg = internal_pgroup_new()) == NULL) {
2047 2047 warn(gettext("Could not create internal property group "
2048 2048 "to find a missing type."));
2049 2049
2050 2050 goto out;
2051 2051 }
2052 2052
2053 2053 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2054 2054 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2055 2055 max_scf_name_len + 1) < 0)
2056 2056 goto out;
2057 2057
2058 2058 i = scf_instance_create(g_hndl);
2059 2059 s = scf_service_create(g_hndl);
2060 2060 if (i == NULL || s == NULL ||
2061 2061 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2062 2062 warn(gettext("Could not get a service for the instance "
2063 2063 "to find a missing type."));
2064 2064
2065 2065 goto out;
2066 2066 }
2067 2067
2068 2068 /*
2069 2069 * Check to see truly at the instance level.
2070 2070 */
2071 2071 lfmri = safe_malloc(max_scf_fmri_len + 1);
2072 2072 if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2073 2073 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2074 2074 goto out;
2075 2075 else
2076 2076 fmri = (const char *)lfmri;
2077 2077
2078 2078 goto retry_pg;
2079 2079 }
2080 2080
2081 2081 out :
2082 2082 if (sc_pg != lcb->sc_parent) {
2083 2083 scf_pg_destroy(sc_pg);
2084 2084 }
2085 2085
2086 2086 /*
2087 2087 * If this is true then the pg was allocated
2088 2088 * here, and the name was set so need to free
2089 2089 * the name and the pg.
2090 2090 */
2091 2091 if (pg != NULL && pg != lcb->sc_parent) {
2092 2092 free((char *)pg->sc_pgroup_name);
2093 2093 internal_pgroup_free(pg);
2094 2094 }
2095 2095
2096 2096 if (cur_selection) {
2097 2097 lscf_select(cur_selection);
2098 2098 free(cur_selection);
2099 2099 }
2100 2100
2101 2101 scf_tmpl_pg_destroy(t_pg);
2102 2102 scf_tmpl_prop_destroy(t_prop);
2103 2103 scf_property_destroy(sc_prop);
2104 2104
2105 2105 if (r != UU_WALK_NEXT)
2106 2106 warn(gettext("Could not find property type for \"%s\" "
2107 2107 "from \"%s\"\n"), prop->sc_property_name,
2108 2108 fmri != NULL ? fmri : lcb->sc_source_fmri);
2109 2109
2110 2110 free(lfmri);
2111 2111
2112 2112 return (r);
2113 2113 }
2114 2114
2115 2115 /*
2116 2116 * Take a property group that does not have a type and check to see if a type
2117 2117 * exists or can be gleened from the current data. Set the type.
2118 2118 *
2119 2119 * Check the current level (instance) and then check the higher level
2120 2120 * (service). This could be the case for adding a new property to
2121 2121 * the instance that's going to "override" a service level property.
2122 2122 *
2123 2123 * For a property group
2124 2124 * 1. Take the type from an existing property group
2125 2125 * 2. Take the type from a template entry
2126 2126 *
2127 2127 * If the type can not be found, then leave the type as is, and let the import
2128 2128 * report the problem of the missing type.
2129 2129 */
2130 2130 static int
2131 2131 find_current_pg_type(void *p, void *sori)
2132 2132 {
2133 2133 entity_t *si = sori;
2134 2134 pgroup_t *pg = p;
2135 2135
2136 2136 const char *ofmri, *fmri;
2137 2137 char *cur_selection = NULL;
2138 2138 char *pg_type = NULL;
2139 2139
2140 2140 scf_propertygroup_t *sc_pg = NULL;
2141 2141 scf_pg_tmpl_t *t_pg = NULL;
2142 2142
2143 2143 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2144 2144 int r = UU_WALK_ERROR;
2145 2145
2146 2146 ofmri = fmri = si->sc_fmri;
2147 2147 if (pg->sc_pgroup_type != NULL) {
2148 2148 r = UU_WALK_NEXT;
2149 2149
2150 2150 goto out;
2151 2151 }
2152 2152
2153 2153 sc_pg = scf_pg_create(g_hndl);
2154 2154 if (sc_pg == NULL) {
2155 2155 warn(gettext("Unable to create property group to attempt "
2156 2156 "and find a missing type.\n"));
2157 2157
2158 2158 return (UU_WALK_ERROR);
2159 2159 }
2160 2160
2161 2161 /*
2162 2162 * Using get_pg() requires that the cur_svc/cur_inst be
2163 2163 * via lscf_select. Need to preserve the current selection
2164 2164 * if going to use lscf_select() to set up the cur_svc/cur_inst
2165 2165 */
2166 2166 if (cur_svc) {
2167 2167 cur_selection = safe_malloc(max_scf_fmri_len + 1);
2168 2168 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2169 2169 }
2170 2170
2171 2171 /*
2172 2172 * If the property group exists get the type, and set
2173 2173 * the pgroup_t type of that type.
2174 2174 *
2175 2175 * If not the check for a template pg_pattern entry
2176 2176 * and take the type from that.
2177 2177 */
2178 2178 retry_svc:
2179 2179 lscf_select(fmri);
2180 2180
2181 2181 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2182 2182 pg_type = safe_malloc(max_scf_pg_type_len + 1);
2183 2183 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2184 2184 max_scf_pg_type_len + 1) != -1) {
2185 2185 pg->sc_pgroup_type = pg_type;
2186 2186
2187 2187 r = UU_WALK_NEXT;
2188 2188 goto out;
2189 2189 } else {
2190 2190 free(pg_type);
2191 2191 }
2192 2192 } else {
2193 2193 if ((t_pg == NULL) &&
2194 2194 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2195 2195 goto out;
2196 2196
2197 2197 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2198 2198 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2199 2199 scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2200 2200 pg->sc_pgroup_type = pg_type;
2201 2201
2202 2202 r = UU_WALK_NEXT;
2203 2203 goto out;
2204 2204 }
2205 2205 }
2206 2206
2207 2207 /*
2208 2208 * If type is not found at the instance level then attempt to
2209 2209 * find the type at the service level.
2210 2210 */
2211 2211 if (!issvc) {
2212 2212 si = si->sc_parent;
2213 2213 fmri = si->sc_fmri;
2214 2214 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2215 2215 goto retry_svc;
2216 2216 }
2217 2217
2218 2218 out :
2219 2219 if (cur_selection) {
2220 2220 lscf_select(cur_selection);
2221 2221 free(cur_selection);
2222 2222 }
2223 2223
2224 2224 /*
2225 2225 * Now walk the properties of the property group to make sure that
2226 2226 * all properties have the correct type and values are valid for
2227 2227 * those types.
2228 2228 */
2229 2229 if (r == UU_WALK_NEXT) {
2230 2230 scf_callback_t cb;
2231 2231
2232 2232 cb.sc_service = issvc;
2233 2233 cb.sc_source_fmri = ofmri;
2234 2234 if (sc_pg != NULL) {
2235 2235 cb.sc_parent = sc_pg;
2236 2236 cb.sc_flags = 0;
2237 2237 } else {
2238 2238 cb.sc_parent = pg;
2239 2239 cb.sc_flags = 1;
2240 2240 }
2241 2241
2242 2242 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2243 2243 &cb, UU_DEFAULT) != 0) {
2244 2244 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2245 2245 bad_error("uu_list_walk", uu_error());
2246 2246
2247 2247 r = UU_WALK_ERROR;
2248 2248 }
2249 2249 } else {
2250 2250 warn(gettext("Could not find property group type for "
2251 2251 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2252 2252 }
2253 2253
2254 2254 scf_tmpl_pg_destroy(t_pg);
2255 2255 scf_pg_destroy(sc_pg);
2256 2256
2257 2257 return (r);
2258 2258 }
2259 2259
2260 2260 /*
2261 2261 * Import. These functions import a bundle into the repository.
2262 2262 */
2263 2263
2264 2264 /*
2265 2265 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses
2266 2266 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success,
2267 2267 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2268 2268 * lcbdata->sc_err to
2269 2269 * ENOMEM - out of memory
2270 2270 * ECONNABORTED - repository connection broken
2271 2271 * ECANCELED - sc_trans's property group was deleted
2272 2272 * EINVAL - p's name is invalid (error printed)
2273 2273 * - p has an invalid value (error printed)
2274 2274 */
2275 2275 static int
2276 2276 lscf_property_import(void *v, void *pvt)
2277 2277 {
2278 2278 property_t *p = v;
2279 2279 scf_callback_t *lcbdata = pvt;
2280 2280 value_t *vp;
2281 2281 scf_transaction_t *trans = lcbdata->sc_trans;
2282 2282 scf_transaction_entry_t *entr;
2283 2283 scf_value_t *val;
2284 2284 scf_type_t tp;
2285 2285
2286 2286 if ((lcbdata->sc_flags & SCI_NOENABLED ||
2287 2287 lcbdata->sc_flags & SCI_DELAYENABLE) &&
2288 2288 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2289 2289 lcbdata->sc_enable = p;
2290 2290 return (UU_WALK_NEXT);
2291 2291 }
2292 2292
2293 2293 entr = scf_entry_create(lcbdata->sc_handle);
2294 2294 if (entr == NULL) {
2295 2295 switch (scf_error()) {
2296 2296 case SCF_ERROR_NO_MEMORY:
2297 2297 return (stash_scferror(lcbdata));
2298 2298
2299 2299 case SCF_ERROR_INVALID_ARGUMENT:
2300 2300 default:
2301 2301 bad_error("scf_entry_create", scf_error());
2302 2302 }
2303 2303 }
2304 2304
2305 2305 tp = p->sc_value_type;
2306 2306
2307 2307 if (scf_transaction_property_new(trans, entr,
2308 2308 p->sc_property_name, tp) != 0) {
2309 2309 switch (scf_error()) {
2310 2310 case SCF_ERROR_INVALID_ARGUMENT:
2311 2311 semerr(emsg_invalid_prop_name, p->sc_property_name);
2312 2312 scf_entry_destroy(entr);
2313 2313 return (stash_scferror(lcbdata));
2314 2314
2315 2315 case SCF_ERROR_EXISTS:
2316 2316 break;
2317 2317
2318 2318 case SCF_ERROR_DELETED:
2319 2319 case SCF_ERROR_CONNECTION_BROKEN:
2320 2320 scf_entry_destroy(entr);
2321 2321 return (stash_scferror(lcbdata));
2322 2322
2323 2323 case SCF_ERROR_NOT_BOUND:
2324 2324 case SCF_ERROR_HANDLE_MISMATCH:
2325 2325 case SCF_ERROR_NOT_SET:
2326 2326 default:
2327 2327 bad_error("scf_transaction_property_new", scf_error());
2328 2328 }
2329 2329
2330 2330 if (scf_transaction_property_change_type(trans, entr,
2331 2331 p->sc_property_name, tp) != 0) {
2332 2332 switch (scf_error()) {
2333 2333 case SCF_ERROR_DELETED:
2334 2334 case SCF_ERROR_CONNECTION_BROKEN:
2335 2335 scf_entry_destroy(entr);
2336 2336 return (stash_scferror(lcbdata));
2337 2337
2338 2338 case SCF_ERROR_INVALID_ARGUMENT:
2339 2339 semerr(emsg_invalid_prop_name,
2340 2340 p->sc_property_name);
2341 2341 scf_entry_destroy(entr);
2342 2342 return (stash_scferror(lcbdata));
2343 2343
2344 2344 case SCF_ERROR_NOT_FOUND:
2345 2345 case SCF_ERROR_NOT_SET:
2346 2346 case SCF_ERROR_HANDLE_MISMATCH:
2347 2347 case SCF_ERROR_NOT_BOUND:
2348 2348 default:
2349 2349 bad_error(
2350 2350 "scf_transaction_property_change_type",
2351 2351 scf_error());
2352 2352 }
2353 2353 }
2354 2354 }
2355 2355
2356 2356 for (vp = uu_list_first(p->sc_property_values);
2357 2357 vp != NULL;
2358 2358 vp = uu_list_next(p->sc_property_values, vp)) {
2359 2359 val = scf_value_create(g_hndl);
2360 2360 if (val == NULL) {
2361 2361 switch (scf_error()) {
2362 2362 case SCF_ERROR_NO_MEMORY:
2363 2363 return (stash_scferror(lcbdata));
2364 2364
2365 2365 case SCF_ERROR_INVALID_ARGUMENT:
2366 2366 default:
2367 2367 bad_error("scf_value_create", scf_error());
2368 2368 }
2369 2369 }
2370 2370
2371 2371 switch (tp) {
2372 2372 case SCF_TYPE_BOOLEAN:
2373 2373 scf_value_set_boolean(val, vp->sc_u.sc_count);
2374 2374 break;
2375 2375 case SCF_TYPE_COUNT:
2376 2376 scf_value_set_count(val, vp->sc_u.sc_count);
2377 2377 break;
2378 2378 case SCF_TYPE_INTEGER:
2379 2379 scf_value_set_integer(val, vp->sc_u.sc_integer);
2380 2380 break;
2381 2381 default:
2382 2382 assert(vp->sc_u.sc_string != NULL);
2383 2383 if (scf_value_set_from_string(val, tp,
2384 2384 vp->sc_u.sc_string) != 0) {
2385 2385 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2386 2386 bad_error("scf_value_set_from_string",
2387 2387 scf_error());
2388 2388
2389 2389 warn(gettext("Value \"%s\" is not a valid "
2390 2390 "%s.\n"), vp->sc_u.sc_string,
2391 2391 scf_type_to_string(tp));
2392 2392 scf_value_destroy(val);
2393 2393 return (stash_scferror(lcbdata));
2394 2394 }
2395 2395 break;
2396 2396 }
2397 2397
2398 2398 if (scf_entry_add_value(entr, val) != 0)
2399 2399 bad_error("scf_entry_add_value", scf_error());
2400 2400 }
2401 2401
2402 2402 return (UU_WALK_NEXT);
2403 2403 }
2404 2404
2405 2405 /*
2406 2406 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent,
2407 2407 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2408 2408 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2409 2409 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2410 2410 * lcbdata->sc_err to
2411 2411 * ECONNABORTED - repository connection broken
2412 2412 * ENOMEM - out of memory
2413 2413 * ENOSPC - svc.configd is out of resources
2414 2414 * ECANCELED - sc_parent was deleted
2415 2415 * EPERM - could not create property group (permission denied) (error printed)
2416 2416 * - could not modify property group (permission denied) (error printed)
2417 2417 * - could not delete property group (permission denied) (error printed)
2418 2418 * EROFS - could not create property group (repository is read-only)
2419 2419 * - could not delete property group (repository is read-only)
2420 2420 * EACCES - could not create property group (backend access denied)
2421 2421 * - could not delete property group (backend access denied)
2422 2422 * EEXIST - could not create property group (already exists)
2423 2423 * EINVAL - invalid property group name (error printed)
2424 2424 * - invalid property name (error printed)
2425 2425 * - invalid value (error printed)
2426 2426 * EBUSY - new property group deleted (error printed)
2427 2427 * - new property group changed (error printed)
2428 2428 * - property group added (error printed)
2429 2429 * - property group deleted (error printed)
2430 2430 */
2431 2431 static int
2432 2432 entity_pgroup_import(void *v, void *pvt)
2433 2433 {
2434 2434 pgroup_t *p = v;
2435 2435 scf_callback_t cbdata;
2436 2436 scf_callback_t *lcbdata = pvt;
2437 2437 void *ent = lcbdata->sc_parent;
2438 2438 int issvc = lcbdata->sc_service;
2439 2439 int r;
2440 2440
2441 2441 const char * const pg_changed = gettext("%s changed unexpectedly "
2442 2442 "(new property group \"%s\" changed).\n");
2443 2443
2444 2444 /* Never import deleted property groups. */
2445 2445 if (p->sc_pgroup_delete) {
2446 2446 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2447 2447 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2448 2448 goto delete_pg;
2449 2449 }
2450 2450 return (UU_WALK_NEXT);
2451 2451 }
2452 2452
2453 2453 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2454 2454 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2455 2455 lcbdata->sc_general = p;
2456 2456 return (UU_WALK_NEXT);
2457 2457 }
2458 2458
2459 2459 add_pg:
2460 2460 if (issvc)
2461 2461 r = scf_service_add_pg(ent, p->sc_pgroup_name,
2462 2462 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2463 2463 else
2464 2464 r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2465 2465 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2466 2466 if (r != 0) {
2467 2467 switch (scf_error()) {
2468 2468 case SCF_ERROR_DELETED:
2469 2469 case SCF_ERROR_CONNECTION_BROKEN:
2470 2470 case SCF_ERROR_BACKEND_READONLY:
2471 2471 case SCF_ERROR_BACKEND_ACCESS:
2472 2472 case SCF_ERROR_NO_RESOURCES:
2473 2473 return (stash_scferror(lcbdata));
2474 2474
2475 2475 case SCF_ERROR_EXISTS:
2476 2476 if (lcbdata->sc_flags & SCI_FORCE)
2477 2477 break;
2478 2478 return (stash_scferror(lcbdata));
2479 2479
2480 2480 case SCF_ERROR_INVALID_ARGUMENT:
2481 2481 warn(emsg_fmri_invalid_pg_name_type,
2482 2482 lcbdata->sc_source_fmri,
2483 2483 p->sc_pgroup_name, p->sc_pgroup_type);
2484 2484 return (stash_scferror(lcbdata));
2485 2485
2486 2486 case SCF_ERROR_PERMISSION_DENIED:
2487 2487 warn(emsg_pg_add_perm, p->sc_pgroup_name,
2488 2488 lcbdata->sc_target_fmri);
2489 2489 return (stash_scferror(lcbdata));
2490 2490
2491 2491 case SCF_ERROR_NOT_BOUND:
2492 2492 case SCF_ERROR_HANDLE_MISMATCH:
2493 2493 case SCF_ERROR_NOT_SET:
2494 2494 default:
2495 2495 bad_error("scf_service_add_pg", scf_error());
2496 2496 }
2497 2497
2498 2498 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2499 2499 switch (scf_error()) {
2500 2500 case SCF_ERROR_CONNECTION_BROKEN:
2501 2501 case SCF_ERROR_DELETED:
2502 2502 return (stash_scferror(lcbdata));
2503 2503
2504 2504 case SCF_ERROR_INVALID_ARGUMENT:
2505 2505 warn(emsg_fmri_invalid_pg_name,
2506 2506 lcbdata->sc_source_fmri,
2507 2507 p->sc_pgroup_name);
2508 2508 return (stash_scferror(lcbdata));
2509 2509
2510 2510 case SCF_ERROR_NOT_FOUND:
2511 2511 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2512 2512 p->sc_pgroup_name);
2513 2513 lcbdata->sc_err = EBUSY;
2514 2514 return (UU_WALK_ERROR);
2515 2515
2516 2516 case SCF_ERROR_NOT_BOUND:
2517 2517 case SCF_ERROR_HANDLE_MISMATCH:
2518 2518 case SCF_ERROR_NOT_SET:
2519 2519 default:
2520 2520 bad_error("entity_get_pg", scf_error());
2521 2521 }
2522 2522 }
2523 2523
2524 2524 if (lcbdata->sc_flags & SCI_KEEP)
2525 2525 goto props;
2526 2526
2527 2527 delete_pg:
2528 2528 if (scf_pg_delete(imp_pg) != 0) {
2529 2529 switch (scf_error()) {
2530 2530 case SCF_ERROR_DELETED:
2531 2531 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2532 2532 p->sc_pgroup_name);
2533 2533 lcbdata->sc_err = EBUSY;
2534 2534 return (UU_WALK_ERROR);
2535 2535
2536 2536 case SCF_ERROR_PERMISSION_DENIED:
2537 2537 warn(emsg_pg_del_perm, p->sc_pgroup_name,
2538 2538 lcbdata->sc_target_fmri);
2539 2539 return (stash_scferror(lcbdata));
2540 2540
2541 2541 case SCF_ERROR_BACKEND_READONLY:
2542 2542 case SCF_ERROR_BACKEND_ACCESS:
2543 2543 case SCF_ERROR_CONNECTION_BROKEN:
2544 2544 return (stash_scferror(lcbdata));
2545 2545
2546 2546 case SCF_ERROR_NOT_SET:
2547 2547 default:
2548 2548 bad_error("scf_pg_delete", scf_error());
2549 2549 }
2550 2550 }
2551 2551
2552 2552 if (p->sc_pgroup_delete)
2553 2553 return (UU_WALK_NEXT);
2554 2554
2555 2555 goto add_pg;
2556 2556 }
2557 2557
2558 2558 props:
2559 2559
2560 2560 /*
2561 2561 * Add properties to property group, if any.
2562 2562 */
2563 2563 cbdata.sc_handle = lcbdata->sc_handle;
2564 2564 cbdata.sc_parent = imp_pg;
2565 2565 cbdata.sc_flags = lcbdata->sc_flags;
2566 2566 cbdata.sc_trans = imp_tx;
2567 2567 cbdata.sc_enable = NULL;
2568 2568
2569 2569 if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2570 2570 switch (scf_error()) {
2571 2571 case SCF_ERROR_BACKEND_ACCESS:
2572 2572 case SCF_ERROR_BACKEND_READONLY:
2573 2573 case SCF_ERROR_CONNECTION_BROKEN:
2574 2574 return (stash_scferror(lcbdata));
2575 2575
2576 2576 case SCF_ERROR_DELETED:
2577 2577 warn(pg_changed, lcbdata->sc_target_fmri,
2578 2578 p->sc_pgroup_name);
2579 2579 lcbdata->sc_err = EBUSY;
2580 2580 return (UU_WALK_ERROR);
2581 2581
2582 2582 case SCF_ERROR_PERMISSION_DENIED:
2583 2583 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2584 2584 lcbdata->sc_target_fmri);
2585 2585 return (stash_scferror(lcbdata));
2586 2586
2587 2587 case SCF_ERROR_NOT_BOUND:
2588 2588 case SCF_ERROR_NOT_SET:
2589 2589 case SCF_ERROR_IN_USE:
2590 2590 case SCF_ERROR_HANDLE_MISMATCH:
2591 2591 default:
2592 2592 bad_error("scf_transaction_start", scf_error());
2593 2593 }
2594 2594 }
2595 2595
2596 2596 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2597 2597 UU_DEFAULT) != 0) {
2598 2598 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2599 2599 bad_error("uu_list_walk", uu_error());
2600 2600 scf_transaction_reset(imp_tx);
2601 2601
2602 2602 lcbdata->sc_err = cbdata.sc_err;
2603 2603 if (cbdata.sc_err == ECANCELED) {
2604 2604 warn(pg_changed, lcbdata->sc_target_fmri,
2605 2605 p->sc_pgroup_name);
2606 2606 lcbdata->sc_err = EBUSY;
2607 2607 }
2608 2608 return (UU_WALK_ERROR);
2609 2609 }
2610 2610
2611 2611 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2612 2612 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2613 2613
2614 2614 /*
2615 2615 * take the snapshot running snapshot then
2616 2616 * import the stored general/enable property
2617 2617 */
2618 2618 r = take_snap(ent, snap_running, imp_rsnap);
2619 2619 switch (r) {
2620 2620 case 0:
2621 2621 break;
2622 2622
2623 2623 case ECONNABORTED:
2624 2624 warn(gettext("Could not take %s snapshot on import "
2625 2625 "(repository connection broken).\n"),
2626 2626 snap_running);
2627 2627 lcbdata->sc_err = r;
2628 2628 return (UU_WALK_ERROR);
2629 2629 case ECANCELED:
2630 2630 warn(emsg_deleted);
2631 2631 lcbdata->sc_err = r;
2632 2632 return (UU_WALK_ERROR);
2633 2633
2634 2634 case EPERM:
2635 2635 warn(gettext("Could not take %s snapshot "
2636 2636 "(permission denied).\n"), snap_running);
2637 2637 lcbdata->sc_err = r;
2638 2638 return (UU_WALK_ERROR);
2639 2639
2640 2640 case ENOSPC:
2641 2641 warn(gettext("Could not take %s snapshot"
2642 2642 "(repository server out of resources).\n"),
2643 2643 snap_running);
2644 2644 lcbdata->sc_err = r;
2645 2645 return (UU_WALK_ERROR);
2646 2646
2647 2647 default:
2648 2648 bad_error("take_snap", r);
2649 2649 }
2650 2650
2651 2651 r = lscf_property_import(cbdata.sc_enable, &cbdata);
2652 2652 if (r != UU_WALK_NEXT) {
2653 2653 if (r != UU_WALK_ERROR)
2654 2654 bad_error("lscf_property_import", r);
2655 2655 return (EINVAL);
2656 2656 }
2657 2657 }
2658 2658
2659 2659 r = scf_transaction_commit(imp_tx);
2660 2660 switch (r) {
2661 2661 case 1:
2662 2662 r = UU_WALK_NEXT;
2663 2663 break;
2664 2664
2665 2665 case 0:
2666 2666 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2667 2667 lcbdata->sc_err = EBUSY;
2668 2668 r = UU_WALK_ERROR;
2669 2669 break;
2670 2670
2671 2671 case -1:
2672 2672 switch (scf_error()) {
2673 2673 case SCF_ERROR_BACKEND_READONLY:
2674 2674 case SCF_ERROR_BACKEND_ACCESS:
2675 2675 case SCF_ERROR_CONNECTION_BROKEN:
2676 2676 case SCF_ERROR_NO_RESOURCES:
2677 2677 r = stash_scferror(lcbdata);
2678 2678 break;
2679 2679
2680 2680 case SCF_ERROR_DELETED:
2681 2681 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2682 2682 p->sc_pgroup_name);
2683 2683 lcbdata->sc_err = EBUSY;
2684 2684 r = UU_WALK_ERROR;
2685 2685 break;
2686 2686
2687 2687 case SCF_ERROR_PERMISSION_DENIED:
2688 2688 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2689 2689 lcbdata->sc_target_fmri);
2690 2690 r = stash_scferror(lcbdata);
2691 2691 break;
2692 2692
2693 2693 case SCF_ERROR_NOT_SET:
2694 2694 case SCF_ERROR_INVALID_ARGUMENT:
2695 2695 case SCF_ERROR_NOT_BOUND:
2696 2696 default:
2697 2697 bad_error("scf_transaction_commit", scf_error());
2698 2698 }
2699 2699 break;
2700 2700
2701 2701 default:
2702 2702 bad_error("scf_transaction_commit", r);
2703 2703 }
2704 2704
2705 2705 scf_transaction_destroy_children(imp_tx);
2706 2706
2707 2707 return (r);
2708 2708 }
2709 2709
2710 2710 /*
2711 2711 * Returns
2712 2712 * 0 - success
2713 2713 * ECONNABORTED - repository connection broken
2714 2714 * ENOMEM - out of memory
2715 2715 * ENOSPC - svc.configd is out of resources
2716 2716 * ECANCELED - inst was deleted
2717 2717 * EPERM - could not create property group (permission denied) (error printed)
2718 2718 * - could not modify property group (permission denied) (error printed)
2719 2719 * EROFS - could not create property group (repository is read-only)
2720 2720 * EACCES - could not create property group (backend access denied)
2721 2721 * EEXIST - could not create property group (already exists)
2722 2722 * EINVAL - invalid property group name (error printed)
2723 2723 * - invalid property name (error printed)
2724 2724 * - invalid value (error printed)
2725 2725 * EBUSY - new property group changed (error printed)
2726 2726 */
2727 2727 static int
2728 2728 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2729 2729 const entity_t *isvc, int flags)
2730 2730 {
2731 2731 scf_callback_t cbdata;
2732 2732
2733 2733 cbdata.sc_handle = scf_service_handle(svc);
2734 2734 cbdata.sc_parent = svc;
2735 2735 cbdata.sc_service = 1;
2736 2736 cbdata.sc_general = 0;
2737 2737 cbdata.sc_enable = 0;
2738 2738 cbdata.sc_flags = flags;
2739 2739 cbdata.sc_source_fmri = isvc->sc_fmri;
2740 2740 cbdata.sc_target_fmri = target_fmri;
2741 2741
2742 2742 /*
2743 2743 * If the op is set, then add the flag to the callback
2744 2744 * flags for later use.
2745 2745 */
2746 2746 if (isvc->sc_op != SVCCFG_OP_NONE) {
2747 2747 switch (isvc->sc_op) {
2748 2748 case SVCCFG_OP_IMPORT :
2749 2749 cbdata.sc_flags |= SCI_OP_IMPORT;
2750 2750 break;
2751 2751 case SVCCFG_OP_APPLY :
2752 2752 cbdata.sc_flags |= SCI_OP_APPLY;
2753 2753 break;
2754 2754 case SVCCFG_OP_RESTORE :
2755 2755 cbdata.sc_flags |= SCI_OP_RESTORE;
2756 2756 break;
2757 2757 default :
2758 2758 uu_die(gettext("lscf_import_service_pgs : "
2759 2759 "Unknown op stored in the service entity\n"));
2760 2760
2761 2761 }
2762 2762 }
2763 2763
2764 2764 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2765 2765 UU_DEFAULT) != 0) {
2766 2766 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2767 2767 bad_error("uu_list_walk", uu_error());
2768 2768
2769 2769 return (cbdata.sc_err);
2770 2770 }
2771 2771
2772 2772 return (0);
2773 2773 }
2774 2774
2775 2775 /*
2776 2776 * Returns
2777 2777 * 0 - success
2778 2778 * ECONNABORTED - repository connection broken
2779 2779 * ENOMEM - out of memory
2780 2780 * ENOSPC - svc.configd is out of resources
2781 2781 * ECANCELED - inst was deleted
2782 2782 * EPERM - could not create property group (permission denied) (error printed)
2783 2783 * - could not modify property group (permission denied) (error printed)
2784 2784 * EROFS - could not create property group (repository is read-only)
2785 2785 * EACCES - could not create property group (backend access denied)
2786 2786 * EEXIST - could not create property group (already exists)
2787 2787 * EINVAL - invalid property group name (error printed)
2788 2788 * - invalid property name (error printed)
2789 2789 * - invalid value (error printed)
2790 2790 * EBUSY - new property group changed (error printed)
2791 2791 */
2792 2792 static int
2793 2793 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2794 2794 const entity_t *iinst, int flags)
2795 2795 {
2796 2796 scf_callback_t cbdata;
2797 2797
2798 2798 cbdata.sc_handle = scf_instance_handle(inst);
2799 2799 cbdata.sc_parent = inst;
2800 2800 cbdata.sc_service = 0;
2801 2801 cbdata.sc_general = NULL;
2802 2802 cbdata.sc_enable = NULL;
2803 2803 cbdata.sc_flags = flags;
2804 2804 cbdata.sc_source_fmri = iinst->sc_fmri;
2805 2805 cbdata.sc_target_fmri = target_fmri;
2806 2806
2807 2807 /*
2808 2808 * If the op is set, then add the flag to the callback
2809 2809 * flags for later use.
2810 2810 */
2811 2811 if (iinst->sc_op != SVCCFG_OP_NONE) {
2812 2812 switch (iinst->sc_op) {
2813 2813 case SVCCFG_OP_IMPORT :
2814 2814 cbdata.sc_flags |= SCI_OP_IMPORT;
2815 2815 break;
2816 2816 case SVCCFG_OP_APPLY :
2817 2817 cbdata.sc_flags |= SCI_OP_APPLY;
2818 2818 break;
2819 2819 case SVCCFG_OP_RESTORE :
2820 2820 cbdata.sc_flags |= SCI_OP_RESTORE;
2821 2821 break;
2822 2822 default :
2823 2823 uu_die(gettext("lscf_import_instance_pgs : "
2824 2824 "Unknown op stored in the instance entity\n"));
2825 2825 }
2826 2826 }
2827 2827
2828 2828 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2829 2829 UU_DEFAULT) != 0) {
2830 2830 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2831 2831 bad_error("uu_list_walk", uu_error());
2832 2832
2833 2833 return (cbdata.sc_err);
2834 2834 }
2835 2835
2836 2836 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2837 2837 cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2838 2838 /*
2839 2839 * If importing with the SCI_NOENABLED flag then
2840 2840 * skip the delay, but if not then add the delay
2841 2841 * of the enable property.
2842 2842 */
2843 2843 if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2844 2844 cbdata.sc_flags |= SCI_DELAYENABLE;
2845 2845 }
2846 2846
2847 2847 if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2848 2848 != UU_WALK_NEXT)
2849 2849 return (cbdata.sc_err);
2850 2850 }
2851 2851
2852 2852 return (0);
2853 2853 }
2854 2854
2855 2855 /*
2856 2856 * Report the reasons why we can't upgrade pg2 to pg1.
2857 2857 */
2858 2858 static void
2859 2859 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2860 2860 int new)
2861 2861 {
2862 2862 property_t *p1, *p2;
2863 2863
2864 2864 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2865 2865
2866 2866 if (!pg_attrs_equal(pg1, pg2, fmri, new))
2867 2867 return;
2868 2868
2869 2869 for (p1 = uu_list_first(pg1->sc_pgroup_props);
2870 2870 p1 != NULL;
2871 2871 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2872 2872 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2873 2873 if (p2 != NULL) {
2874 2874 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2875 2875 new);
2876 2876 continue;
2877 2877 }
2878 2878
2879 2879 if (new)
2880 2880 warn(gettext("Conflict upgrading %s (new property "
2881 2881 "group \"%s\" is missing property \"%s\").\n"),
2882 2882 fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2883 2883 else
2884 2884 warn(gettext("Conflict upgrading %s (property "
2885 2885 "\"%s/%s\" is missing).\n"), fmri,
2886 2886 pg1->sc_pgroup_name, p1->sc_property_name);
2887 2887 }
2888 2888
2889 2889 /*
2890 2890 * Since pg1 should be from the manifest, any properties in pg2 which
2891 2891 * aren't in pg1 shouldn't be reported as conflicts.
2892 2892 */
2893 2893 }
2894 2894
2895 2895 /*
2896 2896 * Add transaction entries to tx which will upgrade cur's pg according to old
2897 2897 * & new.
2898 2898 *
2899 2899 * Returns
2900 2900 * 0 - success
2901 2901 * EINVAL - new has a property with an invalid name or value (message emitted)
2902 2902 * ENOMEM - out of memory
2903 2903 */
2904 2904 static int
2905 2905 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2906 2906 pgroup_t *cur, int speak, const char *fmri)
2907 2907 {
2908 2908 property_t *p, *new_p, *cur_p;
2909 2909 scf_transaction_entry_t *e;
2910 2910 int r;
2911 2911 int is_general;
2912 2912 int is_protected;
2913 2913
2914 2914 if (uu_list_walk(new->sc_pgroup_props, clear_int,
2915 2915 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2916 2916 bad_error("uu_list_walk", uu_error());
2917 2917
2918 2918 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2919 2919
2920 2920 for (p = uu_list_first(old->sc_pgroup_props);
2921 2921 p != NULL;
2922 2922 p = uu_list_next(old->sc_pgroup_props, p)) {
2923 2923 /* p is a property in the old property group. */
2924 2924
2925 2925 /* Protect live properties. */
2926 2926 is_protected = 0;
2927 2927 if (is_general) {
2928 2928 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2929 2929 0 ||
2930 2930 strcmp(p->sc_property_name,
2931 2931 SCF_PROPERTY_RESTARTER) == 0)
2932 2932 is_protected = 1;
2933 2933 }
2934 2934
2935 2935 /* Look for the same property in the new properties. */
2936 2936 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2937 2937 if (new_p != NULL) {
2938 2938 new_p->sc_seen = 1;
2939 2939
2940 2940 /*
2941 2941 * If the new property is the same as the old, don't do
2942 2942 * anything (leave any user customizations).
2943 2943 */
2944 2944 if (prop_equal(p, new_p, NULL, NULL, 0))
2945 2945 continue;
2946 2946
2947 2947 if (new_p->sc_property_override)
2948 2948 goto upgrade;
2949 2949 }
2950 2950
2951 2951 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2952 2952 if (cur_p == NULL) {
2953 2953 /*
2954 2954 * p has been deleted from the repository. If we were
2955 2955 * going to delete it anyway, do nothing. Otherwise
2956 2956 * report a conflict.
2957 2957 */
2958 2958 if (new_p == NULL)
2959 2959 continue;
2960 2960
2961 2961 if (is_protected)
2962 2962 continue;
2963 2963
2964 2964 warn(gettext("Conflict upgrading %s "
2965 2965 "(property \"%s/%s\" is missing).\n"), fmri,
2966 2966 old->sc_pgroup_name, p->sc_property_name);
2967 2967 continue;
2968 2968 }
2969 2969
2970 2970 if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2971 2971 /*
2972 2972 * Conflict. Don't warn if the property is already the
2973 2973 * way we want it, though.
2974 2974 */
2975 2975 if (is_protected)
2976 2976 continue;
2977 2977
2978 2978 if (new_p == NULL)
2979 2979 (void) prop_equal(p, cur_p, fmri,
2980 2980 old->sc_pgroup_name, 0);
2981 2981 else
2982 2982 (void) prop_equal(cur_p, new_p, fmri,
2983 2983 old->sc_pgroup_name, 0);
2984 2984 continue;
2985 2985 }
2986 2986
2987 2987 if (is_protected) {
2988 2988 if (speak)
2989 2989 warn(gettext("%s: Refusing to upgrade "
2990 2990 "\"%s/%s\" (live property).\n"), fmri,
2991 2991 old->sc_pgroup_name, p->sc_property_name);
2992 2992 continue;
2993 2993 }
2994 2994
2995 2995 upgrade:
2996 2996 /* p hasn't been customized in the repository. Upgrade it. */
2997 2997 if (new_p == NULL) {
2998 2998 /* p was deleted. Delete from cur if unchanged. */
2999 2999 if (speak)
3000 3000 warn(gettext(
3001 3001 "%s: Deleting property \"%s/%s\".\n"),
3002 3002 fmri, old->sc_pgroup_name,
3003 3003 p->sc_property_name);
3004 3004
3005 3005 e = scf_entry_create(g_hndl);
3006 3006 if (e == NULL)
3007 3007 return (ENOMEM);
3008 3008
3009 3009 if (scf_transaction_property_delete(tx, e,
3010 3010 p->sc_property_name) != 0) {
3011 3011 switch (scf_error()) {
3012 3012 case SCF_ERROR_DELETED:
3013 3013 scf_entry_destroy(e);
3014 3014 return (ECANCELED);
3015 3015
3016 3016 case SCF_ERROR_CONNECTION_BROKEN:
3017 3017 scf_entry_destroy(e);
3018 3018 return (ECONNABORTED);
3019 3019
3020 3020 case SCF_ERROR_NOT_FOUND:
3021 3021 /*
3022 3022 * This can happen if cur is from the
3023 3023 * running snapshot (and it differs
3024 3024 * from the live properties).
3025 3025 */
3026 3026 scf_entry_destroy(e);
3027 3027 break;
3028 3028
3029 3029 case SCF_ERROR_HANDLE_MISMATCH:
3030 3030 case SCF_ERROR_NOT_BOUND:
3031 3031 case SCF_ERROR_NOT_SET:
3032 3032 case SCF_ERROR_INVALID_ARGUMENT:
3033 3033 default:
3034 3034 bad_error(
3035 3035 "scf_transaction_property_delete",
3036 3036 scf_error());
3037 3037 }
3038 3038 }
3039 3039 } else {
3040 3040 scf_callback_t ctx;
3041 3041
3042 3042 if (speak)
3043 3043 warn(gettext(
3044 3044 "%s: Upgrading property \"%s/%s\".\n"),
3045 3045 fmri, old->sc_pgroup_name,
3046 3046 p->sc_property_name);
3047 3047
3048 3048 ctx.sc_handle = g_hndl;
3049 3049 ctx.sc_trans = tx;
3050 3050 ctx.sc_flags = 0;
3051 3051
3052 3052 r = lscf_property_import(new_p, &ctx);
3053 3053 if (r != UU_WALK_NEXT) {
3054 3054 if (r != UU_WALK_ERROR)
3055 3055 bad_error("lscf_property_import", r);
3056 3056 return (EINVAL);
3057 3057 }
3058 3058 }
3059 3059 }
3060 3060
3061 3061 /* Go over the properties which were added. */
3062 3062 for (new_p = uu_list_first(new->sc_pgroup_props);
3063 3063 new_p != NULL;
3064 3064 new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3065 3065 if (new_p->sc_seen)
3066 3066 continue;
3067 3067
3068 3068 /* This is a new property. */
3069 3069 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3070 3070 if (cur_p == NULL) {
3071 3071 scf_callback_t ctx;
3072 3072
3073 3073 ctx.sc_handle = g_hndl;
3074 3074 ctx.sc_trans = tx;
3075 3075 ctx.sc_flags = 0;
3076 3076
3077 3077 r = lscf_property_import(new_p, &ctx);
3078 3078 if (r != UU_WALK_NEXT) {
3079 3079 if (r != UU_WALK_ERROR)
3080 3080 bad_error("lscf_property_import", r);
3081 3081 return (EINVAL);
3082 3082 }
3083 3083 continue;
3084 3084 }
3085 3085
3086 3086 /*
3087 3087 * Report a conflict if the new property differs from the
3088 3088 * current one. Unless it's general/enabled, since that's
3089 3089 * never in the last-import snapshot.
3090 3090 */
3091 3091 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3092 3092 0 &&
3093 3093 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3094 3094 continue;
3095 3095
3096 3096 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3097 3097 }
3098 3098
3099 3099 return (0);
3100 3100 }
3101 3101
3102 3102 /*
3103 3103 * Upgrade pg according to old & new.
3104 3104 *
3105 3105 * Returns
3106 3106 * 0 - success
3107 3107 * ECONNABORTED - repository connection broken
3108 3108 * ENOMEM - out of memory
3109 3109 * ENOSPC - svc.configd is out of resources
3110 3110 * ECANCELED - pg was deleted
3111 3111 * EPERM - couldn't modify pg (permission denied)
3112 3112 * EROFS - couldn't modify pg (backend read-only)
3113 3113 * EACCES - couldn't modify pg (backend access denied)
3114 3114 * EINVAL - new has a property with invalid name or value (error printed)
3115 3115 * EBUSY - pg changed unexpectedly
3116 3116 */
3117 3117 static int
3118 3118 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3119 3119 pgroup_t *new, int speak, const char *fmri)
3120 3120 {
3121 3121 int r;
3122 3122
3123 3123 if (scf_transaction_start(imp_tx, pg) != 0) {
3124 3124 switch (scf_error()) {
3125 3125 case SCF_ERROR_CONNECTION_BROKEN:
3126 3126 case SCF_ERROR_DELETED:
3127 3127 case SCF_ERROR_PERMISSION_DENIED:
3128 3128 case SCF_ERROR_BACKEND_READONLY:
3129 3129 case SCF_ERROR_BACKEND_ACCESS:
3130 3130 return (scferror2errno(scf_error()));
3131 3131
3132 3132 case SCF_ERROR_HANDLE_MISMATCH:
3133 3133 case SCF_ERROR_IN_USE:
3134 3134 case SCF_ERROR_NOT_BOUND:
3135 3135 case SCF_ERROR_NOT_SET:
3136 3136 default:
3137 3137 bad_error("scf_transaction_start", scf_error());
3138 3138 }
3139 3139 }
3140 3140
3141 3141 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3142 3142 switch (r) {
3143 3143 case 0:
3144 3144 break;
3145 3145
3146 3146 case EINVAL:
3147 3147 case ENOMEM:
3148 3148 scf_transaction_destroy_children(imp_tx);
3149 3149 return (r);
3150 3150
3151 3151 default:
3152 3152 bad_error("add_upgrade_entries", r);
3153 3153 }
3154 3154
3155 3155 r = scf_transaction_commit(imp_tx);
3156 3156
3157 3157 scf_transaction_destroy_children(imp_tx);
3158 3158
3159 3159 switch (r) {
3160 3160 case 1:
3161 3161 break;
3162 3162
3163 3163 case 0:
3164 3164 return (EBUSY);
3165 3165
3166 3166 case -1:
3167 3167 switch (scf_error()) {
3168 3168 case SCF_ERROR_CONNECTION_BROKEN:
3169 3169 case SCF_ERROR_NO_RESOURCES:
3170 3170 case SCF_ERROR_PERMISSION_DENIED:
3171 3171 case SCF_ERROR_BACKEND_READONLY:
3172 3172 case SCF_ERROR_BACKEND_ACCESS:
3173 3173 case SCF_ERROR_DELETED:
3174 3174 return (scferror2errno(scf_error()));
3175 3175
3176 3176 case SCF_ERROR_NOT_BOUND:
3177 3177 case SCF_ERROR_INVALID_ARGUMENT:
3178 3178 case SCF_ERROR_NOT_SET:
3179 3179 default:
3180 3180 bad_error("scf_transaction_commit", scf_error());
3181 3181 }
3182 3182
3183 3183 default:
3184 3184 bad_error("scf_transaction_commit", r);
3185 3185 }
3186 3186
3187 3187 return (0);
3188 3188 }
3189 3189
3190 3190 /*
3191 3191 * Compares two entity FMRIs. Returns
3192 3192 *
3193 3193 * 1 - equal
3194 3194 * 0 - not equal
3195 3195 * -1 - f1 is invalid or not an entity
3196 3196 * -2 - f2 is invalid or not an entity
3197 3197 */
3198 3198 static int
3199 3199 fmri_equal(const char *f1, const char *f2)
3200 3200 {
3201 3201 int r;
3202 3202 const char *s1, *i1, *pg1;
3203 3203 const char *s2, *i2, *pg2;
3204 3204
3205 3205 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3206 3206 return (-1);
3207 3207 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3208 3208 return (-1);
3209 3209
3210 3210 if (s1 == NULL || pg1 != NULL)
3211 3211 return (-1);
3212 3212
3213 3213 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3214 3214 return (-2);
3215 3215 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3216 3216 return (-2);
3217 3217
3218 3218 if (s2 == NULL || pg2 != NULL)
3219 3219 return (-2);
3220 3220
3221 3221 r = strcmp(s1, s2);
3222 3222 if (r != 0)
3223 3223 return (0);
3224 3224
3225 3225 if (i1 == NULL && i2 == NULL)
3226 3226 return (1);
3227 3227
3228 3228 if (i1 == NULL || i2 == NULL)
3229 3229 return (0);
3230 3230
3231 3231 return (strcmp(i1, i2) == 0);
3232 3232 }
3233 3233
3234 3234 /*
3235 3235 * Import a dependent by creating a dependency property group in the dependent
3236 3236 * entity. If lcbdata->sc_trans is set, assume it's been started on the
3237 3237 * dependents pg, and add an entry to create a new property for this
3238 3238 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3239 3239 *
3240 3240 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets
3241 3241 * lcbdata->sc_err to
3242 3242 * ECONNABORTED - repository connection broken
3243 3243 * ENOMEM - out of memory
3244 3244 * ENOSPC - configd is out of resources
3245 3245 * EINVAL - target is invalid (error printed)
3246 3246 * - target is not an entity (error printed)
3247 3247 * - dependent has invalid name (error printed)
3248 3248 * - invalid property name (error printed)
3249 3249 * - invalid value (error printed)
3250 3250 * - scope of target does not exist (error printed)
3251 3251 * EPERM - couldn't create target (permission denied) (error printed)
3252 3252 * - couldn't create dependency pg (permission denied) (error printed)
3253 3253 * - couldn't modify dependency pg (permission denied) (error printed)
3254 3254 * EROFS - couldn't create target (repository read-only)
3255 3255 * - couldn't create dependency pg (repository read-only)
3256 3256 * EACCES - couldn't create target (backend access denied)
3257 3257 * - couldn't create dependency pg (backend access denied)
3258 3258 * ECANCELED - sc_trans's pg was deleted
3259 3259 * EALREADY - property for dependent already exists in sc_trans's pg
3260 3260 * EEXIST - dependency pg already exists in target (error printed)
3261 3261 * EBUSY - target deleted (error printed)
3262 3262 * - property group changed during import (error printed)
3263 3263 */
3264 3264 static int
3265 3265 lscf_dependent_import(void *a1, void *pvt)
3266 3266 {
3267 3267 pgroup_t *pgrp = a1;
3268 3268 scf_callback_t *lcbdata = pvt;
3269 3269
3270 3270 int isservice;
3271 3271 int ret;
3272 3272 scf_transaction_entry_t *e;
3273 3273 scf_value_t *val;
3274 3274 scf_callback_t dependent_cbdata;
3275 3275 scf_error_t scfe;
3276 3276
3277 3277 /*
3278 3278 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if
3279 3279 * it's invalid, we fail before modifying the repository.
3280 3280 */
3281 3281 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3282 3282 &dependent_cbdata.sc_parent, &isservice);
3283 3283 switch (scfe) {
3284 3284 case SCF_ERROR_NONE:
3285 3285 break;
3286 3286
3287 3287 case SCF_ERROR_NO_MEMORY:
3288 3288 return (stash_scferror_err(lcbdata, scfe));
3289 3289
3290 3290 case SCF_ERROR_INVALID_ARGUMENT:
3291 3291 semerr(gettext("The FMRI for the \"%s\" dependent is "
3292 3292 "invalid.\n"), pgrp->sc_pgroup_name);
3293 3293 return (stash_scferror_err(lcbdata, scfe));
3294 3294
3295 3295 case SCF_ERROR_CONSTRAINT_VIOLATED:
3296 3296 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3297 3297 "specifies neither a service nor an instance.\n"),
3298 3298 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3299 3299 return (stash_scferror_err(lcbdata, scfe));
3300 3300
3301 3301 case SCF_ERROR_NOT_FOUND:
3302 3302 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3303 3303 &dependent_cbdata.sc_parent, &isservice);
3304 3304 switch (scfe) {
3305 3305 case SCF_ERROR_NONE:
3306 3306 break;
3307 3307
3308 3308 case SCF_ERROR_NO_MEMORY:
3309 3309 case SCF_ERROR_BACKEND_READONLY:
3310 3310 case SCF_ERROR_BACKEND_ACCESS:
3311 3311 return (stash_scferror_err(lcbdata, scfe));
3312 3312
3313 3313 case SCF_ERROR_NOT_FOUND:
3314 3314 semerr(gettext("The scope in FMRI \"%s\" for the "
3315 3315 "\"%s\" dependent does not exist.\n"),
3316 3316 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3317 3317 lcbdata->sc_err = EINVAL;
3318 3318 return (UU_WALK_ERROR);
3319 3319
3320 3320 case SCF_ERROR_PERMISSION_DENIED:
3321 3321 warn(gettext(
3322 3322 "Could not create %s (permission denied).\n"),
3323 3323 pgrp->sc_pgroup_fmri);
3324 3324 return (stash_scferror_err(lcbdata, scfe));
3325 3325
3326 3326 case SCF_ERROR_INVALID_ARGUMENT:
3327 3327 case SCF_ERROR_CONSTRAINT_VIOLATED:
3328 3328 default:
3329 3329 bad_error("create_entity", scfe);
3330 3330 }
3331 3331 break;
3332 3332
3333 3333 default:
3334 3334 bad_error("fmri_to_entity", scfe);
3335 3335 }
3336 3336
3337 3337 if (lcbdata->sc_trans != NULL) {
3338 3338 e = scf_entry_create(lcbdata->sc_handle);
3339 3339 if (e == NULL) {
3340 3340 if (scf_error() != SCF_ERROR_NO_MEMORY)
3341 3341 bad_error("scf_entry_create", scf_error());
3342 3342
3343 3343 entity_destroy(dependent_cbdata.sc_parent, isservice);
3344 3344 return (stash_scferror(lcbdata));
3345 3345 }
3346 3346
3347 3347 if (scf_transaction_property_new(lcbdata->sc_trans, e,
3348 3348 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3349 3349 switch (scf_error()) {
3350 3350 case SCF_ERROR_INVALID_ARGUMENT:
3351 3351 warn(gettext("Dependent of %s has invalid name "
3352 3352 "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3353 3353 pgrp->sc_pgroup_name);
3354 3354 /* FALLTHROUGH */
3355 3355
3356 3356 case SCF_ERROR_DELETED:
3357 3357 case SCF_ERROR_CONNECTION_BROKEN:
3358 3358 scf_entry_destroy(e);
3359 3359 entity_destroy(dependent_cbdata.sc_parent,
3360 3360 isservice);
3361 3361 return (stash_scferror(lcbdata));
3362 3362
3363 3363 case SCF_ERROR_EXISTS:
3364 3364 scf_entry_destroy(e);
3365 3365 entity_destroy(dependent_cbdata.sc_parent,
3366 3366 isservice);
3367 3367 lcbdata->sc_err = EALREADY;
3368 3368 return (UU_WALK_ERROR);
3369 3369
3370 3370 case SCF_ERROR_NOT_BOUND:
3371 3371 case SCF_ERROR_HANDLE_MISMATCH:
3372 3372 case SCF_ERROR_NOT_SET:
3373 3373 default:
3374 3374 bad_error("scf_transaction_property_new",
3375 3375 scf_error());
3376 3376 }
3377 3377 }
3378 3378
3379 3379 val = scf_value_create(lcbdata->sc_handle);
3380 3380 if (val == NULL) {
3381 3381 if (scf_error() != SCF_ERROR_NO_MEMORY)
3382 3382 bad_error("scf_value_create", scf_error());
3383 3383
3384 3384 entity_destroy(dependent_cbdata.sc_parent, isservice);
3385 3385 return (stash_scferror(lcbdata));
3386 3386 }
3387 3387
3388 3388 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3389 3389 pgrp->sc_pgroup_fmri) != 0)
3390 3390 /* invalid should have been caught above */
3391 3391 bad_error("scf_value_set_from_string", scf_error());
3392 3392
3393 3393 if (scf_entry_add_value(e, val) != 0)
3394 3394 bad_error("scf_entry_add_value", scf_error());
3395 3395 }
3396 3396
3397 3397 /* Add the property group to the target entity. */
3398 3398
3399 3399 dependent_cbdata.sc_handle = lcbdata->sc_handle;
3400 3400 dependent_cbdata.sc_flags = lcbdata->sc_flags;
3401 3401 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3402 3402 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3403 3403
3404 3404 ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3405 3405
3406 3406 entity_destroy(dependent_cbdata.sc_parent, isservice);
3407 3407
3408 3408 if (ret == UU_WALK_NEXT)
3409 3409 return (ret);
3410 3410
3411 3411 if (ret != UU_WALK_ERROR)
3412 3412 bad_error("entity_pgroup_import", ret);
3413 3413
3414 3414 switch (dependent_cbdata.sc_err) {
3415 3415 case ECANCELED:
3416 3416 warn(gettext("%s deleted unexpectedly.\n"),
3417 3417 pgrp->sc_pgroup_fmri);
3418 3418 lcbdata->sc_err = EBUSY;
3419 3419 break;
3420 3420
3421 3421 case EEXIST:
3422 3422 warn(gettext("Could not create \"%s\" dependency in %s "
3423 3423 "(already exists).\n"), pgrp->sc_pgroup_name,
3424 3424 pgrp->sc_pgroup_fmri);
3425 3425 /* FALLTHROUGH */
3426 3426
3427 3427 default:
3428 3428 lcbdata->sc_err = dependent_cbdata.sc_err;
3429 3429 }
3430 3430
3431 3431 return (UU_WALK_ERROR);
3432 3432 }
3433 3433
3434 3434 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3435 3435 const scf_snaplevel_t *, scf_transaction_t *);
3436 3436 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3437 3437 const pgroup_t *);
3438 3438
3439 3439 /*
3440 3440 * Upgrade uncustomized dependents of ent to those specified in ient. Read
3441 3441 * the current dependent targets from running (the snaplevel of a running
3442 3442 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3443 3443 * scf_instance_t * according to ient, otherwise). Draw the ancestral
3444 3444 * dependent targets and dependency properties from li_dpts_pg (the
3445 3445 * "dependents" property group in snpl) and snpl (the snaplevel which
3446 3446 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then
3447 3447 * snpl doesn't have a "dependents" property group, and any dependents in ient
3448 3448 * are new.
3449 3449 *
3450 3450 * Returns
3451 3451 * 0 - success
3452 3452 * ECONNABORTED - repository connection broken
3453 3453 * ENOMEM - out of memory
3454 3454 * ENOSPC - configd is out of resources
3455 3455 * ECANCELED - ent was deleted
3456 3456 * ENODEV - the entity containing li_dpts_pg was deleted
3457 3457 * EPERM - could not modify dependents pg (permission denied) (error printed)
3458 3458 * - couldn't upgrade dependent (permission denied) (error printed)
3459 3459 * - couldn't create dependent (permission denied) (error printed)
3460 3460 * EROFS - could not modify dependents pg (repository read-only)
3461 3461 * - couldn't upgrade dependent (repository read-only)
3462 3462 * - couldn't create dependent (repository read-only)
3463 3463 * EACCES - could not modify dependents pg (backend access denied)
3464 3464 * - could not upgrade dependent (backend access denied)
3465 3465 * - could not create dependent (backend access denied)
3466 3466 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3467 3467 * - dependent target deleted (error printed)
3468 3468 * - dependent pg changed (error printed)
3469 3469 * EINVAL - new dependent is invalid (error printed)
3470 3470 * EBADF - snpl is corrupt (error printed)
3471 3471 * - snpl has corrupt pg (error printed)
3472 3472 * - dependency pg in target is corrupt (error printed)
3473 3473 * - target has corrupt snapshot (error printed)
3474 3474 * EEXIST - dependency pg already existed in target service (error printed)
3475 3475 */
3476 3476 static int
3477 3477 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3478 3478 const scf_snaplevel_t *snpl, const entity_t *ient,
3479 3479 const scf_snaplevel_t *running, void *ent)
3480 3480 {
3481 3481 pgroup_t *new_dpt_pgroup;
3482 3482 scf_callback_t cbdata;
3483 3483 int r, unseen, tx_started = 0;
3484 3484 int have_cur_depts;
3485 3485
3486 3486 const char * const dependents = "dependents";
3487 3487
3488 3488 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3489 3489
3490 3490 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3491 3491 /* Nothing to do. */
3492 3492 return (0);
3493 3493
3494 3494 /* Fetch the current version of the "dependents" property group. */
3495 3495 have_cur_depts = 1;
3496 3496 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3497 3497 switch (scf_error()) {
3498 3498 case SCF_ERROR_NOT_FOUND:
3499 3499 break;
3500 3500
3501 3501 case SCF_ERROR_DELETED:
3502 3502 case SCF_ERROR_CONNECTION_BROKEN:
3503 3503 return (scferror2errno(scf_error()));
3504 3504
3505 3505 case SCF_ERROR_NOT_SET:
3506 3506 case SCF_ERROR_INVALID_ARGUMENT:
3507 3507 case SCF_ERROR_HANDLE_MISMATCH:
3508 3508 case SCF_ERROR_NOT_BOUND:
3509 3509 default:
3510 3510 bad_error("entity_get_pg", scf_error());
3511 3511 }
3512 3512
3513 3513 have_cur_depts = 0;
3514 3514 }
3515 3515
3516 3516 /* Fetch the running version of the "dependents" property group. */
3517 3517 ud_run_dpts_pg_set = 0;
3518 3518 if (running != NULL)
3519 3519 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3520 3520 else
3521 3521 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3522 3522 if (r == 0) {
3523 3523 ud_run_dpts_pg_set = 1;
3524 3524 } else {
3525 3525 switch (scf_error()) {
3526 3526 case SCF_ERROR_NOT_FOUND:
3527 3527 break;
3528 3528
3529 3529 case SCF_ERROR_DELETED:
3530 3530 case SCF_ERROR_CONNECTION_BROKEN:
3531 3531 return (scferror2errno(scf_error()));
3532 3532
3533 3533 case SCF_ERROR_NOT_SET:
3534 3534 case SCF_ERROR_INVALID_ARGUMENT:
3535 3535 case SCF_ERROR_HANDLE_MISMATCH:
3536 3536 case SCF_ERROR_NOT_BOUND:
3537 3537 default:
3538 3538 bad_error(running ? "scf_snaplevel_get_pg" :
3539 3539 "entity_get_pg", scf_error());
3540 3540 }
3541 3541 }
3542 3542
3543 3543 /*
3544 3544 * Clear the seen fields of the dependents, so we can tell which ones
3545 3545 * are new.
3546 3546 */
3547 3547 if (uu_list_walk(ient->sc_dependents, clear_int,
3548 3548 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3549 3549 bad_error("uu_list_walk", uu_error());
3550 3550
3551 3551 if (li_dpts_pg != NULL) {
3552 3552 /*
3553 3553 * Each property in li_dpts_pg represents a dependent tag in
3554 3554 * the old manifest. For each, call upgrade_dependent(),
3555 3555 * which will change ud_cur_depts_pg or dependencies in other
3556 3556 * services as appropriate. Note (a) that changes to
3557 3557 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3558 3558 * made en masse, and (b) it's ok if the entity doesn't have
3559 3559 * a current version of the "dependents" property group,
3560 3560 * because we'll just consider all dependents as customized
3561 3561 * (by being deleted).
3562 3562 */
3563 3563
3564 3564 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3565 3565 switch (scf_error()) {
3566 3566 case SCF_ERROR_DELETED:
3567 3567 return (ENODEV);
3568 3568
3569 3569 case SCF_ERROR_CONNECTION_BROKEN:
3570 3570 return (ECONNABORTED);
3571 3571
3572 3572 case SCF_ERROR_HANDLE_MISMATCH:
3573 3573 case SCF_ERROR_NOT_BOUND:
3574 3574 case SCF_ERROR_NOT_SET:
3575 3575 default:
3576 3576 bad_error("scf_iter_pg_properties",
3577 3577 scf_error());
3578 3578 }
3579 3579 }
3580 3580
3581 3581 if (have_cur_depts &&
3582 3582 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3583 3583 switch (scf_error()) {
3584 3584 case SCF_ERROR_BACKEND_ACCESS:
3585 3585 case SCF_ERROR_BACKEND_READONLY:
3586 3586 case SCF_ERROR_CONNECTION_BROKEN:
3587 3587 return (scferror2errno(scf_error()));
3588 3588
3589 3589 case SCF_ERROR_DELETED:
3590 3590 warn(emsg_pg_deleted, ient->sc_fmri,
3591 3591 dependents);
3592 3592 return (EBUSY);
3593 3593
3594 3594 case SCF_ERROR_PERMISSION_DENIED:
3595 3595 warn(emsg_pg_mod_perm, dependents,
3596 3596 ient->sc_fmri);
3597 3597 return (scferror2errno(scf_error()));
3598 3598
3599 3599 case SCF_ERROR_HANDLE_MISMATCH:
3600 3600 case SCF_ERROR_IN_USE:
3601 3601 case SCF_ERROR_NOT_BOUND:
3602 3602 case SCF_ERROR_NOT_SET:
3603 3603 default:
3604 3604 bad_error("scf_transaction_start", scf_error());
3605 3605 }
3606 3606 }
3607 3607 tx_started = have_cur_depts;
3608 3608
3609 3609 for (;;) {
3610 3610 r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3611 3611 if (r == 0)
3612 3612 break;
3613 3613 if (r == 1) {
3614 3614 r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3615 3615 tx_started ? ud_tx : NULL);
3616 3616 switch (r) {
3617 3617 case 0:
3618 3618 continue;
3619 3619
3620 3620 case ECONNABORTED:
3621 3621 case ENOMEM:
3622 3622 case ENOSPC:
3623 3623 case EBADF:
3624 3624 case EBUSY:
3625 3625 case EINVAL:
3626 3626 case EPERM:
3627 3627 case EROFS:
3628 3628 case EACCES:
3629 3629 case EEXIST:
3630 3630 break;
3631 3631
3632 3632 case ECANCELED:
3633 3633 r = ENODEV;
3634 3634 break;
3635 3635
3636 3636 default:
3637 3637 bad_error("upgrade_dependent", r);
3638 3638 }
3639 3639
3640 3640 if (tx_started)
3641 3641 scf_transaction_destroy_children(ud_tx);
3642 3642 return (r);
3643 3643 }
3644 3644 if (r != -1)
3645 3645 bad_error("scf_iter_next_property", r);
3646 3646
3647 3647 switch (scf_error()) {
3648 3648 case SCF_ERROR_DELETED:
3649 3649 r = ENODEV;
3650 3650 break;
3651 3651
3652 3652 case SCF_ERROR_CONNECTION_BROKEN:
3653 3653 r = ECONNABORTED;
3654 3654 break;
3655 3655
3656 3656 case SCF_ERROR_NOT_SET:
3657 3657 case SCF_ERROR_INVALID_ARGUMENT:
3658 3658 case SCF_ERROR_NOT_BOUND:
3659 3659 case SCF_ERROR_HANDLE_MISMATCH:
3660 3660 default:
3661 3661 bad_error("scf_iter_next_property",
3662 3662 scf_error());
3663 3663 }
3664 3664
3665 3665 if (tx_started)
3666 3666 scf_transaction_destroy_children(ud_tx);
3667 3667 return (r);
3668 3668 }
3669 3669 }
3670 3670
3671 3671 /* import unseen dependents */
3672 3672 unseen = 0;
3673 3673 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3674 3674 new_dpt_pgroup != NULL;
3675 3675 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3676 3676 new_dpt_pgroup)) {
3677 3677 if (!new_dpt_pgroup->sc_pgroup_seen) {
3678 3678 unseen = 1;
3679 3679 break;
3680 3680 }
3681 3681 }
3682 3682
3683 3683 /* If there are none, exit early. */
3684 3684 if (unseen == 0)
3685 3685 goto commit;
3686 3686
3687 3687 /* Set up for lscf_dependent_import() */
3688 3688 cbdata.sc_handle = g_hndl;
3689 3689 cbdata.sc_parent = ent;
3690 3690 cbdata.sc_service = issvc;
3691 3691 cbdata.sc_flags = 0;
3692 3692
3693 3693 if (!have_cur_depts) {
3694 3694 /*
3695 3695 * We have new dependents to import, so we need a "dependents"
3696 3696 * property group.
3697 3697 */
3698 3698 if (issvc)
3699 3699 r = scf_service_add_pg(ent, dependents,
3700 3700 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3701 3701 else
3702 3702 r = scf_instance_add_pg(ent, dependents,
3703 3703 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3704 3704 if (r != 0) {
3705 3705 switch (scf_error()) {
3706 3706 case SCF_ERROR_DELETED:
3707 3707 case SCF_ERROR_CONNECTION_BROKEN:
3708 3708 case SCF_ERROR_BACKEND_READONLY:
3709 3709 case SCF_ERROR_BACKEND_ACCESS:
3710 3710 case SCF_ERROR_NO_RESOURCES:
3711 3711 return (scferror2errno(scf_error()));
3712 3712
3713 3713 case SCF_ERROR_EXISTS:
3714 3714 warn(emsg_pg_added, ient->sc_fmri, dependents);
3715 3715 return (EBUSY);
3716 3716
3717 3717 case SCF_ERROR_PERMISSION_DENIED:
3718 3718 warn(emsg_pg_add_perm, dependents,
3719 3719 ient->sc_fmri);
3720 3720 return (scferror2errno(scf_error()));
3721 3721
3722 3722 case SCF_ERROR_NOT_BOUND:
3723 3723 case SCF_ERROR_HANDLE_MISMATCH:
3724 3724 case SCF_ERROR_INVALID_ARGUMENT:
3725 3725 case SCF_ERROR_NOT_SET:
3726 3726 default:
3727 3727 bad_error("scf_service_add_pg", scf_error());
3728 3728 }
3729 3729 }
3730 3730 }
3731 3731
3732 3732 cbdata.sc_trans = ud_tx;
3733 3733
3734 3734 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3735 3735 switch (scf_error()) {
3736 3736 case SCF_ERROR_CONNECTION_BROKEN:
3737 3737 case SCF_ERROR_BACKEND_ACCESS:
3738 3738 case SCF_ERROR_BACKEND_READONLY:
3739 3739 return (scferror2errno(scf_error()));
3740 3740
3741 3741 case SCF_ERROR_DELETED:
3742 3742 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3743 3743 return (EBUSY);
3744 3744
3745 3745 case SCF_ERROR_PERMISSION_DENIED:
3746 3746 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3747 3747 return (scferror2errno(scf_error()));
3748 3748
3749 3749 case SCF_ERROR_HANDLE_MISMATCH:
3750 3750 case SCF_ERROR_IN_USE:
3751 3751 case SCF_ERROR_NOT_BOUND:
3752 3752 case SCF_ERROR_NOT_SET:
3753 3753 default:
3754 3754 bad_error("scf_transaction_start", scf_error());
3755 3755 }
3756 3756 }
3757 3757 tx_started = 1;
3758 3758
3759 3759 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3760 3760 new_dpt_pgroup != NULL;
3761 3761 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3762 3762 new_dpt_pgroup)) {
3763 3763 if (new_dpt_pgroup->sc_pgroup_seen)
3764 3764 continue;
3765 3765
3766 3766 if (ud_run_dpts_pg_set) {
3767 3767 /*
3768 3768 * If the dependent is already there, then we have
3769 3769 * a conflict.
3770 3770 */
3771 3771 if (scf_pg_get_property(ud_run_dpts_pg,
3772 3772 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3773 3773 r = handle_dependent_conflict(ient, ud_prop,
3774 3774 new_dpt_pgroup);
3775 3775 switch (r) {
3776 3776 case 0:
3777 3777 continue;
3778 3778
3779 3779 case ECONNABORTED:
3780 3780 case ENOMEM:
3781 3781 case EBUSY:
3782 3782 case EBADF:
3783 3783 case EINVAL:
3784 3784 scf_transaction_destroy_children(ud_tx);
3785 3785 return (r);
3786 3786
3787 3787 default:
3788 3788 bad_error("handle_dependent_conflict",
3789 3789 r);
3790 3790 }
3791 3791 } else {
3792 3792 switch (scf_error()) {
3793 3793 case SCF_ERROR_NOT_FOUND:
3794 3794 break;
3795 3795
3796 3796 case SCF_ERROR_INVALID_ARGUMENT:
3797 3797 warn(emsg_fmri_invalid_pg_name,
3798 3798 ient->sc_fmri,
3799 3799 new_dpt_pgroup->sc_pgroup_name);
3800 3800 scf_transaction_destroy_children(ud_tx);
3801 3801 return (EINVAL);
3802 3802
3803 3803 case SCF_ERROR_DELETED:
3804 3804 warn(emsg_pg_deleted, ient->sc_fmri,
3805 3805 new_dpt_pgroup->sc_pgroup_name);
3806 3806 scf_transaction_destroy_children(ud_tx);
3807 3807 return (EBUSY);
3808 3808
3809 3809 case SCF_ERROR_CONNECTION_BROKEN:
3810 3810 scf_transaction_destroy_children(ud_tx);
3811 3811 return (ECONNABORTED);
3812 3812
3813 3813 case SCF_ERROR_NOT_BOUND:
3814 3814 case SCF_ERROR_HANDLE_MISMATCH:
3815 3815 case SCF_ERROR_NOT_SET:
3816 3816 default:
3817 3817 bad_error("scf_pg_get_property",
3818 3818 scf_error());
3819 3819 }
3820 3820 }
3821 3821 }
3822 3822
3823 3823 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3824 3824 if (r != UU_WALK_NEXT) {
3825 3825 if (r != UU_WALK_ERROR)
3826 3826 bad_error("lscf_dependent_import", r);
3827 3827
3828 3828 if (cbdata.sc_err == EALREADY) {
3829 3829 /* Collisions were handled preemptively. */
3830 3830 bad_error("lscf_dependent_import",
3831 3831 cbdata.sc_err);
3832 3832 }
3833 3833
3834 3834 scf_transaction_destroy_children(ud_tx);
3835 3835 return (cbdata.sc_err);
3836 3836 }
3837 3837 }
3838 3838
3839 3839 commit:
3840 3840 if (!tx_started)
3841 3841 return (0);
3842 3842
3843 3843 r = scf_transaction_commit(ud_tx);
3844 3844
3845 3845 scf_transaction_destroy_children(ud_tx);
3846 3846
3847 3847 switch (r) {
3848 3848 case 1:
3849 3849 return (0);
3850 3850
3851 3851 case 0:
3852 3852 warn(emsg_pg_changed, ient->sc_fmri, dependents);
3853 3853 return (EBUSY);
3854 3854
3855 3855 case -1:
3856 3856 break;
3857 3857
3858 3858 default:
3859 3859 bad_error("scf_transaction_commit", r);
3860 3860 }
3861 3861
3862 3862 switch (scf_error()) {
3863 3863 case SCF_ERROR_CONNECTION_BROKEN:
3864 3864 case SCF_ERROR_BACKEND_READONLY:
3865 3865 case SCF_ERROR_BACKEND_ACCESS:
3866 3866 case SCF_ERROR_NO_RESOURCES:
3867 3867 return (scferror2errno(scf_error()));
3868 3868
3869 3869 case SCF_ERROR_DELETED:
3870 3870 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3871 3871 return (EBUSY);
3872 3872
3873 3873 case SCF_ERROR_PERMISSION_DENIED:
3874 3874 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3875 3875 return (scferror2errno(scf_error()));
3876 3876
3877 3877 case SCF_ERROR_NOT_BOUND:
3878 3878 case SCF_ERROR_INVALID_ARGUMENT:
3879 3879 case SCF_ERROR_NOT_SET:
3880 3880 default:
3881 3881 bad_error("scf_transaction_destroy", scf_error());
3882 3882 /* NOTREACHED */
3883 3883 }
3884 3884 }
3885 3885
3886 3886 /*
3887 3887 * Used to add the manifests to the list of currently supported manifests.
3888 3888 * We can modify the existing manifest list removing entries if the files
3889 3889 * don't exist.
3890 3890 *
3891 3891 * Get the old list and the new file name
3892 3892 * If the new file name is in the list return
3893 3893 * If not then add the file to the list.
3894 3894 * As we process the list check to see if the files in the old list exist
3895 3895 * if not then remove the file from the list.
3896 3896 * Commit the list of manifest file names.
3897 3897 *
3898 3898 */
3899 3899 static int
3900 3900 upgrade_manifestfiles(pgroup_t *pg, entity_t *ient,
3901 3901 const scf_snaplevel_t *running, void *ent)
3902 3902 {
3903 3903 scf_propertygroup_t *ud_mfsts_pg = NULL;
3904 3904 scf_property_t *ud_prop = NULL;
3905 3905 scf_iter_t *ud_prop_iter;
3906 3906 scf_value_t *fname_value;
3907 3907 scf_callback_t cbdata;
3908 3908 pgroup_t *mfst_pgroup;
3909 3909 property_t *mfst_prop;
3910 3910 property_t *old_prop;
3911 3911 char *pname;
3912 3912 char *fval;
3913 3913 char *old_pname;
3914 3914 char *old_fval;
3915 3915 int no_upgrade_pg;
3916 3916 int mfst_seen;
3917 3917 int r;
3918 3918
3919 3919 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3920 3920
3921 3921 /*
3922 3922 * This should always be the service base on the code
3923 3923 * path, and the fact that the manifests pg is a service
3924 3924 * level property group only.
3925 3925 */
3926 3926 ud_mfsts_pg = scf_pg_create(g_hndl);
3927 3927 ud_prop = scf_property_create(g_hndl);
3928 3928 ud_prop_iter = scf_iter_create(g_hndl);
3929 3929 fname_value = scf_value_create(g_hndl);
3930 3930
3931 3931 /* Fetch the "manifests" property group */
3932 3932 no_upgrade_pg = 0;
3933 3933 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3934 3934 ud_mfsts_pg);
3935 3935 if (r != 0) {
3936 3936 switch (scf_error()) {
3937 3937 case SCF_ERROR_NOT_FOUND:
3938 3938 no_upgrade_pg = 1;
3939 3939 break;
3940 3940
3941 3941 case SCF_ERROR_DELETED:
3942 3942 case SCF_ERROR_CONNECTION_BROKEN:
3943 3943 return (scferror2errno(scf_error()));
3944 3944
3945 3945 case SCF_ERROR_NOT_SET:
3946 3946 case SCF_ERROR_INVALID_ARGUMENT:
3947 3947 case SCF_ERROR_HANDLE_MISMATCH:
3948 3948 case SCF_ERROR_NOT_BOUND:
3949 3949 default:
3950 3950 bad_error(running ? "scf_snaplevel_get_pg" :
3951 3951 "entity_get_pg", scf_error());
3952 3952 }
3953 3953 }
3954 3954
3955 3955 if (no_upgrade_pg) {
3956 3956 cbdata.sc_handle = g_hndl;
3957 3957 cbdata.sc_parent = ent;
3958 3958 cbdata.sc_service = issvc;
3959 3959 cbdata.sc_flags = SCI_FORCE;
3960 3960 cbdata.sc_source_fmri = ient->sc_fmri;
3961 3961 cbdata.sc_target_fmri = ient->sc_fmri;
3962 3962
3963 3963 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3964 3964 return (cbdata.sc_err);
3965 3965
3966 3966 return (0);
3967 3967 }
3968 3968
3969 3969 /* Fetch the new manifests property group */
3970 3970 mfst_pgroup = internal_pgroup_find_or_create(ient,
3971 3971 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
3972 3972 assert(mfst_pgroup != NULL);
3973 3973
3974 3974 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3975 3975 SCF_SUCCESS)
3976 3976 return (-1);
3977 3977
3978 3978 if ((pname = malloc(MAXPATHLEN)) == NULL)
3979 3979 return (ENOMEM);
3980 3980 if ((fval = malloc(MAXPATHLEN)) == NULL) {
3981 3981 free(pname);
3982 3982 return (ENOMEM);
3983 3983 }
3984 3984
3985 3985 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3986 3986 mfst_seen = 0;
3987 3987 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3988 3988 continue;
3989 3989
3990 3990 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3991 3991 mfst_prop != NULL;
3992 3992 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3993 3993 mfst_prop)) {
3994 3994 if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3995 3995 mfst_seen = 1;
3996 3996 }
3997 3997 }
3998 3998
3999 3999 /*
4000 4000 * If the manifest is not seen then add it to the new mfst
4001 4001 * property list to get proccessed into the repo.
4002 4002 */
4003 4003 if (mfst_seen == 0) {
4004 4004 /*
4005 4005 * If we cannot get the value then there is no
4006 4006 * reason to attempt to attach the value to
4007 4007 * the property group
4008 4008 */
4009 4009 if (prop_get_val(ud_prop, fname_value) == 0 &&
4010 4010 scf_value_get_astring(fname_value, fval,
4011 4011 MAXPATHLEN) != -1) {
4012 4012 old_pname = safe_strdup(pname);
4013 4013 old_fval = safe_strdup(fval);
4014 4014 old_prop = internal_property_create(old_pname,
4015 4015 SCF_TYPE_ASTRING, 1, old_fval);
4016 4016
4017 4017 /*
4018 4018 * Already checked to see if the property exists
4019 4019 * in the group, and it does not.
4020 4020 */
4021 4021 (void) internal_attach_property(mfst_pgroup,
4022 4022 old_prop);
4023 4023 }
4024 4024 }
4025 4025 }
4026 4026 free(pname);
4027 4027 free(fval);
4028 4028
4029 4029 cbdata.sc_handle = g_hndl;
4030 4030 cbdata.sc_parent = ent;
4031 4031 cbdata.sc_service = issvc;
4032 4032 cbdata.sc_flags = SCI_FORCE;
4033 4033 cbdata.sc_source_fmri = ient->sc_fmri;
4034 4034 cbdata.sc_target_fmri = ient->sc_fmri;
4035 4035
4036 4036 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4037 4037 return (cbdata.sc_err);
4038 4038
4039 4039 return (r);
4040 4040 }
4041 4041
4042 4042 /*
4043 4043 * prop is taken to be a property in the "dependents" property group of snpl,
4044 4044 * which is taken to be the snaplevel of a last-import snapshot corresponding
4045 4045 * to ient. If prop is a valid dependents property, upgrade the dependent it
4046 4046 * represents according to the repository & ient. If ud_run_dpts_pg_set is
4047 4047 * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4048 4048 * of the entity ient represents (possibly in the running snapshot). If it
4049 4049 * needs to be changed, an entry will be added to tx, if not NULL.
4050 4050 *
4051 4051 * Returns
4052 4052 * 0 - success
4053 4053 * ECONNABORTED - repository connection broken
4054 4054 * ENOMEM - out of memory
4055 4055 * ENOSPC - configd was out of resources
4056 4056 * ECANCELED - snpl's entity was deleted
4057 4057 * EINVAL - dependent target is invalid (error printed)
4058 4058 * - dependent is invalid (error printed)
4059 4059 * EBADF - snpl is corrupt (error printed)
4060 4060 * - snpl has corrupt pg (error printed)
4061 4061 * - dependency pg in target is corrupt (error printed)
4062 4062 * - running snapshot in dependent is missing snaplevel (error printed)
4063 4063 * EPERM - couldn't delete dependency pg (permission denied) (error printed)
4064 4064 * - couldn't create dependent (permission denied) (error printed)
4065 4065 * - couldn't modify dependent pg (permission denied) (error printed)
4066 4066 * EROFS - couldn't delete dependency pg (repository read-only)
4067 4067 * - couldn't create dependent (repository read-only)
4068 4068 * EACCES - couldn't delete dependency pg (backend access denied)
4069 4069 * - couldn't create dependent (backend access denied)
4070 4070 * EBUSY - ud_run_dpts_pg was deleted (error printed)
4071 4071 * - tx's pg was deleted (error printed)
4072 4072 * - dependent pg was changed or deleted (error printed)
4073 4073 * EEXIST - dependency pg already exists in new target (error printed)
4074 4074 */
4075 4075 static int
4076 4076 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4077 4077 const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4078 4078 {
4079 4079 pgroup_t pgrp;
4080 4080 scf_type_t ty;
4081 4081 pgroup_t *new_dpt_pgroup;
4082 4082 pgroup_t *old_dpt_pgroup = NULL;
4083 4083 pgroup_t *current_pg;
4084 4084 pgroup_t *dpt;
4085 4085 scf_callback_t cbdata;
4086 4086 int tissvc;
4087 4087 void *target_ent;
4088 4088 scf_error_t serr;
4089 4089 int r;
4090 4090 scf_transaction_entry_t *ent;
4091 4091
4092 4092 const char * const cf_inval = gettext("Conflict upgrading %s "
4093 4093 "(dependent \"%s\" has invalid dependents property).\n");
4094 4094 const char * const cf_missing = gettext("Conflict upgrading %s "
4095 4095 "(dependent \"%s\" is missing).\n");
4096 4096 const char * const cf_newdpg = gettext("Conflict upgrading %s "
4097 4097 "(dependent \"%s\" has new dependency property group).\n");
4098 4098 const char * const cf_newtarg = gettext("Conflict upgrading %s "
4099 4099 "(dependent \"%s\" has new target).\n");
4100 4100 const char * const li_corrupt =
4101 4101 gettext("%s: \"last-import\" snapshot is corrupt.\n");
4102 4102 const char * const upgrading =
4103 4103 gettext("%s: Upgrading dependent \"%s\".\n");
4104 4104 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4105 4105 "corrupt (missing snaplevel).\n");
4106 4106
4107 4107 if (scf_property_type(prop, &ty) != 0) {
4108 4108 switch (scf_error()) {
4109 4109 case SCF_ERROR_DELETED:
4110 4110 case SCF_ERROR_CONNECTION_BROKEN:
4111 4111 return (scferror2errno(scf_error()));
4112 4112
4113 4113 case SCF_ERROR_NOT_BOUND:
4114 4114 case SCF_ERROR_NOT_SET:
4115 4115 default:
4116 4116 bad_error("scf_property_type", scf_error());
4117 4117 }
4118 4118 }
4119 4119
4120 4120 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4121 4121 warn(li_corrupt, ient->sc_fmri);
4122 4122 return (EBADF);
4123 4123 }
4124 4124
4125 4125 /*
4126 4126 * prop represents a dependent in the old manifest. It is named after
4127 4127 * the dependent.
4128 4128 */
4129 4129 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4130 4130 switch (scf_error()) {
4131 4131 case SCF_ERROR_DELETED:
4132 4132 case SCF_ERROR_CONNECTION_BROKEN:
4133 4133 return (scferror2errno(scf_error()));
4134 4134
4135 4135 case SCF_ERROR_NOT_BOUND:
4136 4136 case SCF_ERROR_NOT_SET:
4137 4137 default:
4138 4138 bad_error("scf_property_get_name", scf_error());
4139 4139 }
4140 4140 }
4141 4141
4142 4142 /* See if it's in the new manifest. */
4143 4143 pgrp.sc_pgroup_name = ud_name;
4144 4144 new_dpt_pgroup =
4145 4145 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4146 4146
4147 4147 /* If it's not, delete it... if it hasn't been customized. */
4148 4148 if (new_dpt_pgroup == NULL) {
4149 4149 if (!ud_run_dpts_pg_set)
4150 4150 return (0);
4151 4151
4152 4152 if (scf_property_get_value(prop, ud_val) != 0) {
4153 4153 switch (scf_error()) {
4154 4154 case SCF_ERROR_NOT_FOUND:
4155 4155 case SCF_ERROR_CONSTRAINT_VIOLATED:
4156 4156 warn(li_corrupt, ient->sc_fmri);
4157 4157 return (EBADF);
4158 4158
4159 4159 case SCF_ERROR_DELETED:
4160 4160 case SCF_ERROR_CONNECTION_BROKEN:
4161 4161 return (scferror2errno(scf_error()));
4162 4162
4163 4163 case SCF_ERROR_HANDLE_MISMATCH:
4164 4164 case SCF_ERROR_NOT_BOUND:
4165 4165 case SCF_ERROR_NOT_SET:
4166 4166 case SCF_ERROR_PERMISSION_DENIED:
4167 4167 default:
4168 4168 bad_error("scf_property_get_value",
4169 4169 scf_error());
4170 4170 }
4171 4171 }
4172 4172
4173 4173 if (scf_value_get_as_string(ud_val, ud_oldtarg,
4174 4174 max_scf_value_len + 1) < 0)
4175 4175 bad_error("scf_value_get_as_string", scf_error());
4176 4176
4177 4177 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4178 4178 0) {
4179 4179 switch (scf_error()) {
4180 4180 case SCF_ERROR_NOT_FOUND:
4181 4181 return (0);
4182 4182
4183 4183 case SCF_ERROR_CONNECTION_BROKEN:
4184 4184 return (scferror2errno(scf_error()));
4185 4185
4186 4186 case SCF_ERROR_DELETED:
4187 4187 warn(emsg_pg_deleted, ient->sc_fmri,
4188 4188 "dependents");
4189 4189 return (EBUSY);
4190 4190
4191 4191 case SCF_ERROR_INVALID_ARGUMENT:
4192 4192 case SCF_ERROR_NOT_BOUND:
4193 4193 case SCF_ERROR_HANDLE_MISMATCH:
4194 4194 case SCF_ERROR_NOT_SET:
4195 4195 default:
4196 4196 bad_error("scf_pg_get_property", scf_error());
4197 4197 }
4198 4198 }
4199 4199 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4200 4200 switch (scf_error()) {
4201 4201 case SCF_ERROR_NOT_FOUND:
4202 4202 case SCF_ERROR_CONSTRAINT_VIOLATED:
4203 4203 warn(cf_inval, ient->sc_fmri, ud_name);
4204 4204 return (0);
4205 4205
4206 4206 case SCF_ERROR_DELETED:
4207 4207 case SCF_ERROR_CONNECTION_BROKEN:
4208 4208 return (scferror2errno(scf_error()));
4209 4209
4210 4210 case SCF_ERROR_HANDLE_MISMATCH:
4211 4211 case SCF_ERROR_NOT_BOUND:
4212 4212 case SCF_ERROR_NOT_SET:
4213 4213 case SCF_ERROR_PERMISSION_DENIED:
4214 4214 default:
4215 4215 bad_error("scf_property_get_value",
4216 4216 scf_error());
4217 4217 }
4218 4218 }
4219 4219
4220 4220 ty = scf_value_type(ud_val);
4221 4221 assert(ty != SCF_TYPE_INVALID);
4222 4222 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4223 4223 warn(cf_inval, ient->sc_fmri, ud_name);
4224 4224 return (0);
4225 4225 }
4226 4226
4227 4227 if (scf_value_get_as_string(ud_val, ud_ctarg,
4228 4228 max_scf_value_len + 1) < 0)
4229 4229 bad_error("scf_value_get_as_string", scf_error());
4230 4230
4231 4231 r = fmri_equal(ud_ctarg, ud_oldtarg);
4232 4232 switch (r) {
4233 4233 case 1:
4234 4234 break;
4235 4235
4236 4236 case 0:
4237 4237 case -1: /* warn? */
4238 4238 warn(cf_newtarg, ient->sc_fmri, ud_name);
4239 4239 return (0);
4240 4240
4241 4241 case -2:
4242 4242 warn(li_corrupt, ient->sc_fmri);
4243 4243 return (EBADF);
4244 4244
4245 4245 default:
4246 4246 bad_error("fmri_equal", r);
4247 4247 }
4248 4248
4249 4249 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4250 4250 switch (scf_error()) {
4251 4251 case SCF_ERROR_NOT_FOUND:
4252 4252 warn(li_corrupt, ient->sc_fmri);
4253 4253 return (EBADF);
4254 4254
4255 4255 case SCF_ERROR_DELETED:
4256 4256 case SCF_ERROR_CONNECTION_BROKEN:
4257 4257 return (scferror2errno(scf_error()));
4258 4258
4259 4259 case SCF_ERROR_NOT_BOUND:
4260 4260 case SCF_ERROR_HANDLE_MISMATCH:
4261 4261 case SCF_ERROR_INVALID_ARGUMENT:
4262 4262 case SCF_ERROR_NOT_SET:
4263 4263 default:
4264 4264 bad_error("scf_snaplevel_get_pg", scf_error());
4265 4265 }
4266 4266 }
4267 4267
4268 4268 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4269 4269 snap_lastimport);
4270 4270 switch (r) {
4271 4271 case 0:
4272 4272 break;
4273 4273
4274 4274 case ECANCELED:
4275 4275 case ECONNABORTED:
4276 4276 case ENOMEM:
4277 4277 case EBADF:
4278 4278 return (r);
4279 4279
4280 4280 case EACCES:
4281 4281 default:
4282 4282 bad_error("load_pg", r);
4283 4283 }
4284 4284
4285 4285 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4286 4286 switch (serr) {
4287 4287 case SCF_ERROR_NONE:
4288 4288 break;
4289 4289
4290 4290 case SCF_ERROR_NO_MEMORY:
4291 4291 internal_pgroup_free(old_dpt_pgroup);
4292 4292 return (ENOMEM);
4293 4293
4294 4294 case SCF_ERROR_NOT_FOUND:
4295 4295 internal_pgroup_free(old_dpt_pgroup);
4296 4296 goto delprop;
4297 4297
4298 4298 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */
4299 4299 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
4300 4300 default:
4301 4301 bad_error("fmri_to_entity", serr);
4302 4302 }
4303 4303
4304 4304 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4305 4305 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4306 4306 switch (r) {
4307 4307 case 0:
4308 4308 break;
4309 4309
4310 4310 case ECONNABORTED:
4311 4311 internal_pgroup_free(old_dpt_pgroup);
4312 4312 return (r);
4313 4313
4314 4314 case ECANCELED:
4315 4315 case ENOENT:
4316 4316 internal_pgroup_free(old_dpt_pgroup);
4317 4317 goto delprop;
4318 4318
4319 4319 case EBADF:
4320 4320 warn(r_no_lvl, ud_ctarg);
4321 4321 internal_pgroup_free(old_dpt_pgroup);
4322 4322 return (r);
4323 4323
4324 4324 case EINVAL:
4325 4325 default:
4326 4326 bad_error("entity_get_running_pg", r);
4327 4327 }
4328 4328
4329 4329 /* load it */
4330 4330 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4331 4331 switch (r) {
4332 4332 case 0:
4333 4333 break;
4334 4334
4335 4335 case ECANCELED:
4336 4336 internal_pgroup_free(old_dpt_pgroup);
4337 4337 goto delprop;
4338 4338
4339 4339 case ECONNABORTED:
4340 4340 case ENOMEM:
4341 4341 case EBADF:
4342 4342 internal_pgroup_free(old_dpt_pgroup);
4343 4343 return (r);
4344 4344
4345 4345 case EACCES:
4346 4346 default:
4347 4347 bad_error("load_pg", r);
4348 4348 }
4349 4349
4350 4350 /* compare property groups */
4351 4351 if (!pg_equal(old_dpt_pgroup, current_pg)) {
4352 4352 warn(cf_newdpg, ient->sc_fmri, ud_name);
4353 4353 internal_pgroup_free(old_dpt_pgroup);
4354 4354 internal_pgroup_free(current_pg);
4355 4355 return (0);
4356 4356 }
4357 4357
4358 4358 internal_pgroup_free(old_dpt_pgroup);
4359 4359 internal_pgroup_free(current_pg);
4360 4360
4361 4361 if (g_verbose)
4362 4362 warn(gettext("%s: Deleting dependent \"%s\".\n"),
4363 4363 ient->sc_fmri, ud_name);
4364 4364
4365 4365 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4366 4366 switch (scf_error()) {
4367 4367 case SCF_ERROR_NOT_FOUND:
4368 4368 case SCF_ERROR_DELETED:
4369 4369 internal_pgroup_free(old_dpt_pgroup);
4370 4370 goto delprop;
4371 4371
4372 4372 case SCF_ERROR_CONNECTION_BROKEN:
4373 4373 internal_pgroup_free(old_dpt_pgroup);
4374 4374 return (ECONNABORTED);
4375 4375
4376 4376 case SCF_ERROR_NOT_SET:
4377 4377 case SCF_ERROR_INVALID_ARGUMENT:
4378 4378 case SCF_ERROR_HANDLE_MISMATCH:
4379 4379 case SCF_ERROR_NOT_BOUND:
4380 4380 default:
4381 4381 bad_error("entity_get_pg", scf_error());
4382 4382 }
4383 4383 }
4384 4384
4385 4385 if (scf_pg_delete(ud_pg) != 0) {
4386 4386 switch (scf_error()) {
4387 4387 case SCF_ERROR_DELETED:
4388 4388 break;
4389 4389
4390 4390 case SCF_ERROR_CONNECTION_BROKEN:
4391 4391 case SCF_ERROR_BACKEND_READONLY:
4392 4392 case SCF_ERROR_BACKEND_ACCESS:
4393 4393 return (scferror2errno(scf_error()));
4394 4394
4395 4395 case SCF_ERROR_PERMISSION_DENIED:
4396 4396 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4397 4397 return (scferror2errno(scf_error()));
4398 4398
4399 4399 case SCF_ERROR_NOT_SET:
4400 4400 default:
4401 4401 bad_error("scf_pg_delete", scf_error());
4402 4402 }
4403 4403 }
4404 4404
4405 4405 /*
4406 4406 * This service was changed, so it must be refreshed. But
4407 4407 * since it's not mentioned in the new manifest, we have to
4408 4408 * record its FMRI here for use later. We record the name
4409 4409 * & the entity (via sc_parent) in case we need to print error
4410 4410 * messages during the refresh.
4411 4411 */
4412 4412 dpt = internal_pgroup_new();
4413 4413 if (dpt == NULL)
4414 4414 return (ENOMEM);
4415 4415 dpt->sc_pgroup_name = strdup(ud_name);
4416 4416 dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4417 4417 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4418 4418 return (ENOMEM);
4419 4419 dpt->sc_parent = (entity_t *)ient;
4420 4420 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4421 4421 uu_die(gettext("libuutil error: %s\n"),
4422 4422 uu_strerror(uu_error()));
4423 4423
4424 4424 delprop:
4425 4425 if (tx == NULL)
4426 4426 return (0);
4427 4427
4428 4428 ent = scf_entry_create(g_hndl);
4429 4429 if (ent == NULL)
4430 4430 return (ENOMEM);
4431 4431
4432 4432 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4433 4433 scf_entry_destroy(ent);
4434 4434 switch (scf_error()) {
4435 4435 case SCF_ERROR_DELETED:
4436 4436 warn(emsg_pg_deleted, ient->sc_fmri,
4437 4437 "dependents");
4438 4438 return (EBUSY);
4439 4439
4440 4440 case SCF_ERROR_CONNECTION_BROKEN:
4441 4441 return (scferror2errno(scf_error()));
4442 4442
4443 4443 case SCF_ERROR_NOT_FOUND:
4444 4444 break;
4445 4445
4446 4446 case SCF_ERROR_HANDLE_MISMATCH:
4447 4447 case SCF_ERROR_NOT_BOUND:
4448 4448 case SCF_ERROR_INVALID_ARGUMENT:
4449 4449 case SCF_ERROR_NOT_SET:
4450 4450 default:
4451 4451 bad_error("scf_transaction_property_delete",
4452 4452 scf_error());
4453 4453 }
4454 4454 }
4455 4455
4456 4456 return (0);
4457 4457 }
4458 4458
4459 4459 new_dpt_pgroup->sc_pgroup_seen = 1;
4460 4460
4461 4461 /*
4462 4462 * Decide whether the dependent has changed in the manifest.
4463 4463 */
4464 4464 /* Compare the target. */
4465 4465 if (scf_property_get_value(prop, ud_val) != 0) {
4466 4466 switch (scf_error()) {
4467 4467 case SCF_ERROR_NOT_FOUND:
4468 4468 case SCF_ERROR_CONSTRAINT_VIOLATED:
4469 4469 warn(li_corrupt, ient->sc_fmri);
4470 4470 return (EBADF);
4471 4471
4472 4472 case SCF_ERROR_DELETED:
4473 4473 case SCF_ERROR_CONNECTION_BROKEN:
4474 4474 return (scferror2errno(scf_error()));
4475 4475
4476 4476 case SCF_ERROR_HANDLE_MISMATCH:
4477 4477 case SCF_ERROR_NOT_BOUND:
4478 4478 case SCF_ERROR_NOT_SET:
4479 4479 case SCF_ERROR_PERMISSION_DENIED:
4480 4480 default:
4481 4481 bad_error("scf_property_get_value", scf_error());
4482 4482 }
4483 4483 }
4484 4484
4485 4485 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4486 4486 0)
4487 4487 bad_error("scf_value_get_as_string", scf_error());
4488 4488
4489 4489 /*
4490 4490 * If the fmri's are not equal then the old fmri will need to
4491 4491 * be refreshed to ensure that the changes are properly updated
4492 4492 * in that service.
4493 4493 */
4494 4494 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4495 4495 switch (r) {
4496 4496 case 0:
4497 4497 dpt = internal_pgroup_new();
4498 4498 if (dpt == NULL)
4499 4499 return (ENOMEM);
4500 4500 dpt->sc_pgroup_name = strdup(ud_name);
4501 4501 dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4502 4502 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4503 4503 return (ENOMEM);
4504 4504 dpt->sc_parent = (entity_t *)ient;
4505 4505 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4506 4506 uu_die(gettext("libuutil error: %s\n"),
4507 4507 uu_strerror(uu_error()));
4508 4508 break;
4509 4509
4510 4510 case 1:
4511 4511 /* Compare the dependency pgs. */
4512 4512 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4513 4513 switch (scf_error()) {
4514 4514 case SCF_ERROR_NOT_FOUND:
4515 4515 warn(li_corrupt, ient->sc_fmri);
4516 4516 return (EBADF);
4517 4517
4518 4518 case SCF_ERROR_DELETED:
4519 4519 case SCF_ERROR_CONNECTION_BROKEN:
4520 4520 return (scferror2errno(scf_error()));
4521 4521
4522 4522 case SCF_ERROR_NOT_BOUND:
4523 4523 case SCF_ERROR_HANDLE_MISMATCH:
4524 4524 case SCF_ERROR_INVALID_ARGUMENT:
4525 4525 case SCF_ERROR_NOT_SET:
4526 4526 default:
4527 4527 bad_error("scf_snaplevel_get_pg", scf_error());
4528 4528 }
4529 4529 }
4530 4530
4531 4531 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4532 4532 snap_lastimport);
4533 4533 switch (r) {
4534 4534 case 0:
4535 4535 break;
4536 4536
4537 4537 case ECANCELED:
4538 4538 case ECONNABORTED:
4539 4539 case ENOMEM:
4540 4540 case EBADF:
4541 4541 return (r);
4542 4542
4543 4543 case EACCES:
4544 4544 default:
4545 4545 bad_error("load_pg", r);
4546 4546 }
4547 4547
4548 4548 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4549 4549 /* no change, leave customizations */
4550 4550 internal_pgroup_free(old_dpt_pgroup);
4551 4551 return (0);
4552 4552 }
4553 4553 break;
4554 4554
4555 4555 case -1:
4556 4556 warn(li_corrupt, ient->sc_fmri);
4557 4557 return (EBADF);
4558 4558
4559 4559 case -2:
4560 4560 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4561 4561 ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4562 4562 return (EINVAL);
4563 4563
4564 4564 default:
4565 4565 bad_error("fmri_equal", r);
4566 4566 }
4567 4567
4568 4568 /*
4569 4569 * The dependent has changed in the manifest. Upgrade the current
4570 4570 * properties if they haven't been customized.
4571 4571 */
4572 4572
4573 4573 /*
4574 4574 * If new_dpt_pgroup->sc_override, then act as though the property
4575 4575 * group hasn't been customized.
4576 4576 */
4577 4577 if (new_dpt_pgroup->sc_pgroup_override) {
4578 4578 (void) strcpy(ud_ctarg, ud_oldtarg);
4579 4579 goto nocust;
4580 4580 }
4581 4581
4582 4582 if (!ud_run_dpts_pg_set) {
4583 4583 warn(cf_missing, ient->sc_fmri, ud_name);
4584 4584 r = 0;
4585 4585 goto out;
4586 4586 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4587 4587 switch (scf_error()) {
4588 4588 case SCF_ERROR_NOT_FOUND:
4589 4589 warn(cf_missing, ient->sc_fmri, ud_name);
4590 4590 r = 0;
4591 4591 goto out;
4592 4592
4593 4593 case SCF_ERROR_CONNECTION_BROKEN:
4594 4594 r = scferror2errno(scf_error());
4595 4595 goto out;
4596 4596
4597 4597 case SCF_ERROR_DELETED:
4598 4598 warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4599 4599 r = EBUSY;
4600 4600 goto out;
4601 4601
4602 4602 case SCF_ERROR_INVALID_ARGUMENT:
4603 4603 case SCF_ERROR_NOT_BOUND:
4604 4604 case SCF_ERROR_HANDLE_MISMATCH:
4605 4605 case SCF_ERROR_NOT_SET:
4606 4606 default:
4607 4607 bad_error("scf_pg_get_property", scf_error());
4608 4608 }
4609 4609 }
4610 4610
4611 4611 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4612 4612 switch (scf_error()) {
4613 4613 case SCF_ERROR_NOT_FOUND:
4614 4614 case SCF_ERROR_CONSTRAINT_VIOLATED:
4615 4615 warn(cf_inval, ient->sc_fmri, ud_name);
4616 4616 r = 0;
4617 4617 goto out;
4618 4618
4619 4619 case SCF_ERROR_DELETED:
4620 4620 case SCF_ERROR_CONNECTION_BROKEN:
4621 4621 r = scferror2errno(scf_error());
4622 4622 goto out;
4623 4623
4624 4624 case SCF_ERROR_HANDLE_MISMATCH:
4625 4625 case SCF_ERROR_NOT_BOUND:
4626 4626 case SCF_ERROR_NOT_SET:
4627 4627 case SCF_ERROR_PERMISSION_DENIED:
4628 4628 default:
4629 4629 bad_error("scf_property_get_value", scf_error());
4630 4630 }
4631 4631 }
4632 4632
4633 4633 ty = scf_value_type(ud_val);
4634 4634 assert(ty != SCF_TYPE_INVALID);
4635 4635 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4636 4636 warn(cf_inval, ient->sc_fmri, ud_name);
4637 4637 r = 0;
4638 4638 goto out;
4639 4639 }
4640 4640 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4641 4641 0)
4642 4642 bad_error("scf_value_get_as_string", scf_error());
4643 4643
4644 4644 r = fmri_equal(ud_ctarg, ud_oldtarg);
4645 4645 if (r == -1) {
4646 4646 warn(cf_inval, ient->sc_fmri, ud_name);
4647 4647 r = 0;
4648 4648 goto out;
4649 4649 } else if (r == -2) {
4650 4650 warn(li_corrupt, ient->sc_fmri);
4651 4651 r = EBADF;
4652 4652 goto out;
4653 4653 } else if (r == 0) {
4654 4654 /*
4655 4655 * Target has been changed. Only abort now if it's been
4656 4656 * changed to something other than what's in the manifest.
4657 4657 */
4658 4658 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4659 4659 if (r == -1) {
4660 4660 warn(cf_inval, ient->sc_fmri, ud_name);
4661 4661 r = 0;
4662 4662 goto out;
4663 4663 } else if (r == 0) {
4664 4664 warn(cf_newtarg, ient->sc_fmri, ud_name);
4665 4665 r = 0;
4666 4666 goto out;
4667 4667 } else if (r != 1) {
4668 4668 /* invalid sc_pgroup_fmri caught above */
4669 4669 bad_error("fmri_equal", r);
4670 4670 }
4671 4671
4672 4672 /*
4673 4673 * Fetch the current dependency pg. If it's what the manifest
4674 4674 * says, then no problem.
4675 4675 */
4676 4676 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4677 4677 switch (serr) {
4678 4678 case SCF_ERROR_NONE:
4679 4679 break;
4680 4680
4681 4681 case SCF_ERROR_NOT_FOUND:
4682 4682 warn(cf_missing, ient->sc_fmri, ud_name);
4683 4683 r = 0;
4684 4684 goto out;
4685 4685
4686 4686 case SCF_ERROR_NO_MEMORY:
4687 4687 r = ENOMEM;
4688 4688 goto out;
4689 4689
4690 4690 case SCF_ERROR_CONSTRAINT_VIOLATED:
4691 4691 case SCF_ERROR_INVALID_ARGUMENT:
4692 4692 default:
4693 4693 bad_error("fmri_to_entity", serr);
4694 4694 }
4695 4695
4696 4696 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4697 4697 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4698 4698 switch (r) {
4699 4699 case 0:
4700 4700 break;
4701 4701
4702 4702 case ECONNABORTED:
4703 4703 goto out;
4704 4704
4705 4705 case ECANCELED:
4706 4706 case ENOENT:
4707 4707 warn(cf_missing, ient->sc_fmri, ud_name);
4708 4708 r = 0;
4709 4709 goto out;
4710 4710
4711 4711 case EBADF:
4712 4712 warn(r_no_lvl, ud_ctarg);
4713 4713 goto out;
4714 4714
4715 4715 case EINVAL:
4716 4716 default:
4717 4717 bad_error("entity_get_running_pg", r);
4718 4718 }
4719 4719
4720 4720 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4721 4721 switch (r) {
4722 4722 case 0:
4723 4723 break;
4724 4724
4725 4725 case ECANCELED:
4726 4726 warn(cf_missing, ient->sc_fmri, ud_name);
4727 4727 r = 0;
4728 4728 goto out;
4729 4729
4730 4730 case ECONNABORTED:
4731 4731 case ENOMEM:
4732 4732 case EBADF:
4733 4733 goto out;
4734 4734
4735 4735 case EACCES:
4736 4736 default:
4737 4737 bad_error("load_pg", r);
4738 4738 }
4739 4739
4740 4740 if (!pg_equal(current_pg, new_dpt_pgroup))
4741 4741 warn(cf_newdpg, ient->sc_fmri, ud_name);
4742 4742 internal_pgroup_free(current_pg);
4743 4743 r = 0;
4744 4744 goto out;
4745 4745 } else if (r != 1) {
4746 4746 bad_error("fmri_equal", r);
4747 4747 }
4748 4748
4749 4749 nocust:
4750 4750 /*
4751 4751 * Target has not been customized. Check the dependency property
4752 4752 * group.
4753 4753 */
4754 4754
4755 4755 if (old_dpt_pgroup == NULL) {
4756 4756 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4757 4757 ud_pg) != 0) {
4758 4758 switch (scf_error()) {
4759 4759 case SCF_ERROR_NOT_FOUND:
4760 4760 warn(li_corrupt, ient->sc_fmri);
4761 4761 return (EBADF);
4762 4762
4763 4763 case SCF_ERROR_DELETED:
4764 4764 case SCF_ERROR_CONNECTION_BROKEN:
4765 4765 return (scferror2errno(scf_error()));
4766 4766
4767 4767 case SCF_ERROR_NOT_BOUND:
4768 4768 case SCF_ERROR_HANDLE_MISMATCH:
4769 4769 case SCF_ERROR_INVALID_ARGUMENT:
4770 4770 case SCF_ERROR_NOT_SET:
4771 4771 default:
4772 4772 bad_error("scf_snaplevel_get_pg", scf_error());
4773 4773 }
4774 4774 }
4775 4775
4776 4776 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4777 4777 snap_lastimport);
4778 4778 switch (r) {
4779 4779 case 0:
4780 4780 break;
4781 4781
4782 4782 case ECANCELED:
4783 4783 case ECONNABORTED:
4784 4784 case ENOMEM:
4785 4785 case EBADF:
4786 4786 return (r);
4787 4787
4788 4788 case EACCES:
4789 4789 default:
4790 4790 bad_error("load_pg", r);
4791 4791 }
4792 4792 }
4793 4793 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4794 4794 switch (serr) {
4795 4795 case SCF_ERROR_NONE:
4796 4796 break;
4797 4797
4798 4798 case SCF_ERROR_NOT_FOUND:
4799 4799 warn(cf_missing, ient->sc_fmri, ud_name);
4800 4800 r = 0;
4801 4801 goto out;
4802 4802
4803 4803 case SCF_ERROR_NO_MEMORY:
4804 4804 r = ENOMEM;
4805 4805 goto out;
4806 4806
4807 4807 case SCF_ERROR_CONSTRAINT_VIOLATED:
4808 4808 case SCF_ERROR_INVALID_ARGUMENT:
4809 4809 default:
4810 4810 bad_error("fmri_to_entity", serr);
4811 4811 }
4812 4812
4813 4813 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4814 4814 ud_iter2, ud_inst, imp_snap, ud_snpl);
4815 4815 switch (r) {
4816 4816 case 0:
4817 4817 break;
4818 4818
4819 4819 case ECONNABORTED:
4820 4820 goto out;
4821 4821
4822 4822 case ECANCELED:
4823 4823 case ENOENT:
4824 4824 warn(cf_missing, ient->sc_fmri, ud_name);
4825 4825 r = 0;
4826 4826 goto out;
4827 4827
4828 4828 case EBADF:
4829 4829 warn(r_no_lvl, ud_ctarg);
4830 4830 goto out;
4831 4831
4832 4832 case EINVAL:
4833 4833 default:
4834 4834 bad_error("entity_get_running_pg", r);
4835 4835 }
4836 4836
4837 4837 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4838 4838 switch (r) {
4839 4839 case 0:
4840 4840 break;
4841 4841
4842 4842 case ECANCELED:
4843 4843 warn(cf_missing, ient->sc_fmri, ud_name);
4844 4844 goto out;
4845 4845
4846 4846 case ECONNABORTED:
4847 4847 case ENOMEM:
4848 4848 case EBADF:
4849 4849 goto out;
4850 4850
4851 4851 case EACCES:
4852 4852 default:
4853 4853 bad_error("load_pg", r);
4854 4854 }
4855 4855
4856 4856 if (!pg_equal(current_pg, old_dpt_pgroup)) {
4857 4857 if (!pg_equal(current_pg, new_dpt_pgroup))
4858 4858 warn(cf_newdpg, ient->sc_fmri, ud_name);
4859 4859 internal_pgroup_free(current_pg);
4860 4860 r = 0;
4861 4861 goto out;
4862 4862 }
4863 4863
4864 4864 /* Uncustomized. Upgrade. */
4865 4865
4866 4866 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4867 4867 switch (r) {
4868 4868 case 1:
4869 4869 if (pg_equal(current_pg, new_dpt_pgroup)) {
4870 4870 /* Already upgraded. */
4871 4871 internal_pgroup_free(current_pg);
4872 4872 r = 0;
4873 4873 goto out;
4874 4874 }
4875 4875
4876 4876 internal_pgroup_free(current_pg);
4877 4877
4878 4878 /* upgrade current_pg */
4879 4879 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4880 4880 switch (scf_error()) {
4881 4881 case SCF_ERROR_CONNECTION_BROKEN:
4882 4882 r = scferror2errno(scf_error());
4883 4883 goto out;
4884 4884
4885 4885 case SCF_ERROR_DELETED:
4886 4886 warn(cf_missing, ient->sc_fmri, ud_name);
4887 4887 r = 0;
4888 4888 goto out;
4889 4889
4890 4890 case SCF_ERROR_NOT_FOUND:
4891 4891 break;
4892 4892
4893 4893 case SCF_ERROR_INVALID_ARGUMENT:
4894 4894 case SCF_ERROR_NOT_BOUND:
4895 4895 case SCF_ERROR_NOT_SET:
4896 4896 case SCF_ERROR_HANDLE_MISMATCH:
4897 4897 default:
4898 4898 bad_error("entity_get_pg", scf_error());
4899 4899 }
4900 4900
4901 4901 if (tissvc)
4902 4902 r = scf_service_add_pg(target_ent, ud_name,
4903 4903 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4904 4904 else
4905 4905 r = scf_instance_add_pg(target_ent, ud_name,
4906 4906 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4907 4907 if (r != 0) {
4908 4908 switch (scf_error()) {
4909 4909 case SCF_ERROR_CONNECTION_BROKEN:
4910 4910 case SCF_ERROR_NO_RESOURCES:
4911 4911 case SCF_ERROR_BACKEND_READONLY:
4912 4912 case SCF_ERROR_BACKEND_ACCESS:
4913 4913 r = scferror2errno(scf_error());
4914 4914 goto out;
4915 4915
4916 4916 case SCF_ERROR_DELETED:
4917 4917 warn(cf_missing, ient->sc_fmri,
4918 4918 ud_name);
4919 4919 r = 0;
4920 4920 goto out;
4921 4921
4922 4922 case SCF_ERROR_PERMISSION_DENIED:
4923 4923 warn(emsg_pg_deleted, ud_ctarg,
4924 4924 ud_name);
4925 4925 r = EPERM;
4926 4926 goto out;
4927 4927
4928 4928 case SCF_ERROR_EXISTS:
4929 4929 warn(emsg_pg_added, ud_ctarg, ud_name);
4930 4930 r = EBUSY;
4931 4931 goto out;
4932 4932
4933 4933 case SCF_ERROR_NOT_BOUND:
4934 4934 case SCF_ERROR_HANDLE_MISMATCH:
4935 4935 case SCF_ERROR_INVALID_ARGUMENT:
4936 4936 case SCF_ERROR_NOT_SET:
4937 4937 default:
4938 4938 bad_error("entity_add_pg", scf_error());
4939 4939 }
4940 4940 }
4941 4941 }
4942 4942
4943 4943 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4944 4944 switch (r) {
4945 4945 case 0:
4946 4946 break;
4947 4947
4948 4948 case ECANCELED:
4949 4949 warn(cf_missing, ient->sc_fmri, ud_name);
4950 4950 goto out;
4951 4951
4952 4952 case ECONNABORTED:
4953 4953 case ENOMEM:
4954 4954 case EBADF:
4955 4955 goto out;
4956 4956
4957 4957 case EACCES:
4958 4958 default:
4959 4959 bad_error("load_pg", r);
4960 4960 }
4961 4961
4962 4962 if (g_verbose)
4963 4963 warn(upgrading, ient->sc_fmri, ud_name);
4964 4964
4965 4965 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4966 4966 new_dpt_pgroup, 0, ient->sc_fmri);
4967 4967 switch (r) {
4968 4968 case 0:
4969 4969 break;
4970 4970
4971 4971 case ECANCELED:
4972 4972 warn(emsg_pg_deleted, ud_ctarg, ud_name);
4973 4973 r = EBUSY;
4974 4974 goto out;
4975 4975
4976 4976 case EPERM:
4977 4977 warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4978 4978 goto out;
4979 4979
4980 4980 case EBUSY:
4981 4981 warn(emsg_pg_changed, ud_ctarg, ud_name);
4982 4982 goto out;
4983 4983
4984 4984 case ECONNABORTED:
4985 4985 case ENOMEM:
4986 4986 case ENOSPC:
4987 4987 case EROFS:
4988 4988 case EACCES:
4989 4989 case EINVAL:
4990 4990 goto out;
4991 4991
4992 4992 default:
4993 4993 bad_error("upgrade_pg", r);
4994 4994 }
4995 4995 break;
4996 4996
4997 4997 case 0: {
4998 4998 scf_transaction_entry_t *ent;
4999 4999 scf_value_t *val;
5000 5000
5001 5001 internal_pgroup_free(current_pg);
5002 5002
5003 5003 /* delete old pg */
5004 5004 if (g_verbose)
5005 5005 warn(upgrading, ient->sc_fmri, ud_name);
5006 5006
5007 5007 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5008 5008 switch (scf_error()) {
5009 5009 case SCF_ERROR_CONNECTION_BROKEN:
5010 5010 r = scferror2errno(scf_error());
5011 5011 goto out;
5012 5012
5013 5013 case SCF_ERROR_DELETED:
5014 5014 warn(cf_missing, ient->sc_fmri, ud_name);
5015 5015 r = 0;
5016 5016 goto out;
5017 5017
5018 5018 case SCF_ERROR_NOT_FOUND:
5019 5019 break;
5020 5020
5021 5021 case SCF_ERROR_INVALID_ARGUMENT:
5022 5022 case SCF_ERROR_NOT_BOUND:
5023 5023 case SCF_ERROR_NOT_SET:
5024 5024 case SCF_ERROR_HANDLE_MISMATCH:
5025 5025 default:
5026 5026 bad_error("entity_get_pg", scf_error());
5027 5027 }
5028 5028 } else if (scf_pg_delete(ud_pg) != 0) {
5029 5029 switch (scf_error()) {
5030 5030 case SCF_ERROR_DELETED:
5031 5031 break;
5032 5032
5033 5033 case SCF_ERROR_CONNECTION_BROKEN:
5034 5034 case SCF_ERROR_BACKEND_READONLY:
5035 5035 case SCF_ERROR_BACKEND_ACCESS:
5036 5036 r = scferror2errno(scf_error());
5037 5037 goto out;
5038 5038
5039 5039 case SCF_ERROR_PERMISSION_DENIED:
5040 5040 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5041 5041 r = scferror2errno(scf_error());
5042 5042 goto out;
5043 5043
5044 5044 case SCF_ERROR_NOT_SET:
5045 5045 default:
5046 5046 bad_error("scf_pg_delete", scf_error());
5047 5047 }
5048 5048 }
5049 5049
5050 5050 /* import new one */
5051 5051 cbdata.sc_handle = g_hndl;
5052 5052 cbdata.sc_trans = NULL; /* handled below */
5053 5053 cbdata.sc_flags = 0;
5054 5054
5055 5055 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5056 5056 if (r != UU_WALK_NEXT) {
5057 5057 if (r != UU_WALK_ERROR)
5058 5058 bad_error("lscf_dependent_import", r);
5059 5059
5060 5060 r = cbdata.sc_err;
5061 5061 goto out;
5062 5062 }
5063 5063
5064 5064 if (tx == NULL)
5065 5065 break;
5066 5066
5067 5067 if ((ent = scf_entry_create(g_hndl)) == NULL ||
5068 5068 (val = scf_value_create(g_hndl)) == NULL) {
5069 5069 if (scf_error() == SCF_ERROR_NO_MEMORY)
5070 5070 return (ENOMEM);
5071 5071
5072 5072 bad_error("scf_entry_create", scf_error());
5073 5073 }
5074 5074
5075 5075 if (scf_transaction_property_change_type(tx, ent, ud_name,
5076 5076 SCF_TYPE_FMRI) != 0) {
5077 5077 switch (scf_error()) {
5078 5078 case SCF_ERROR_CONNECTION_BROKEN:
5079 5079 r = scferror2errno(scf_error());
5080 5080 goto out;
5081 5081
5082 5082 case SCF_ERROR_DELETED:
5083 5083 warn(emsg_pg_deleted, ient->sc_fmri,
5084 5084 "dependents");
5085 5085 r = EBUSY;
5086 5086 goto out;
5087 5087
5088 5088 case SCF_ERROR_NOT_FOUND:
5089 5089 break;
5090 5090
5091 5091 case SCF_ERROR_NOT_BOUND:
5092 5092 case SCF_ERROR_HANDLE_MISMATCH:
5093 5093 case SCF_ERROR_INVALID_ARGUMENT:
5094 5094 case SCF_ERROR_NOT_SET:
5095 5095 default:
5096 5096 bad_error("scf_transaction_property_"
5097 5097 "change_type", scf_error());
5098 5098 }
5099 5099
5100 5100 if (scf_transaction_property_new(tx, ent, ud_name,
5101 5101 SCF_TYPE_FMRI) != 0) {
5102 5102 switch (scf_error()) {
5103 5103 case SCF_ERROR_CONNECTION_BROKEN:
5104 5104 r = scferror2errno(scf_error());
5105 5105 goto out;
5106 5106
5107 5107 case SCF_ERROR_DELETED:
5108 5108 warn(emsg_pg_deleted, ient->sc_fmri,
5109 5109 "dependents");
5110 5110 r = EBUSY;
5111 5111 goto out;
5112 5112
5113 5113 case SCF_ERROR_EXISTS:
5114 5114 warn(emsg_pg_changed, ient->sc_fmri,
5115 5115 "dependents");
5116 5116 r = EBUSY;
5117 5117 goto out;
5118 5118
5119 5119 case SCF_ERROR_INVALID_ARGUMENT:
5120 5120 case SCF_ERROR_HANDLE_MISMATCH:
5121 5121 case SCF_ERROR_NOT_BOUND:
5122 5122 case SCF_ERROR_NOT_SET:
5123 5123 default:
5124 5124 bad_error("scf_transaction_property_"
5125 5125 "new", scf_error());
5126 5126 }
5127 5127 }
5128 5128 }
5129 5129
5130 5130 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5131 5131 new_dpt_pgroup->sc_pgroup_fmri) != 0)
5132 5132 /* invalid sc_pgroup_fmri caught above */
5133 5133 bad_error("scf_value_set_from_string",
5134 5134 scf_error());
5135 5135
5136 5136 if (scf_entry_add_value(ent, val) != 0)
5137 5137 bad_error("scf_entry_add_value", scf_error());
5138 5138 break;
5139 5139 }
5140 5140
5141 5141 case -2:
5142 5142 warn(li_corrupt, ient->sc_fmri);
5143 5143 internal_pgroup_free(current_pg);
5144 5144 r = EBADF;
5145 5145 goto out;
5146 5146
5147 5147 case -1:
5148 5148 default:
5149 5149 /* invalid sc_pgroup_fmri caught above */
5150 5150 bad_error("fmri_equal", r);
5151 5151 }
5152 5152
5153 5153 r = 0;
5154 5154
5155 5155 out:
5156 5156 if (old_dpt_pgroup != NULL)
5157 5157 internal_pgroup_free(old_dpt_pgroup);
5158 5158
5159 5159 return (r);
5160 5160 }
5161 5161
5162 5162 /*
5163 5163 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5164 5164 * would import it, except it seems to exist in the service anyway. Compare
5165 5165 * the existent dependent with the one we would import, and report any
5166 5166 * differences (if there are none, be silent). prop is the property which
5167 5167 * represents the existent dependent (in the dependents property group) in the
5168 5168 * entity corresponding to ient.
5169 5169 *
5170 5170 * Returns
5171 5171 * 0 - success (Sort of. At least, we can continue importing.)
5172 5172 * ECONNABORTED - repository connection broken
5173 5173 * EBUSY - ancestor of prop was deleted (error printed)
5174 5174 * ENOMEM - out of memory
5175 5175 * EBADF - corrupt property group (error printed)
5176 5176 * EINVAL - new_dpt_pgroup has invalid target (error printed)
5177 5177 */
5178 5178 static int
5179 5179 handle_dependent_conflict(const entity_t * const ient,
5180 5180 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5181 5181 {
5182 5182 int r;
5183 5183 scf_type_t ty;
5184 5184 scf_error_t scfe;
5185 5185 void *tptr;
5186 5186 int tissvc;
5187 5187 pgroup_t *pgroup;
5188 5188
5189 5189 if (scf_property_get_value(prop, ud_val) != 0) {
5190 5190 switch (scf_error()) {
5191 5191 case SCF_ERROR_CONNECTION_BROKEN:
5192 5192 return (scferror2errno(scf_error()));
5193 5193
5194 5194 case SCF_ERROR_DELETED:
5195 5195 warn(emsg_pg_deleted, ient->sc_fmri,
5196 5196 new_dpt_pgroup->sc_pgroup_name);
5197 5197 return (EBUSY);
5198 5198
5199 5199 case SCF_ERROR_CONSTRAINT_VIOLATED:
5200 5200 case SCF_ERROR_NOT_FOUND:
5201 5201 warn(gettext("Conflict upgrading %s (not importing "
5202 5202 "dependent \"%s\" because it already exists.) "
5203 5203 "Warning: The \"%s/%2$s\" property has more or "
5204 5204 "fewer than one value)).\n"), ient->sc_fmri,
5205 5205 new_dpt_pgroup->sc_pgroup_name, "dependents");
5206 5206 return (0);
5207 5207
5208 5208 case SCF_ERROR_HANDLE_MISMATCH:
5209 5209 case SCF_ERROR_NOT_BOUND:
5210 5210 case SCF_ERROR_NOT_SET:
5211 5211 case SCF_ERROR_PERMISSION_DENIED:
5212 5212 default:
5213 5213 bad_error("scf_property_get_value",
5214 5214 scf_error());
5215 5215 }
5216 5216 }
5217 5217
5218 5218 ty = scf_value_type(ud_val);
5219 5219 assert(ty != SCF_TYPE_INVALID);
5220 5220 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5221 5221 warn(gettext("Conflict upgrading %s (not importing dependent "
5222 5222 "\"%s\" because it already exists). Warning: The "
5223 5223 "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5224 5224 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5225 5225 scf_type_to_string(ty), "dependents");
5226 5226 return (0);
5227 5227 }
5228 5228
5229 5229 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5230 5230 0)
5231 5231 bad_error("scf_value_get_as_string", scf_error());
5232 5232
5233 5233 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5234 5234 switch (r) {
5235 5235 case 0:
5236 5236 warn(gettext("Conflict upgrading %s (not importing dependent "
5237 5237 "\"%s\" (target \"%s\") because it already exists with "
5238 5238 "target \"%s\").\n"), ient->sc_fmri,
5239 5239 new_dpt_pgroup->sc_pgroup_name,
5240 5240 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5241 5241 return (0);
5242 5242
5243 5243 case 1:
5244 5244 break;
5245 5245
5246 5246 case -1:
5247 5247 warn(gettext("Conflict upgrading %s (not importing dependent "
5248 5248 "\"%s\" because it already exists). Warning: The current "
5249 5249 "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5250 5250 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5251 5251 return (0);
5252 5252
5253 5253 case -2:
5254 5254 warn(gettext("Dependent \"%s\" of %s has invalid target "
5255 5255 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5256 5256 new_dpt_pgroup->sc_pgroup_fmri);
5257 5257 return (EINVAL);
5258 5258
5259 5259 default:
5260 5260 bad_error("fmri_equal", r);
5261 5261 }
5262 5262
5263 5263 /* compare dependency pgs in target */
5264 5264 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5265 5265 switch (scfe) {
5266 5266 case SCF_ERROR_NONE:
5267 5267 break;
5268 5268
5269 5269 case SCF_ERROR_NO_MEMORY:
5270 5270 return (ENOMEM);
5271 5271
5272 5272 case SCF_ERROR_NOT_FOUND:
5273 5273 warn(emsg_dpt_dangling, ient->sc_fmri,
5274 5274 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5275 5275 return (0);
5276 5276
5277 5277 case SCF_ERROR_CONSTRAINT_VIOLATED:
5278 5278 case SCF_ERROR_INVALID_ARGUMENT:
5279 5279 default:
5280 5280 bad_error("fmri_to_entity", scfe);
5281 5281 }
5282 5282
5283 5283 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5284 5284 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5285 5285 switch (r) {
5286 5286 case 0:
5287 5287 break;
5288 5288
5289 5289 case ECONNABORTED:
5290 5290 return (r);
5291 5291
5292 5292 case ECANCELED:
5293 5293 warn(emsg_dpt_dangling, ient->sc_fmri,
5294 5294 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5295 5295 return (0);
5296 5296
5297 5297 case EBADF:
5298 5298 if (tissvc)
5299 5299 warn(gettext("%s has an instance with a \"%s\" "
5300 5300 "snapshot which is missing a snaplevel.\n"),
5301 5301 ud_ctarg, "running");
5302 5302 else
5303 5303 warn(gettext("%s has a \"%s\" snapshot which is "
5304 5304 "missing a snaplevel.\n"), ud_ctarg, "running");
5305 5305 /* FALLTHROUGH */
5306 5306
5307 5307 case ENOENT:
5308 5308 warn(emsg_dpt_no_dep, ient->sc_fmri,
5309 5309 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5310 5310 new_dpt_pgroup->sc_pgroup_name);
5311 5311 return (0);
5312 5312
5313 5313 case EINVAL:
5314 5314 default:
5315 5315 bad_error("entity_get_running_pg", r);
5316 5316 }
5317 5317
5318 5318 pgroup = internal_pgroup_new();
5319 5319 if (pgroup == NULL)
5320 5320 return (ENOMEM);
5321 5321
5322 5322 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5323 5323 switch (r) {
5324 5324 case 0:
5325 5325 break;
5326 5326
5327 5327 case ECONNABORTED:
5328 5328 case EBADF:
5329 5329 case ENOMEM:
5330 5330 internal_pgroup_free(pgroup);
5331 5331 return (r);
5332 5332
5333 5333 case ECANCELED:
5334 5334 warn(emsg_dpt_no_dep, ient->sc_fmri,
5335 5335 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5336 5336 new_dpt_pgroup->sc_pgroup_name);
5337 5337 internal_pgroup_free(pgroup);
5338 5338 return (0);
5339 5339
5340 5340 case EACCES:
5341 5341 default:
5342 5342 bad_error("load_pg", r);
5343 5343 }
5344 5344
5345 5345 /* report differences */
5346 5346 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5347 5347 internal_pgroup_free(pgroup);
5348 5348 return (0);
5349 5349 }
5350 5350
5351 5351 /*
5352 5352 * lipg is a property group in the last-import snapshot of ent, which is an
5353 5353 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in
5354 5354 * ient's pgroups, delete it from ent if it hasn't been customized. If it is
5355 5355 * in ents's property groups, compare and upgrade ent appropriately.
5356 5356 *
5357 5357 * Returns
5358 5358 * 0 - success
5359 5359 * ECONNABORTED - repository connection broken
5360 5360 * ENOMEM - out of memory
5361 5361 * ENOSPC - configd is out of resources
5362 5362 * EINVAL - ient has invalid dependent (error printed)
5363 5363 * - ient has invalid pgroup_t (error printed)
5364 5364 * ECANCELED - ent has been deleted
5365 5365 * ENODEV - entity containing lipg has been deleted
5366 5366 * - entity containing running has been deleted
5367 5367 * EPERM - could not delete pg (permission denied) (error printed)
5368 5368 * - couldn't upgrade dependents (permission denied) (error printed)
5369 5369 * - couldn't import pg (permission denied) (error printed)
5370 5370 * - couldn't upgrade pg (permission denied) (error printed)
5371 5371 * EROFS - could not delete pg (repository read-only)
5372 5372 * - couldn't upgrade dependents (repository read-only)
5373 5373 * - couldn't import pg (repository read-only)
5374 5374 * - couldn't upgrade pg (repository read-only)
5375 5375 * EACCES - could not delete pg (backend access denied)
5376 5376 * - couldn't upgrade dependents (backend access denied)
5377 5377 * - couldn't import pg (backend access denied)
5378 5378 * - couldn't upgrade pg (backend access denied)
5379 5379 * - couldn't read property (backend access denied)
5380 5380 * EBUSY - property group was added (error printed)
5381 5381 * - property group was deleted (error printed)
5382 5382 * - property group changed (error printed)
5383 5383 * - "dependents" pg was added, changed, or deleted (error printed)
5384 5384 * - dependent target deleted (error printed)
5385 5385 * - dependent pg changed (error printed)
5386 5386 * EBADF - imp_snpl is corrupt (error printed)
5387 5387 * - ent has bad pg (error printed)
5388 5388 * EEXIST - dependent collision in target service (error printed)
5389 5389 */
5390 5390 static int
5391 5391 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5392 5392 const scf_snaplevel_t *running)
5393 5393 {
5394 5394 int r;
5395 5395 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5396 5396 scf_callback_t cbdata;
5397 5397
5398 5398 const char * const cf_pg_missing =
5399 5399 gettext("Conflict upgrading %s (property group %s is missing)\n");
5400 5400 const char * const deleting =
5401 5401 gettext("%s: Deleting property group \"%s\".\n");
5402 5402
5403 5403 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5404 5404
5405 5405 /* Skip dependent property groups. */
5406 5406 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5407 5407 switch (scf_error()) {
5408 5408 case SCF_ERROR_DELETED:
5409 5409 return (ENODEV);
5410 5410
5411 5411 case SCF_ERROR_CONNECTION_BROKEN:
5412 5412 return (ECONNABORTED);
5413 5413
5414 5414 case SCF_ERROR_NOT_SET:
5415 5415 case SCF_ERROR_NOT_BOUND:
5416 5416 default:
5417 5417 bad_error("scf_pg_get_type", scf_error());
5418 5418 }
5419 5419 }
5420 5420
5421 5421 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5422 5422 if (scf_pg_get_property(lipg, "external", NULL) == 0)
5423 5423 return (0);
5424 5424
5425 5425 switch (scf_error()) {
5426 5426 case SCF_ERROR_NOT_FOUND:
5427 5427 break;
5428 5428
5429 5429 case SCF_ERROR_CONNECTION_BROKEN:
5430 5430 return (ECONNABORTED);
5431 5431
5432 5432 case SCF_ERROR_DELETED:
5433 5433 return (ENODEV);
5434 5434
5435 5435 case SCF_ERROR_INVALID_ARGUMENT:
5436 5436 case SCF_ERROR_NOT_BOUND:
5437 5437 case SCF_ERROR_HANDLE_MISMATCH:
5438 5438 case SCF_ERROR_NOT_SET:
5439 5439 default:
5440 5440 bad_error("scf_pg_get_property", scf_error());
5441 5441 }
5442 5442 }
5443 5443
5444 5444 /* lookup pg in new properties */
5445 5445 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5446 5446 switch (scf_error()) {
5447 5447 case SCF_ERROR_DELETED:
5448 5448 return (ENODEV);
5449 5449
5450 5450 case SCF_ERROR_CONNECTION_BROKEN:
5451 5451 return (ECONNABORTED);
5452 5452
5453 5453 case SCF_ERROR_NOT_SET:
5454 5454 case SCF_ERROR_NOT_BOUND:
5455 5455 default:
5456 5456 bad_error("scf_pg_get_name", scf_error());
5457 5457 }
5458 5458 }
5459 5459
5460 5460 pgrp.sc_pgroup_name = imp_str;
5461 5461 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5462 5462
5463 5463 if (mpg != NULL)
5464 5464 mpg->sc_pgroup_seen = 1;
5465 5465
5466 5466 /* Special handling for dependents */
5467 5467 if (strcmp(imp_str, "dependents") == 0)
5468 5468 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5469 5469
5470 5470 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5471 5471 return (upgrade_manifestfiles(NULL, ient, running, ent));
5472 5472
5473 5473 if (mpg == NULL || mpg->sc_pgroup_delete) {
5474 5474 /* property group was deleted from manifest */
5475 5475 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5476 5476 switch (scf_error()) {
5477 5477 case SCF_ERROR_NOT_FOUND:
5478 5478 return (0);
5479 5479
5480 5480 case SCF_ERROR_DELETED:
5481 5481 case SCF_ERROR_CONNECTION_BROKEN:
5482 5482 return (scferror2errno(scf_error()));
5483 5483
5484 5484 case SCF_ERROR_INVALID_ARGUMENT:
5485 5485 case SCF_ERROR_HANDLE_MISMATCH:
5486 5486 case SCF_ERROR_NOT_BOUND:
5487 5487 case SCF_ERROR_NOT_SET:
5488 5488 default:
5489 5489 bad_error("entity_get_pg", scf_error());
5490 5490 }
5491 5491 }
5492 5492
5493 5493 if (mpg != NULL && mpg->sc_pgroup_delete) {
5494 5494 if (g_verbose)
5495 5495 warn(deleting, ient->sc_fmri, imp_str);
5496 5496 if (scf_pg_delete(imp_pg2) == 0)
5497 5497 return (0);
5498 5498
5499 5499 switch (scf_error()) {
5500 5500 case SCF_ERROR_DELETED:
5501 5501 return (0);
5502 5502
5503 5503 case SCF_ERROR_CONNECTION_BROKEN:
5504 5504 case SCF_ERROR_BACKEND_READONLY:
5505 5505 case SCF_ERROR_BACKEND_ACCESS:
5506 5506 return (scferror2errno(scf_error()));
5507 5507
5508 5508 case SCF_ERROR_PERMISSION_DENIED:
5509 5509 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5510 5510 return (scferror2errno(scf_error()));
5511 5511
5512 5512 case SCF_ERROR_NOT_SET:
5513 5513 default:
5514 5514 bad_error("scf_pg_delete", scf_error());
5515 5515 }
5516 5516 }
5517 5517
5518 5518 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5519 5519 switch (r) {
5520 5520 case 0:
5521 5521 break;
5522 5522
5523 5523 case ECANCELED:
5524 5524 return (ENODEV);
5525 5525
5526 5526 case ECONNABORTED:
5527 5527 case ENOMEM:
5528 5528 case EBADF:
5529 5529 case EACCES:
5530 5530 return (r);
5531 5531
5532 5532 default:
5533 5533 bad_error("load_pg", r);
5534 5534 }
5535 5535
5536 5536 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5537 5537 switch (r) {
5538 5538 case 0:
5539 5539 break;
5540 5540
5541 5541 case ECANCELED:
5542 5542 case ECONNABORTED:
5543 5543 case ENOMEM:
5544 5544 case EBADF:
5545 5545 case EACCES:
5546 5546 internal_pgroup_free(lipg_i);
5547 5547 return (r);
5548 5548
5549 5549 default:
5550 5550 bad_error("load_pg", r);
5551 5551 }
5552 5552
5553 5553 if (pg_equal(lipg_i, curpg_i)) {
5554 5554 if (g_verbose)
5555 5555 warn(deleting, ient->sc_fmri, imp_str);
5556 5556 if (scf_pg_delete(imp_pg2) != 0) {
5557 5557 switch (scf_error()) {
5558 5558 case SCF_ERROR_DELETED:
5559 5559 break;
5560 5560
5561 5561 case SCF_ERROR_CONNECTION_BROKEN:
5562 5562 internal_pgroup_free(lipg_i);
5563 5563 internal_pgroup_free(curpg_i);
5564 5564 return (ECONNABORTED);
5565 5565
5566 5566 case SCF_ERROR_NOT_SET:
5567 5567 case SCF_ERROR_NOT_BOUND:
5568 5568 default:
5569 5569 bad_error("scf_pg_delete", scf_error());
5570 5570 }
5571 5571 }
5572 5572 } else {
5573 5573 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5574 5574 }
5575 5575
5576 5576 internal_pgroup_free(lipg_i);
5577 5577 internal_pgroup_free(curpg_i);
5578 5578
5579 5579 return (0);
5580 5580 }
5581 5581
5582 5582 /*
5583 5583 * Only dependent pgs can have override set, and we skipped those
5584 5584 * above.
5585 5585 */
5586 5586 assert(!mpg->sc_pgroup_override);
5587 5587
5588 5588 /* compare */
5589 5589 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5590 5590 switch (r) {
5591 5591 case 0:
5592 5592 break;
5593 5593
5594 5594 case ECANCELED:
5595 5595 return (ENODEV);
5596 5596
5597 5597 case ECONNABORTED:
5598 5598 case EBADF:
5599 5599 case ENOMEM:
5600 5600 case EACCES:
5601 5601 return (r);
5602 5602
5603 5603 default:
5604 5604 bad_error("load_pg", r);
5605 5605 }
5606 5606
5607 5607 if (pg_equal(mpg, lipg_i)) {
5608 5608 /* The manifest pg has not changed. Move on. */
5609 5609 r = 0;
5610 5610 goto out;
5611 5611 }
5612 5612
5613 5613 /* upgrade current properties according to lipg & mpg */
5614 5614 if (running != NULL)
5615 5615 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5616 5616 else
5617 5617 r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5618 5618 if (r != 0) {
5619 5619 switch (scf_error()) {
5620 5620 case SCF_ERROR_CONNECTION_BROKEN:
5621 5621 r = scferror2errno(scf_error());
5622 5622 goto out;
5623 5623
5624 5624 case SCF_ERROR_DELETED:
5625 5625 if (running != NULL)
5626 5626 r = ENODEV;
5627 5627 else
5628 5628 r = ECANCELED;
5629 5629 goto out;
5630 5630
5631 5631 case SCF_ERROR_NOT_FOUND:
5632 5632 break;
5633 5633
5634 5634 case SCF_ERROR_INVALID_ARGUMENT:
5635 5635 case SCF_ERROR_HANDLE_MISMATCH:
5636 5636 case SCF_ERROR_NOT_BOUND:
5637 5637 case SCF_ERROR_NOT_SET:
5638 5638 default:
5639 5639 bad_error("entity_get_pg", scf_error());
5640 5640 }
5641 5641
5642 5642 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5643 5643
5644 5644 r = 0;
5645 5645 goto out;
5646 5646 }
5647 5647
5648 5648 r = load_pg_attrs(imp_pg2, &curpg_i);
5649 5649 switch (r) {
5650 5650 case 0:
5651 5651 break;
5652 5652
5653 5653 case ECANCELED:
5654 5654 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5655 5655 r = 0;
5656 5656 goto out;
5657 5657
5658 5658 case ECONNABORTED:
5659 5659 case ENOMEM:
5660 5660 goto out;
5661 5661
5662 5662 default:
5663 5663 bad_error("load_pg_attrs", r);
5664 5664 }
5665 5665
5666 5666 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5667 5667 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5668 5668 internal_pgroup_free(curpg_i);
5669 5669 r = 0;
5670 5670 goto out;
5671 5671 }
5672 5672
5673 5673 internal_pgroup_free(curpg_i);
5674 5674
5675 5675 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5676 5676 switch (r) {
5677 5677 case 0:
5678 5678 break;
5679 5679
5680 5680 case ECANCELED:
5681 5681 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5682 5682 r = 0;
5683 5683 goto out;
5684 5684
5685 5685 case ECONNABORTED:
5686 5686 case EBADF:
5687 5687 case ENOMEM:
5688 5688 case EACCES:
5689 5689 goto out;
5690 5690
5691 5691 default:
5692 5692 bad_error("load_pg", r);
5693 5693 }
5694 5694
5695 5695 if (pg_equal(lipg_i, curpg_i) &&
5696 5696 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5697 5697 int do_delete = 1;
5698 5698
5699 5699 if (g_verbose)
5700 5700 warn(gettext("%s: Upgrading property group \"%s\".\n"),
5701 5701 ient->sc_fmri, mpg->sc_pgroup_name);
5702 5702
5703 5703 internal_pgroup_free(curpg_i);
5704 5704
5705 5705 if (running != NULL &&
5706 5706 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5707 5707 switch (scf_error()) {
5708 5708 case SCF_ERROR_DELETED:
5709 5709 r = ECANCELED;
5710 5710 goto out;
5711 5711
5712 5712 case SCF_ERROR_NOT_FOUND:
5713 5713 do_delete = 0;
5714 5714 break;
5715 5715
5716 5716 case SCF_ERROR_CONNECTION_BROKEN:
5717 5717 r = scferror2errno(scf_error());
5718 5718 goto out;
5719 5719
5720 5720 case SCF_ERROR_HANDLE_MISMATCH:
5721 5721 case SCF_ERROR_INVALID_ARGUMENT:
5722 5722 case SCF_ERROR_NOT_SET:
5723 5723 case SCF_ERROR_NOT_BOUND:
5724 5724 default:
5725 5725 bad_error("entity_get_pg", scf_error());
5726 5726 }
5727 5727 }
5728 5728
5729 5729 if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5730 5730 switch (scf_error()) {
5731 5731 case SCF_ERROR_DELETED:
5732 5732 break;
5733 5733
5734 5734 case SCF_ERROR_CONNECTION_BROKEN:
5735 5735 case SCF_ERROR_BACKEND_READONLY:
5736 5736 case SCF_ERROR_BACKEND_ACCESS:
5737 5737 r = scferror2errno(scf_error());
5738 5738 goto out;
5739 5739
5740 5740 case SCF_ERROR_PERMISSION_DENIED:
5741 5741 warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5742 5742 ient->sc_fmri);
5743 5743 r = scferror2errno(scf_error());
5744 5744 goto out;
5745 5745
5746 5746 case SCF_ERROR_NOT_SET:
5747 5747 case SCF_ERROR_NOT_BOUND:
5748 5748 default:
5749 5749 bad_error("scf_pg_delete", scf_error());
5750 5750 }
5751 5751 }
5752 5752
5753 5753 cbdata.sc_handle = g_hndl;
5754 5754 cbdata.sc_parent = ent;
5755 5755 cbdata.sc_service = issvc;
5756 5756 cbdata.sc_flags = 0;
5757 5757 cbdata.sc_source_fmri = ient->sc_fmri;
5758 5758 cbdata.sc_target_fmri = ient->sc_fmri;
5759 5759
5760 5760 r = entity_pgroup_import(mpg, &cbdata);
5761 5761 switch (r) {
5762 5762 case UU_WALK_NEXT:
5763 5763 r = 0;
5764 5764 goto out;
5765 5765
5766 5766 case UU_WALK_ERROR:
5767 5767 if (cbdata.sc_err == EEXIST) {
5768 5768 warn(emsg_pg_added, ient->sc_fmri,
5769 5769 mpg->sc_pgroup_name);
5770 5770 r = EBUSY;
5771 5771 } else {
5772 5772 r = cbdata.sc_err;
5773 5773 }
5774 5774 goto out;
5775 5775
5776 5776 default:
5777 5777 bad_error("entity_pgroup_import", r);
5778 5778 }
5779 5779 }
5780 5780
5781 5781 if (running != NULL &&
5782 5782 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5783 5783 switch (scf_error()) {
5784 5784 case SCF_ERROR_CONNECTION_BROKEN:
5785 5785 case SCF_ERROR_DELETED:
5786 5786 r = scferror2errno(scf_error());
5787 5787 goto out;
5788 5788
5789 5789 case SCF_ERROR_NOT_FOUND:
5790 5790 break;
5791 5791
5792 5792 case SCF_ERROR_HANDLE_MISMATCH:
5793 5793 case SCF_ERROR_INVALID_ARGUMENT:
5794 5794 case SCF_ERROR_NOT_SET:
5795 5795 case SCF_ERROR_NOT_BOUND:
5796 5796 default:
5797 5797 bad_error("entity_get_pg", scf_error());
5798 5798 }
5799 5799
5800 5800 cbdata.sc_handle = g_hndl;
5801 5801 cbdata.sc_parent = ent;
5802 5802 cbdata.sc_service = issvc;
5803 5803 cbdata.sc_flags = SCI_FORCE;
5804 5804 cbdata.sc_source_fmri = ient->sc_fmri;
5805 5805 cbdata.sc_target_fmri = ient->sc_fmri;
5806 5806
5807 5807 r = entity_pgroup_import(mpg, &cbdata);
5808 5808 switch (r) {
5809 5809 case UU_WALK_NEXT:
5810 5810 r = 0;
5811 5811 goto out;
5812 5812
5813 5813 case UU_WALK_ERROR:
5814 5814 if (cbdata.sc_err == EEXIST) {
5815 5815 warn(emsg_pg_added, ient->sc_fmri,
5816 5816 mpg->sc_pgroup_name);
5817 5817 r = EBUSY;
5818 5818 } else {
5819 5819 r = cbdata.sc_err;
5820 5820 }
5821 5821 goto out;
5822 5822
5823 5823 default:
5824 5824 bad_error("entity_pgroup_import", r);
5825 5825 }
5826 5826 }
5827 5827
5828 5828 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5829 5829 internal_pgroup_free(curpg_i);
5830 5830 switch (r) {
5831 5831 case 0:
5832 5832 ient->sc_import_state = IMPORT_PROP_BEGUN;
5833 5833 break;
5834 5834
5835 5835 case ECANCELED:
5836 5836 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5837 5837 r = EBUSY;
5838 5838 break;
5839 5839
5840 5840 case EPERM:
5841 5841 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5842 5842 break;
5843 5843
5844 5844 case EBUSY:
5845 5845 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5846 5846 break;
5847 5847
5848 5848 case ECONNABORTED:
5849 5849 case ENOMEM:
5850 5850 case ENOSPC:
5851 5851 case EROFS:
5852 5852 case EACCES:
5853 5853 case EINVAL:
5854 5854 break;
5855 5855
5856 5856 default:
5857 5857 bad_error("upgrade_pg", r);
5858 5858 }
5859 5859
5860 5860 out:
5861 5861 internal_pgroup_free(lipg_i);
5862 5862 return (r);
5863 5863 }
5864 5864
5865 5865 /*
5866 5866 * Upgrade the properties of ent according to snpl & ient.
5867 5867 *
5868 5868 * Returns
5869 5869 * 0 - success
5870 5870 * ECONNABORTED - repository connection broken
5871 5871 * ENOMEM - out of memory
5872 5872 * ENOSPC - configd is out of resources
5873 5873 * ECANCELED - ent was deleted
5874 5874 * ENODEV - entity containing snpl was deleted
5875 5875 * - entity containing running was deleted
5876 5876 * EBADF - imp_snpl is corrupt (error printed)
5877 5877 * - ent has corrupt pg (error printed)
5878 5878 * - dependent has corrupt pg (error printed)
5879 5879 * - dependent target has a corrupt snapshot (error printed)
5880 5880 * EBUSY - pg was added, changed, or deleted (error printed)
5881 5881 * - dependent target was deleted (error printed)
5882 5882 * - dependent pg changed (error printed)
5883 5883 * EINVAL - invalid property group name (error printed)
5884 5884 * - invalid property name (error printed)
5885 5885 * - invalid value (error printed)
5886 5886 * - ient has invalid pgroup or dependent (error printed)
5887 5887 * EPERM - could not create property group (permission denied) (error printed)
5888 5888 * - could not modify property group (permission denied) (error printed)
5889 5889 * - couldn't delete, upgrade, or import pg or dependent (error printed)
5890 5890 * EROFS - could not create property group (repository read-only)
5891 5891 * - couldn't delete, upgrade, or import pg or dependent
5892 5892 * EACCES - could not create property group (backend access denied)
5893 5893 * - couldn't delete, upgrade, or import pg or dependent
5894 5894 * EEXIST - dependent collision in target service (error printed)
5895 5895 */
5896 5896 static int
5897 5897 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5898 5898 entity_t *ient)
5899 5899 {
5900 5900 pgroup_t *pg, *rpg;
5901 5901 int r;
5902 5902 uu_list_t *pgs = ient->sc_pgroups;
5903 5903
5904 5904 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5905 5905
5906 5906 /* clear sc_sceen for pgs */
5907 5907 if (uu_list_walk(pgs, clear_int,
5908 5908 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5909 5909 bad_error("uu_list_walk", uu_error());
5910 5910
5911 5911 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5912 5912 switch (scf_error()) {
5913 5913 case SCF_ERROR_DELETED:
5914 5914 return (ENODEV);
5915 5915
5916 5916 case SCF_ERROR_CONNECTION_BROKEN:
5917 5917 return (ECONNABORTED);
5918 5918
5919 5919 case SCF_ERROR_NOT_SET:
5920 5920 case SCF_ERROR_NOT_BOUND:
5921 5921 case SCF_ERROR_HANDLE_MISMATCH:
5922 5922 default:
5923 5923 bad_error("scf_iter_snaplevel_pgs", scf_error());
5924 5924 }
5925 5925 }
5926 5926
5927 5927 for (;;) {
5928 5928 r = scf_iter_next_pg(imp_up_iter, imp_pg);
5929 5929 if (r == 0)
5930 5930 break;
5931 5931 if (r == 1) {
5932 5932 r = process_old_pg(imp_pg, ient, ent, running);
5933 5933 switch (r) {
5934 5934 case 0:
5935 5935 break;
5936 5936
5937 5937 case ECONNABORTED:
5938 5938 case ENOMEM:
5939 5939 case ENOSPC:
5940 5940 case ECANCELED:
5941 5941 case ENODEV:
5942 5942 case EPERM:
5943 5943 case EROFS:
5944 5944 case EACCES:
5945 5945 case EBADF:
5946 5946 case EBUSY:
5947 5947 case EINVAL:
5948 5948 case EEXIST:
5949 5949 return (r);
5950 5950
5951 5951 default:
5952 5952 bad_error("process_old_pg", r);
5953 5953 }
5954 5954 continue;
5955 5955 }
5956 5956 if (r != -1)
5957 5957 bad_error("scf_iter_next_pg", r);
5958 5958
5959 5959 switch (scf_error()) {
5960 5960 case SCF_ERROR_DELETED:
5961 5961 return (ENODEV);
5962 5962
5963 5963 case SCF_ERROR_CONNECTION_BROKEN:
5964 5964 return (ECONNABORTED);
5965 5965
5966 5966 case SCF_ERROR_HANDLE_MISMATCH:
5967 5967 case SCF_ERROR_NOT_BOUND:
5968 5968 case SCF_ERROR_NOT_SET:
5969 5969 case SCF_ERROR_INVALID_ARGUMENT:
5970 5970 default:
5971 5971 bad_error("scf_iter_next_pg", scf_error());
5972 5972 }
5973 5973 }
5974 5974
5975 5975 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5976 5976 if (pg->sc_pgroup_seen)
5977 5977 continue;
5978 5978
5979 5979 /* pg is new */
5980 5980
5981 5981 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5982 5982 r = upgrade_dependents(NULL, imp_snpl, ient, running,
5983 5983 ent);
5984 5984 switch (r) {
5985 5985 case 0:
5986 5986 break;
5987 5987
5988 5988 case ECONNABORTED:
5989 5989 case ENOMEM:
5990 5990 case ENOSPC:
5991 5991 case ECANCELED:
5992 5992 case ENODEV:
5993 5993 case EBADF:
5994 5994 case EBUSY:
5995 5995 case EINVAL:
5996 5996 case EPERM:
5997 5997 case EROFS:
5998 5998 case EACCES:
5999 5999 case EEXIST:
6000 6000 return (r);
6001 6001
6002 6002 default:
6003 6003 bad_error("upgrade_dependents", r);
6004 6004 }
6005 6005 continue;
6006 6006 }
6007 6007
6008 6008 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6009 6009 r = upgrade_manifestfiles(pg, ient, running, ent);
6010 6010 switch (r) {
6011 6011 case 0:
6012 6012 break;
6013 6013
6014 6014 case ECONNABORTED:
6015 6015 case ENOMEM:
6016 6016 case ENOSPC:
6017 6017 case ECANCELED:
6018 6018 case ENODEV:
6019 6019 case EBADF:
6020 6020 case EBUSY:
6021 6021 case EINVAL:
6022 6022 case EPERM:
6023 6023 case EROFS:
6024 6024 case EACCES:
6025 6025 case EEXIST:
6026 6026 return (r);
6027 6027
6028 6028 default:
6029 6029 bad_error("upgrade_manifestfiles", r);
6030 6030 }
6031 6031 continue;
6032 6032 }
6033 6033
6034 6034 if (running != NULL) {
6035 6035 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6036 6036 imp_pg);
6037 6037 } else {
6038 6038 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6039 6039 imp_pg);
6040 6040 }
6041 6041 if (r != 0) {
6042 6042 scf_callback_t cbdata;
6043 6043
6044 6044 switch (scf_error()) {
6045 6045 case SCF_ERROR_NOT_FOUND:
6046 6046 break;
6047 6047
6048 6048 case SCF_ERROR_CONNECTION_BROKEN:
6049 6049 return (scferror2errno(scf_error()));
6050 6050
6051 6051 case SCF_ERROR_DELETED:
6052 6052 if (running != NULL)
6053 6053 return (ENODEV);
6054 6054 else
6055 6055 return (scferror2errno(scf_error()));
6056 6056
6057 6057 case SCF_ERROR_INVALID_ARGUMENT:
6058 6058 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6059 6059 pg->sc_pgroup_name);
6060 6060 return (EINVAL);
6061 6061
6062 6062 case SCF_ERROR_NOT_SET:
6063 6063 case SCF_ERROR_HANDLE_MISMATCH:
6064 6064 case SCF_ERROR_NOT_BOUND:
6065 6065 default:
6066 6066 bad_error("entity_get_pg", scf_error());
6067 6067 }
6068 6068
6069 6069 /* User doesn't have pg, so import it. */
6070 6070
6071 6071 cbdata.sc_handle = g_hndl;
6072 6072 cbdata.sc_parent = ent;
6073 6073 cbdata.sc_service = issvc;
6074 6074 cbdata.sc_flags = SCI_FORCE;
6075 6075 cbdata.sc_source_fmri = ient->sc_fmri;
6076 6076 cbdata.sc_target_fmri = ient->sc_fmri;
6077 6077
6078 6078 r = entity_pgroup_import(pg, &cbdata);
6079 6079 switch (r) {
6080 6080 case UU_WALK_NEXT:
6081 6081 ient->sc_import_state = IMPORT_PROP_BEGUN;
6082 6082 continue;
6083 6083
6084 6084 case UU_WALK_ERROR:
6085 6085 if (cbdata.sc_err == EEXIST) {
6086 6086 warn(emsg_pg_added, ient->sc_fmri,
6087 6087 pg->sc_pgroup_name);
6088 6088 return (EBUSY);
6089 6089 }
6090 6090 return (cbdata.sc_err);
6091 6091
6092 6092 default:
6093 6093 bad_error("entity_pgroup_import", r);
6094 6094 }
6095 6095 }
6096 6096
6097 6097 /* report differences between pg & current */
6098 6098 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6099 6099 switch (r) {
6100 6100 case 0:
6101 6101 break;
6102 6102
6103 6103 case ECANCELED:
6104 6104 warn(emsg_pg_deleted, ient->sc_fmri,
6105 6105 pg->sc_pgroup_name);
6106 6106 return (EBUSY);
6107 6107
6108 6108 case ECONNABORTED:
6109 6109 case EBADF:
6110 6110 case ENOMEM:
6111 6111 case EACCES:
6112 6112 return (r);
6113 6113
6114 6114 default:
6115 6115 bad_error("load_pg", r);
6116 6116 }
6117 6117 report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6118 6118 internal_pgroup_free(rpg);
6119 6119 rpg = NULL;
6120 6120 }
6121 6121
6122 6122 return (0);
6123 6123 }
6124 6124
6125 6125 /*
6126 6126 * Import an instance. If it doesn't exist, create it. If it has
6127 6127 * a last-import snapshot, upgrade its properties. Finish by updating its
6128 6128 * last-import snapshot. If it doesn't have a last-import snapshot then it
6129 6129 * could have been created for a dependent tag in another manifest. Import the
6130 6130 * new properties. If there's a conflict, don't override, like now?
6131 6131 *
6132 6132 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
6133 6133 * lcbdata->sc_err to
6134 6134 * ECONNABORTED - repository connection broken
6135 6135 * ENOMEM - out of memory
6136 6136 * ENOSPC - svc.configd is out of resources
6137 6137 * EEXIST - dependency collision in dependent service (error printed)
6138 6138 * EPERM - couldn't create temporary instance (permission denied)
6139 6139 * - couldn't import into temporary instance (permission denied)
6140 6140 * - couldn't take snapshot (permission denied)
6141 6141 * - couldn't upgrade properties (permission denied)
6142 6142 * - couldn't import properties (permission denied)
6143 6143 * - couldn't import dependents (permission denied)
6144 6144 * EROFS - couldn't create temporary instance (repository read-only)
6145 6145 * - couldn't import into temporary instance (repository read-only)
6146 6146 * - couldn't upgrade properties (repository read-only)
6147 6147 * - couldn't import properties (repository read-only)
6148 6148 * - couldn't import dependents (repository read-only)
6149 6149 * EACCES - couldn't create temporary instance (backend access denied)
6150 6150 * - couldn't import into temporary instance (backend access denied)
6151 6151 * - couldn't upgrade properties (backend access denied)
6152 6152 * - couldn't import properties (backend access denied)
6153 6153 * - couldn't import dependents (backend access denied)
6154 6154 * EINVAL - invalid instance name (error printed)
6155 6155 * - invalid pgroup_t's (error printed)
6156 6156 * - invalid dependents (error printed)
6157 6157 * EBUSY - temporary service deleted (error printed)
6158 6158 * - temporary instance deleted (error printed)
6159 6159 * - temporary instance changed (error printed)
6160 6160 * - temporary instance already exists (error printed)
6161 6161 * - instance deleted (error printed)
6162 6162 * EBADF - instance has corrupt last-import snapshot (error printed)
6163 6163 * - instance is corrupt (error printed)
6164 6164 * - dependent has corrupt pg (error printed)
6165 6165 * - dependent target has a corrupt snapshot (error printed)
6166 6166 * -1 - unknown libscf error (error printed)
6167 6167 */
6168 6168 static int
6169 6169 lscf_instance_import(void *v, void *pvt)
6170 6170 {
6171 6171 entity_t *inst = v;
6172 6172 scf_callback_t ctx;
6173 6173 scf_callback_t *lcbdata = pvt;
6174 6174 scf_service_t *rsvc = lcbdata->sc_parent;
6175 6175 int r;
6176 6176 scf_snaplevel_t *running;
6177 6177 int flags = lcbdata->sc_flags;
6178 6178
6179 6179 const char * const emsg_tdel =
6180 6180 gettext("Temporary instance svc:/%s:%s was deleted.\n");
6181 6181 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6182 6182 "changed unexpectedly.\n");
6183 6183 const char * const emsg_del = gettext("%s changed unexpectedly "
6184 6184 "(instance \"%s\" was deleted.)\n");
6185 6185 const char * const emsg_badsnap = gettext(
6186 6186 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6187 6187
6188 6188 /*
6189 6189 * prepare last-import snapshot:
6190 6190 * create temporary instance (service was precreated)
6191 6191 * populate with properties from bundle
6192 6192 * take snapshot
6193 6193 */
6194 6194 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6195 6195 switch (scf_error()) {
6196 6196 case SCF_ERROR_CONNECTION_BROKEN:
6197 6197 case SCF_ERROR_NO_RESOURCES:
6198 6198 case SCF_ERROR_BACKEND_READONLY:
6199 6199 case SCF_ERROR_BACKEND_ACCESS:
6200 6200 return (stash_scferror(lcbdata));
6201 6201
6202 6202 case SCF_ERROR_EXISTS:
6203 6203 warn(gettext("Temporary service svc:/%s "
6204 6204 "changed unexpectedly (instance \"%s\" added).\n"),
6205 6205 imp_tsname, inst->sc_name);
6206 6206 lcbdata->sc_err = EBUSY;
6207 6207 return (UU_WALK_ERROR);
6208 6208
6209 6209 case SCF_ERROR_DELETED:
6210 6210 warn(gettext("Temporary service svc:/%s "
6211 6211 "was deleted unexpectedly.\n"), imp_tsname);
6212 6212 lcbdata->sc_err = EBUSY;
6213 6213 return (UU_WALK_ERROR);
6214 6214
6215 6215 case SCF_ERROR_INVALID_ARGUMENT:
6216 6216 warn(gettext("Invalid instance name \"%s\".\n"),
6217 6217 inst->sc_name);
6218 6218 return (stash_scferror(lcbdata));
6219 6219
6220 6220 case SCF_ERROR_PERMISSION_DENIED:
6221 6221 warn(gettext("Could not create temporary instance "
6222 6222 "\"%s\" in svc:/%s (permission denied).\n"),
6223 6223 inst->sc_name, imp_tsname);
6224 6224 return (stash_scferror(lcbdata));
6225 6225
6226 6226 case SCF_ERROR_HANDLE_MISMATCH:
6227 6227 case SCF_ERROR_NOT_BOUND:
6228 6228 case SCF_ERROR_NOT_SET:
6229 6229 default:
6230 6230 bad_error("scf_service_add_instance", scf_error());
6231 6231 }
6232 6232 }
6233 6233
6234 6234 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6235 6235 inst->sc_name);
6236 6236 if (r < 0)
6237 6237 bad_error("snprintf", errno);
6238 6238
6239 6239 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6240 6240 lcbdata->sc_flags | SCI_NOENABLED);
6241 6241 switch (r) {
6242 6242 case 0:
6243 6243 break;
6244 6244
6245 6245 case ECANCELED:
6246 6246 warn(emsg_tdel, imp_tsname, inst->sc_name);
6247 6247 lcbdata->sc_err = EBUSY;
6248 6248 r = UU_WALK_ERROR;
6249 6249 goto deltemp;
6250 6250
6251 6251 case EEXIST:
6252 6252 warn(emsg_tchg, imp_tsname, inst->sc_name);
6253 6253 lcbdata->sc_err = EBUSY;
6254 6254 r = UU_WALK_ERROR;
6255 6255 goto deltemp;
6256 6256
6257 6257 case ECONNABORTED:
6258 6258 goto connaborted;
6259 6259
6260 6260 case ENOMEM:
6261 6261 case ENOSPC:
6262 6262 case EPERM:
6263 6263 case EROFS:
6264 6264 case EACCES:
6265 6265 case EINVAL:
6266 6266 case EBUSY:
6267 6267 lcbdata->sc_err = r;
6268 6268 r = UU_WALK_ERROR;
6269 6269 goto deltemp;
6270 6270
6271 6271 default:
6272 6272 bad_error("lscf_import_instance_pgs", r);
6273 6273 }
6274 6274
6275 6275 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6276 6276 inst->sc_name);
6277 6277 if (r < 0)
6278 6278 bad_error("snprintf", errno);
6279 6279
6280 6280 ctx.sc_handle = lcbdata->sc_handle;
6281 6281 ctx.sc_parent = imp_tinst;
6282 6282 ctx.sc_service = 0;
6283 6283 ctx.sc_source_fmri = inst->sc_fmri;
6284 6284 ctx.sc_target_fmri = imp_str;
6285 6285 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6286 6286 UU_DEFAULT) != 0) {
6287 6287 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6288 6288 bad_error("uu_list_walk", uu_error());
6289 6289
6290 6290 switch (ctx.sc_err) {
6291 6291 case ECONNABORTED:
6292 6292 goto connaborted;
6293 6293
6294 6294 case ECANCELED:
6295 6295 warn(emsg_tdel, imp_tsname, inst->sc_name);
6296 6296 lcbdata->sc_err = EBUSY;
6297 6297 break;
6298 6298
6299 6299 case EEXIST:
6300 6300 warn(emsg_tchg, imp_tsname, inst->sc_name);
6301 6301 lcbdata->sc_err = EBUSY;
6302 6302 break;
6303 6303
6304 6304 default:
6305 6305 lcbdata->sc_err = ctx.sc_err;
6306 6306 }
6307 6307 r = UU_WALK_ERROR;
6308 6308 goto deltemp;
6309 6309 }
6310 6310
6311 6311 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6312 6312 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6313 6313 switch (scf_error()) {
6314 6314 case SCF_ERROR_CONNECTION_BROKEN:
6315 6315 goto connaborted;
6316 6316
6317 6317 case SCF_ERROR_NO_RESOURCES:
6318 6318 r = stash_scferror(lcbdata);
6319 6319 goto deltemp;
6320 6320
6321 6321 case SCF_ERROR_EXISTS:
6322 6322 warn(emsg_tchg, imp_tsname, inst->sc_name);
6323 6323 lcbdata->sc_err = EBUSY;
6324 6324 r = UU_WALK_ERROR;
6325 6325 goto deltemp;
6326 6326
6327 6327 case SCF_ERROR_PERMISSION_DENIED:
6328 6328 warn(gettext("Could not take \"%s\" snapshot of %s "
6329 6329 "(permission denied).\n"), snap_lastimport,
6330 6330 imp_str);
6331 6331 r = stash_scferror(lcbdata);
6332 6332 goto deltemp;
6333 6333
6334 6334 default:
6335 6335 scfwarn();
6336 6336 lcbdata->sc_err = -1;
6337 6337 r = UU_WALK_ERROR;
6338 6338 goto deltemp;
6339 6339
6340 6340 case SCF_ERROR_HANDLE_MISMATCH:
6341 6341 case SCF_ERROR_INVALID_ARGUMENT:
6342 6342 case SCF_ERROR_NOT_SET:
6343 6343 bad_error("_scf_snapshot_take_new_named", scf_error());
6344 6344 }
6345 6345 }
6346 6346
6347 6347 if (lcbdata->sc_flags & SCI_FRESH)
6348 6348 goto fresh;
6349 6349
6350 6350 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6351 6351 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6352 6352 imp_lisnap) != 0) {
6353 6353 switch (scf_error()) {
6354 6354 case SCF_ERROR_DELETED:
6355 6355 warn(emsg_del, inst->sc_parent->sc_fmri,
6356 6356 inst->sc_name);
6357 6357 lcbdata->sc_err = EBUSY;
6358 6358 r = UU_WALK_ERROR;
6359 6359 goto deltemp;
6360 6360
6361 6361 case SCF_ERROR_NOT_FOUND:
6362 6362 flags |= SCI_FORCE;
6363 6363 goto nosnap;
6364 6364
6365 6365 case SCF_ERROR_CONNECTION_BROKEN:
6366 6366 goto connaborted;
6367 6367
6368 6368 case SCF_ERROR_INVALID_ARGUMENT:
6369 6369 case SCF_ERROR_HANDLE_MISMATCH:
6370 6370 case SCF_ERROR_NOT_BOUND:
6371 6371 case SCF_ERROR_NOT_SET:
6372 6372 default:
6373 6373 bad_error("scf_instance_get_snapshot",
6374 6374 scf_error());
6375 6375 }
6376 6376 }
6377 6377
6378 6378 /* upgrade */
6379 6379
6380 6380 /*
6381 6381 * compare new properties with last-import properties
6382 6382 * upgrade current properties
6383 6383 */
6384 6384 /* clear sc_sceen for pgs */
6385 6385 if (uu_list_walk(inst->sc_pgroups, clear_int,
6386 6386 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6387 6387 0)
6388 6388 bad_error("uu_list_walk", uu_error());
6389 6389
6390 6390 r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6391 6391 switch (r) {
6392 6392 case 0:
6393 6393 break;
6394 6394
6395 6395 case ECONNABORTED:
6396 6396 goto connaborted;
6397 6397
6398 6398 case ECANCELED:
6399 6399 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6400 6400 lcbdata->sc_err = EBUSY;
6401 6401 r = UU_WALK_ERROR;
6402 6402 goto deltemp;
6403 6403
6404 6404 case ENOENT:
6405 6405 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6406 6406 lcbdata->sc_err = EBADF;
6407 6407 r = UU_WALK_ERROR;
6408 6408 goto deltemp;
6409 6409
6410 6410 default:
6411 6411 bad_error("get_snaplevel", r);
6412 6412 }
6413 6413
6414 6414 if (scf_instance_get_snapshot(imp_inst, snap_running,
6415 6415 imp_rsnap) != 0) {
6416 6416 switch (scf_error()) {
6417 6417 case SCF_ERROR_DELETED:
6418 6418 warn(emsg_del, inst->sc_parent->sc_fmri,
6419 6419 inst->sc_name);
6420 6420 lcbdata->sc_err = EBUSY;
6421 6421 r = UU_WALK_ERROR;
6422 6422 goto deltemp;
6423 6423
6424 6424 case SCF_ERROR_NOT_FOUND:
6425 6425 break;
6426 6426
6427 6427 case SCF_ERROR_CONNECTION_BROKEN:
6428 6428 goto connaborted;
6429 6429
6430 6430 case SCF_ERROR_INVALID_ARGUMENT:
6431 6431 case SCF_ERROR_HANDLE_MISMATCH:
6432 6432 case SCF_ERROR_NOT_BOUND:
6433 6433 case SCF_ERROR_NOT_SET:
6434 6434 default:
6435 6435 bad_error("scf_instance_get_snapshot",
6436 6436 scf_error());
6437 6437 }
6438 6438
6439 6439 running = NULL;
6440 6440 } else {
6441 6441 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6442 6442 switch (r) {
6443 6443 case 0:
6444 6444 running = imp_rsnpl;
6445 6445 break;
6446 6446
6447 6447 case ECONNABORTED:
6448 6448 goto connaborted;
6449 6449
6450 6450 case ECANCELED:
6451 6451 warn(emsg_del, inst->sc_parent->sc_fmri,
6452 6452 inst->sc_name);
6453 6453 lcbdata->sc_err = EBUSY;
6454 6454 r = UU_WALK_ERROR;
6455 6455 goto deltemp;
6456 6456
6457 6457 case ENOENT:
6458 6458 warn(emsg_badsnap, snap_running, inst->sc_fmri);
6459 6459 lcbdata->sc_err = EBADF;
6460 6460 r = UU_WALK_ERROR;
6461 6461 goto deltemp;
6462 6462
6463 6463 default:
6464 6464 bad_error("get_snaplevel", r);
6465 6465 }
6466 6466 }
6467 6467
6468 6468 r = upgrade_props(imp_inst, running, imp_snpl, inst);
6469 6469 switch (r) {
6470 6470 case 0:
6471 6471 break;
6472 6472
6473 6473 case ECANCELED:
6474 6474 case ENODEV:
6475 6475 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6476 6476 lcbdata->sc_err = EBUSY;
6477 6477 r = UU_WALK_ERROR;
6478 6478 goto deltemp;
6479 6479
6480 6480 case ECONNABORTED:
6481 6481 goto connaborted;
6482 6482
6483 6483 case ENOMEM:
6484 6484 case ENOSPC:
6485 6485 case EBADF:
6486 6486 case EBUSY:
6487 6487 case EINVAL:
6488 6488 case EPERM:
6489 6489 case EROFS:
6490 6490 case EACCES:
6491 6491 case EEXIST:
6492 6492 lcbdata->sc_err = r;
6493 6493 r = UU_WALK_ERROR;
6494 6494 goto deltemp;
6495 6495
6496 6496 default:
6497 6497 bad_error("upgrade_props", r);
6498 6498 }
6499 6499
6500 6500 inst->sc_import_state = IMPORT_PROP_DONE;
6501 6501 } else {
6502 6502 switch (scf_error()) {
6503 6503 case SCF_ERROR_CONNECTION_BROKEN:
6504 6504 goto connaborted;
6505 6505
6506 6506 case SCF_ERROR_NOT_FOUND:
6507 6507 break;
6508 6508
6509 6509 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6510 6510 case SCF_ERROR_HANDLE_MISMATCH:
6511 6511 case SCF_ERROR_NOT_BOUND:
6512 6512 case SCF_ERROR_NOT_SET:
6513 6513 default:
6514 6514 bad_error("scf_service_get_instance", scf_error());
6515 6515 }
6516 6516
6517 6517 fresh:
6518 6518 /* create instance */
6519 6519 if (scf_service_add_instance(rsvc, inst->sc_name,
6520 6520 imp_inst) != 0) {
6521 6521 switch (scf_error()) {
6522 6522 case SCF_ERROR_CONNECTION_BROKEN:
6523 6523 goto connaborted;
6524 6524
6525 6525 case SCF_ERROR_NO_RESOURCES:
6526 6526 case SCF_ERROR_BACKEND_READONLY:
6527 6527 case SCF_ERROR_BACKEND_ACCESS:
6528 6528 r = stash_scferror(lcbdata);
6529 6529 goto deltemp;
6530 6530
6531 6531 case SCF_ERROR_EXISTS:
6532 6532 warn(gettext("%s changed unexpectedly "
6533 6533 "(instance \"%s\" added).\n"),
6534 6534 inst->sc_parent->sc_fmri, inst->sc_name);
6535 6535 lcbdata->sc_err = EBUSY;
6536 6536 r = UU_WALK_ERROR;
6537 6537 goto deltemp;
6538 6538
6539 6539 case SCF_ERROR_PERMISSION_DENIED:
6540 6540 warn(gettext("Could not create \"%s\" instance "
6541 6541 "in %s (permission denied).\n"),
6542 6542 inst->sc_name, inst->sc_parent->sc_fmri);
6543 6543 r = stash_scferror(lcbdata);
6544 6544 goto deltemp;
6545 6545
6546 6546 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6547 6547 case SCF_ERROR_HANDLE_MISMATCH:
6548 6548 case SCF_ERROR_NOT_BOUND:
6549 6549 case SCF_ERROR_NOT_SET:
6550 6550 default:
6551 6551 bad_error("scf_service_add_instance",
6552 6552 scf_error());
6553 6553 }
6554 6554 }
6555 6555
6556 6556 nosnap:
6557 6557 /*
6558 6558 * Create a last-import snapshot to serve as an attachment
6559 6559 * point for the real one from the temporary instance. Since
6560 6560 * the contents is irrelevant, take it now, while the instance
6561 6561 * is empty, to minimize svc.configd's work.
6562 6562 */
6563 6563 if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6564 6564 imp_lisnap) != 0) {
6565 6565 switch (scf_error()) {
6566 6566 case SCF_ERROR_CONNECTION_BROKEN:
6567 6567 goto connaborted;
6568 6568
6569 6569 case SCF_ERROR_NO_RESOURCES:
6570 6570 r = stash_scferror(lcbdata);
6571 6571 goto deltemp;
6572 6572
6573 6573 case SCF_ERROR_EXISTS:
6574 6574 warn(gettext("%s changed unexpectedly "
6575 6575 "(snapshot \"%s\" added).\n"),
6576 6576 inst->sc_fmri, snap_lastimport);
6577 6577 lcbdata->sc_err = EBUSY;
6578 6578 r = UU_WALK_ERROR;
6579 6579 goto deltemp;
6580 6580
6581 6581 case SCF_ERROR_PERMISSION_DENIED:
6582 6582 warn(gettext("Could not take \"%s\" snapshot "
6583 6583 "of %s (permission denied).\n"),
6584 6584 snap_lastimport, inst->sc_fmri);
6585 6585 r = stash_scferror(lcbdata);
6586 6586 goto deltemp;
6587 6587
6588 6588 default:
6589 6589 scfwarn();
6590 6590 lcbdata->sc_err = -1;
6591 6591 r = UU_WALK_ERROR;
6592 6592 goto deltemp;
6593 6593
6594 6594 case SCF_ERROR_NOT_SET:
6595 6595 case SCF_ERROR_INTERNAL:
6596 6596 case SCF_ERROR_INVALID_ARGUMENT:
6597 6597 case SCF_ERROR_HANDLE_MISMATCH:
6598 6598 bad_error("_scf_snapshot_take_new",
6599 6599 scf_error());
6600 6600 }
6601 6601 }
6602 6602
6603 6603 if (li_only)
6604 6604 goto lionly;
6605 6605
6606 6606 inst->sc_import_state = IMPORT_PROP_BEGUN;
6607 6607
6608 6608 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6609 6609 flags);
6610 6610 switch (r) {
6611 6611 case 0:
6612 6612 break;
6613 6613
6614 6614 case ECONNABORTED:
6615 6615 goto connaborted;
6616 6616
6617 6617 case ECANCELED:
6618 6618 warn(gettext("%s changed unexpectedly "
6619 6619 "(instance \"%s\" deleted).\n"),
6620 6620 inst->sc_parent->sc_fmri, inst->sc_name);
6621 6621 lcbdata->sc_err = EBUSY;
6622 6622 r = UU_WALK_ERROR;
6623 6623 goto deltemp;
6624 6624
6625 6625 case EEXIST:
6626 6626 warn(gettext("%s changed unexpectedly "
6627 6627 "(property group added).\n"), inst->sc_fmri);
6628 6628 lcbdata->sc_err = EBUSY;
6629 6629 r = UU_WALK_ERROR;
6630 6630 goto deltemp;
6631 6631
6632 6632 default:
6633 6633 lcbdata->sc_err = r;
6634 6634 r = UU_WALK_ERROR;
6635 6635 goto deltemp;
6636 6636
6637 6637 case EINVAL: /* caught above */
6638 6638 bad_error("lscf_import_instance_pgs", r);
6639 6639 }
6640 6640
6641 6641 ctx.sc_parent = imp_inst;
6642 6642 ctx.sc_service = 0;
6643 6643 ctx.sc_trans = NULL;
6644 6644 ctx.sc_flags = 0;
6645 6645 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6646 6646 &ctx, UU_DEFAULT) != 0) {
6647 6647 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6648 6648 bad_error("uu_list_walk", uu_error());
6649 6649
6650 6650 if (ctx.sc_err == ECONNABORTED)
6651 6651 goto connaborted;
6652 6652 lcbdata->sc_err = ctx.sc_err;
6653 6653 r = UU_WALK_ERROR;
6654 6654 goto deltemp;
6655 6655 }
6656 6656
6657 6657 inst->sc_import_state = IMPORT_PROP_DONE;
6658 6658
6659 6659 if (g_verbose)
6660 6660 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6661 6661 snap_initial, inst->sc_fmri);
6662 6662 r = take_snap(imp_inst, snap_initial, imp_snap);
6663 6663 switch (r) {
6664 6664 case 0:
6665 6665 break;
6666 6666
6667 6667 case ECONNABORTED:
6668 6668 goto connaborted;
6669 6669
6670 6670 case ENOSPC:
6671 6671 case -1:
6672 6672 lcbdata->sc_err = r;
6673 6673 r = UU_WALK_ERROR;
6674 6674 goto deltemp;
6675 6675
6676 6676 case ECANCELED:
6677 6677 warn(gettext("%s changed unexpectedly "
6678 6678 "(instance %s deleted).\n"),
6679 6679 inst->sc_parent->sc_fmri, inst->sc_name);
6680 6680 lcbdata->sc_err = r;
6681 6681 r = UU_WALK_ERROR;
6682 6682 goto deltemp;
6683 6683
6684 6684 case EPERM:
6685 6685 warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6686 6686 lcbdata->sc_err = r;
6687 6687 r = UU_WALK_ERROR;
6688 6688 goto deltemp;
6689 6689
6690 6690 default:
6691 6691 bad_error("take_snap", r);
6692 6692 }
6693 6693 }
6694 6694
6695 6695 lionly:
6696 6696 if (lcbdata->sc_flags & SCI_NOSNAP)
6697 6697 goto deltemp;
6698 6698
6699 6699 /* transfer snapshot from temporary instance */
6700 6700 if (g_verbose)
6701 6701 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6702 6702 snap_lastimport, inst->sc_fmri);
6703 6703 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6704 6704 switch (scf_error()) {
6705 6705 case SCF_ERROR_CONNECTION_BROKEN:
6706 6706 goto connaborted;
6707 6707
6708 6708 case SCF_ERROR_NO_RESOURCES:
6709 6709 r = stash_scferror(lcbdata);
6710 6710 goto deltemp;
6711 6711
6712 6712 case SCF_ERROR_PERMISSION_DENIED:
6713 6713 warn(gettext("Could not take \"%s\" snapshot for %s "
6714 6714 "(permission denied).\n"), snap_lastimport,
6715 6715 inst->sc_fmri);
6716 6716 r = stash_scferror(lcbdata);
6717 6717 goto deltemp;
6718 6718
6719 6719 case SCF_ERROR_NOT_SET:
6720 6720 case SCF_ERROR_HANDLE_MISMATCH:
6721 6721 default:
6722 6722 bad_error("_scf_snapshot_attach", scf_error());
6723 6723 }
6724 6724 }
6725 6725
6726 6726 inst->sc_import_state = IMPORT_COMPLETE;
6727 6727
6728 6728 r = UU_WALK_NEXT;
6729 6729
6730 6730 deltemp:
6731 6731 /* delete temporary instance */
6732 6732 if (scf_instance_delete(imp_tinst) != 0) {
6733 6733 switch (scf_error()) {
6734 6734 case SCF_ERROR_DELETED:
6735 6735 break;
6736 6736
6737 6737 case SCF_ERROR_CONNECTION_BROKEN:
6738 6738 goto connaborted;
6739 6739
6740 6740 case SCF_ERROR_NOT_SET:
6741 6741 case SCF_ERROR_NOT_BOUND:
6742 6742 default:
6743 6743 bad_error("scf_instance_delete", scf_error());
6744 6744 }
6745 6745 }
6746 6746
6747 6747 return (r);
6748 6748
6749 6749 connaborted:
6750 6750 warn(gettext("Could not delete svc:/%s:%s "
6751 6751 "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6752 6752 lcbdata->sc_err = ECONNABORTED;
6753 6753 return (UU_WALK_ERROR);
6754 6754 }
6755 6755
6756 6756 /*
6757 6757 * When an instance is imported we end up telling configd about it. Once we tell
6758 6758 * configd about these changes, startd eventually notices. If this is a new
6759 6759 * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6760 6760 * property group. However, many of the other tools expect that this property
6761 6761 * group exists and has certain values.
6762 6762 *
6763 6763 * These values are added asynchronously by startd. We should not return from
6764 6764 * this routine until we can verify that the property group we need is there.
6765 6765 *
6766 6766 * Before we go ahead and verify this, we have to ask ourselves an important
6767 6767 * question: Is the early manifest service currently running? Because if it is
6768 6768 * running and it has invoked us, then the service will never get a restarter
6769 6769 * property because svc.startd is blocked on EMI finishing before it lets itself
6770 6770 * fully connect to svc.configd. Of course, this means that this race condition
6771 6771 * is in fact impossible to 100% eliminate.
6772 6772 *
6773 6773 * svc.startd makes sure that EMI only runs once and has succeeded by checking
6774 6774 * the state of the EMI instance. If it is online it bails out and makes sure
6775 6775 * that it doesn't run again. In this case, we're going to do something similar,
6776 6776 * only if the state is online, then we're going to actually verify. EMI always
6777 6777 * has to be present, but it can be explicitly disabled to reduce the amount of
6778 6778 * damage it can cause. If EMI has been disabled then we no longer have to worry
6779 6779 * about the implicit race condition and can go ahead and check things. If EMI
6780 6780 * is in some state that isn't online or disabled and isn't runinng, then we
6781 6781 * assume that things are rather bad and we're not going to get in your way,
6782 6782 * even if the rest of SMF does.
6783 6783 *
6784 6784 * Returns 0 on success or returns an errno.
6785 6785 */
6786 6786 #ifndef NATIVE_BUILD
6787 6787 static int
6788 6788 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6789 6789 {
6790 6790 int ret, err;
6791 6791 struct timespec ts;
6792 6792 char *emi_state;
6793 6793
6794 6794 /*
6795 6795 * smf_get_state does not distinguish between its different failure
6796 6796 * modes: memory allocation failures, SMF internal failures, and a lack
6797 6797 * of EMI entirely because it's been removed. In these cases, we're
6798 6798 * going to be conservative and opt to say that if we don't know, better
6799 6799 * to not block import or falsely warn to the user.
6800 6800 */
6801 6801 if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
6802 6802 return (0);
6803 6803 }
6804 6804
6805 6805 /*
6806 6806 * As per the block comment for this function check the state of EMI
6807 6807 */
6808 6808 if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6809 6809 strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6810 6810 warn(gettext("Not validating instance %s:%s because EMI's "
6811 6811 "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6812 6812 free(emi_state);
6813 6813 return (0);
6814 6814 }
6815 6815
6816 6816 free(emi_state);
6817 6817
6818 6818 /*
6819 6819 * First we have to get the property.
6820 6820 */
6821 6821 if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6822 6822 ret = scf_error();
6823 6823 warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6824 6824 return (ret);
6825 6825 }
6826 6826
6827 6827 /*
6828 6828 * We should always be able to get the instance. It should already
6829 6829 * exist because we just created it or got it. There probably is a
6830 6830 * slim chance that someone may have come in and deleted it though from
6831 6831 * under us.
6832 6832 */
6833 6833 if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6834 6834 != 0) {
6835 6835 ret = scf_error();
6836 6836 warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6837 6837 switch (ret) {
6838 6838 case SCF_ERROR_DELETED:
6839 6839 err = ENODEV;
6840 6840 break;
6841 6841 case SCF_ERROR_CONNECTION_BROKEN:
6842 6842 warn(gettext("Lost repository connection\n"));
6843 6843 err = ECONNABORTED;
6844 6844 break;
6845 6845 case SCF_ERROR_NOT_FOUND:
6846 6846 warn(gettext("Instance \"%s\" disappeared out from "
6847 6847 "under us.\n"), inst->sc_name);
6848 6848 err = ENOENT;
6849 6849 break;
6850 6850 default:
6851 6851 bad_error("scf_service_get_instance", ret);
6852 6852 }
6853 6853
6854 6854 return (err);
6855 6855 }
6856 6856
6857 6857 /*
6858 6858 * An astute observer may want to use _scf_wait_pg which would notify us
6859 6859 * of a property group change, unfortunately that does not work if the
6860 6860 * property group in question does not exist. So instead we have to
6861 6861 * manually poll and ask smf the best way to get to it.
6862 6862 */
6863 6863 while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6864 6864 != SCF_SUCCESS) {
6865 6865 ret = scf_error();
6866 6866 if (ret != SCF_ERROR_NOT_FOUND) {
6867 6867 warn(gettext("Failed to get restarter property "
6868 6868 "group for instance: %s\n"), inst->sc_name);
6869 6869 switch (ret) {
6870 6870 case SCF_ERROR_DELETED:
6871 6871 err = ENODEV;
6872 6872 break;
6873 6873 case SCF_ERROR_CONNECTION_BROKEN:
6874 6874 warn(gettext("Lost repository connection\n"));
6875 6875 err = ECONNABORTED;
6876 6876 break;
6877 6877 default:
6878 6878 bad_error("scf_service_get_instance", ret);
6879 6879 }
6880 6880
6881 6881 return (err);
6882 6882 }
6883 6883
6884 6884 ts.tv_sec = pg_timeout / NANOSEC;
6885 6885 ts.tv_nsec = pg_timeout % NANOSEC;
6886 6886
6887 6887 (void) nanosleep(&ts, NULL);
6888 6888 }
6889 6889
6890 6890 /*
6891 6891 * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6892 6892 * So in addition to the property group being present, we need to wait
6893 6893 * for the property to be there in some form.
6894 6894 *
6895 6895 * Note that a property group is a frozen snapshot in time. To properly
6896 6896 * get beyond this, you have to refresh the property group each time.
6897 6897 */
6898 6898 while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6899 6899 imp_prop)) != 0) {
6900 6900
6901 6901 ret = scf_error();
6902 6902 if (ret != SCF_ERROR_NOT_FOUND) {
6903 6903 warn(gettext("Failed to get property %s from the "
6904 6904 "restarter property group of instance %s\n"),
6905 6905 SCF_PROPERTY_STATE, inst->sc_name);
6906 6906 switch (ret) {
6907 6907 case SCF_ERROR_CONNECTION_BROKEN:
6908 6908 warn(gettext("Lost repository connection\n"));
6909 6909 err = ECONNABORTED;
6910 6910 break;
6911 6911 case SCF_ERROR_DELETED:
6912 6912 err = ENODEV;
6913 6913 break;
6914 6914 default:
6915 6915 bad_error("scf_pg_get_property", ret);
6916 6916 }
6917 6917
6918 6918 return (err);
6919 6919 }
6920 6920
6921 6921 ts.tv_sec = pg_timeout / NANOSEC;
6922 6922 ts.tv_nsec = pg_timeout % NANOSEC;
6923 6923
6924 6924 (void) nanosleep(&ts, NULL);
6925 6925
6926 6926 ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6927 6927 if (ret != SCF_SUCCESS) {
6928 6928 warn(gettext("Failed to get restarter property "
6929 6929 "group for instance: %s\n"), inst->sc_name);
6930 6930 switch (ret) {
6931 6931 case SCF_ERROR_DELETED:
6932 6932 err = ENODEV;
6933 6933 break;
6934 6934 case SCF_ERROR_CONNECTION_BROKEN:
6935 6935 warn(gettext("Lost repository connection\n"));
6936 6936 err = ECONNABORTED;
6937 6937 break;
6938 6938 default:
6939 6939 bad_error("scf_service_get_instance", ret);
6940 6940 }
6941 6941
6942 6942 return (err);
6943 6943 }
6944 6944 }
6945 6945
6946 6946 /*
6947 6947 * We don't have to free the property groups or other values that we got
6948 6948 * because we stored them in global variables that are allocated and
6949 6949 * freed by the routines that call into these functions. Unless of
6950 6950 * course the rest of the code here that we are basing this on is
6951 6951 * mistaken.
6952 6952 */
6953 6953 return (0);
6954 6954 }
6955 6955 #endif
6956 6956
6957 6957 /*
6958 6958 * If the service is missing, create it, import its properties, and import the
6959 6959 * instances. Since the service is brand new, it should be empty, and if we
6960 6960 * run into any existing entities (SCF_ERROR_EXISTS), abort.
6961 6961 *
6962 6962 * If the service exists, we want to upgrade its properties and import the
6963 6963 * instances. Upgrade requires a last-import snapshot, though, which are
6964 6964 * children of instances, so first we'll have to go through the instances
6965 6965 * looking for a last-import snapshot. If we don't find one then we'll just
6966 6966 * override-import the service properties (but don't delete existing
6967 6967 * properties: another service might have declared us as a dependent). Before
6968 6968 * we change anything, though, we want to take the previous snapshots. We
6969 6969 * also give lscf_instance_import() a leg up on taking last-import snapshots
6970 6970 * by importing the manifest's service properties into a temporary service.
6971 6971 *
6972 6972 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and
6973 6973 * sets lcbdata->sc_err to
6974 6974 * ECONNABORTED - repository connection broken
6975 6975 * ENOMEM - out of memory
6976 6976 * ENOSPC - svc.configd is out of resources
6977 6977 * EPERM - couldn't create temporary service (error printed)
6978 6978 * - couldn't import into temp service (error printed)
6979 6979 * - couldn't create service (error printed)
6980 6980 * - couldn't import dependent (error printed)
6981 6981 * - couldn't take snapshot (error printed)
6982 6982 * - couldn't create instance (error printed)
6983 6983 * - couldn't create, modify, or delete pg (error printed)
6984 6984 * - couldn't create, modify, or delete dependent (error printed)
6985 6985 * - couldn't import instance (error printed)
6986 6986 * EROFS - couldn't create temporary service (repository read-only)
6987 6987 * - couldn't import into temporary service (repository read-only)
6988 6988 * - couldn't create service (repository read-only)
6989 6989 * - couldn't import dependent (repository read-only)
6990 6990 * - couldn't create instance (repository read-only)
6991 6991 * - couldn't create, modify, or delete pg or dependent
6992 6992 * - couldn't import instance (repository read-only)
6993 6993 * EACCES - couldn't create temporary service (backend access denied)
6994 6994 * - couldn't import into temporary service (backend access denied)
6995 6995 * - couldn't create service (backend access denied)
6996 6996 * - couldn't import dependent (backend access denied)
6997 6997 * - couldn't create instance (backend access denied)
6998 6998 * - couldn't create, modify, or delete pg or dependent
6999 6999 * - couldn't import instance (backend access denied)
7000 7000 * EINVAL - service name is invalid (error printed)
7001 7001 * - service name is too long (error printed)
7002 7002 * - s has invalid pgroup (error printed)
7003 7003 * - s has invalid dependent (error printed)
7004 7004 * - instance name is invalid (error printed)
7005 7005 * - instance entity_t is invalid (error printed)
7006 7006 * EEXIST - couldn't create temporary service (already exists) (error printed)
7007 7007 * - couldn't import dependent (dependency pg already exists) (printed)
7008 7008 * - dependency collision in dependent service (error printed)
7009 7009 * EBUSY - temporary service deleted (error printed)
7010 7010 * - property group added to temporary service (error printed)
7011 7011 * - new property group changed or was deleted (error printed)
7012 7012 * - service was added unexpectedly (error printed)
7013 7013 * - service was deleted unexpectedly (error printed)
7014 7014 * - property group added to new service (error printed)
7015 7015 * - instance added unexpectedly (error printed)
7016 7016 * - instance deleted unexpectedly (error printed)
7017 7017 * - dependent service deleted unexpectedly (error printed)
7018 7018 * - pg was added, changed, or deleted (error printed)
7019 7019 * - dependent pg changed (error printed)
7020 7020 * - temporary instance added, changed, or deleted (error printed)
7021 7021 * EBADF - a last-import snapshot is corrupt (error printed)
7022 7022 * - the service is corrupt (error printed)
7023 7023 * - a dependent is corrupt (error printed)
7024 7024 * - an instance is corrupt (error printed)
7025 7025 * - an instance has a corrupt last-import snapshot (error printed)
7026 7026 * - dependent target has a corrupt snapshot (error printed)
7027 7027 * -1 - unknown libscf error (error printed)
7028 7028 */
7029 7029 static int
7030 7030 lscf_service_import(void *v, void *pvt)
7031 7031 {
7032 7032 entity_t *s = v;
7033 7033 scf_callback_t cbdata;
7034 7034 scf_callback_t *lcbdata = pvt;
7035 7035 scf_scope_t *scope = lcbdata->sc_parent;
7036 7036 entity_t *inst, linst;
7037 7037 int r;
7038 7038 int fresh = 0;
7039 7039 scf_snaplevel_t *running;
7040 7040 int have_ge = 0;
7041 7041 boolean_t retried = B_FALSE;
7042 7042
7043 7043 const char * const ts_deleted = gettext("Temporary service svc:/%s "
7044 7044 "was deleted unexpectedly.\n");
7045 7045 const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7046 7046 "changed unexpectedly (property group added).\n");
7047 7047 const char * const s_deleted =
7048 7048 gettext("%s was deleted unexpectedly.\n");
7049 7049 const char * const i_deleted =
7050 7050 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7051 7051 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7052 7052 "is corrupt (missing service snaplevel).\n");
7053 7053 const char * const s_mfile_upd =
7054 7054 gettext("Unable to update the manifest file connection "
7055 7055 "for %s\n");
7056 7056
7057 7057 li_only = 0;
7058 7058 /* Validate the service name */
7059 7059 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7060 7060 switch (scf_error()) {
7061 7061 case SCF_ERROR_CONNECTION_BROKEN:
7062 7062 return (stash_scferror(lcbdata));
7063 7063
7064 7064 case SCF_ERROR_INVALID_ARGUMENT:
7065 7065 warn(gettext("\"%s\" is an invalid service name. "
7066 7066 "Cannot import.\n"), s->sc_name);
7067 7067 return (stash_scferror(lcbdata));
7068 7068
7069 7069 case SCF_ERROR_NOT_FOUND:
7070 7070 break;
7071 7071
7072 7072 case SCF_ERROR_HANDLE_MISMATCH:
7073 7073 case SCF_ERROR_NOT_BOUND:
7074 7074 case SCF_ERROR_NOT_SET:
7075 7075 default:
7076 7076 bad_error("scf_scope_get_service", scf_error());
7077 7077 }
7078 7078 }
7079 7079
7080 7080 /* create temporary service */
7081 7081 /*
7082 7082 * the size of the buffer was reduced to max_scf_name_len to prevent
7083 7083 * hitting bug 6681151. After the bug fix, the size of the buffer
7084 7084 * should be restored to its original value (max_scf_name_len +1)
7085 7085 */
7086 7086 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7087 7087 if (r < 0)
7088 7088 bad_error("snprintf", errno);
7089 7089 if (r > max_scf_name_len) {
7090 7090 warn(gettext(
7091 7091 "Service name \"%s\" is too long. Cannot import.\n"),
7092 7092 s->sc_name);
7093 7093 lcbdata->sc_err = EINVAL;
7094 7094 return (UU_WALK_ERROR);
7095 7095 }
7096 7096
7097 7097 retry:
7098 7098 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7099 7099 switch (scf_error()) {
7100 7100 case SCF_ERROR_CONNECTION_BROKEN:
7101 7101 case SCF_ERROR_NO_RESOURCES:
7102 7102 case SCF_ERROR_BACKEND_READONLY:
7103 7103 case SCF_ERROR_BACKEND_ACCESS:
7104 7104 return (stash_scferror(lcbdata));
7105 7105
7106 7106 case SCF_ERROR_EXISTS:
7107 7107 if (!retried) {
7108 7108 lscf_delete(imp_tsname, 0);
7109 7109 retried = B_TRUE;
7110 7110 goto retry;
7111 7111 }
7112 7112 warn(gettext(
7113 7113 "Temporary service \"%s\" must be deleted before "
7114 7114 "this manifest can be imported.\n"), imp_tsname);
7115 7115 return (stash_scferror(lcbdata));
7116 7116
7117 7117 case SCF_ERROR_PERMISSION_DENIED:
7118 7118 warn(gettext("Could not create temporary service "
7119 7119 "\"%s\" (permission denied).\n"), imp_tsname);
7120 7120 return (stash_scferror(lcbdata));
7121 7121
7122 7122 case SCF_ERROR_INVALID_ARGUMENT:
7123 7123 case SCF_ERROR_HANDLE_MISMATCH:
7124 7124 case SCF_ERROR_NOT_BOUND:
7125 7125 case SCF_ERROR_NOT_SET:
7126 7126 default:
7127 7127 bad_error("scf_scope_add_service", scf_error());
7128 7128 }
7129 7129 }
7130 7130
7131 7131 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7132 7132 if (r < 0)
7133 7133 bad_error("snprintf", errno);
7134 7134
7135 7135 cbdata.sc_handle = lcbdata->sc_handle;
7136 7136 cbdata.sc_parent = imp_tsvc;
7137 7137 cbdata.sc_service = 1;
7138 7138 cbdata.sc_source_fmri = s->sc_fmri;
7139 7139 cbdata.sc_target_fmri = imp_str;
7140 7140 cbdata.sc_flags = 0;
7141 7141
7142 7142 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7143 7143 UU_DEFAULT) != 0) {
7144 7144 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7145 7145 bad_error("uu_list_walk", uu_error());
7146 7146
7147 7147 lcbdata->sc_err = cbdata.sc_err;
7148 7148 switch (cbdata.sc_err) {
7149 7149 case ECONNABORTED:
7150 7150 goto connaborted;
7151 7151
7152 7152 case ECANCELED:
7153 7153 warn(ts_deleted, imp_tsname);
7154 7154 lcbdata->sc_err = EBUSY;
7155 7155 return (UU_WALK_ERROR);
7156 7156
7157 7157 case EEXIST:
7158 7158 warn(ts_pg_added, imp_tsname);
7159 7159 lcbdata->sc_err = EBUSY;
7160 7160 return (UU_WALK_ERROR);
7161 7161 }
7162 7162
7163 7163 r = UU_WALK_ERROR;
7164 7164 goto deltemp;
7165 7165 }
7166 7166
7167 7167 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7168 7168 UU_DEFAULT) != 0) {
7169 7169 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7170 7170 bad_error("uu_list_walk", uu_error());
7171 7171
7172 7172 lcbdata->sc_err = cbdata.sc_err;
7173 7173 switch (cbdata.sc_err) {
7174 7174 case ECONNABORTED:
7175 7175 goto connaborted;
7176 7176
7177 7177 case ECANCELED:
7178 7178 warn(ts_deleted, imp_tsname);
7179 7179 lcbdata->sc_err = EBUSY;
7180 7180 return (UU_WALK_ERROR);
7181 7181
7182 7182 case EEXIST:
7183 7183 warn(ts_pg_added, imp_tsname);
7184 7184 lcbdata->sc_err = EBUSY;
7185 7185 return (UU_WALK_ERROR);
7186 7186 }
7187 7187
7188 7188 r = UU_WALK_ERROR;
7189 7189 goto deltemp;
7190 7190 }
7191 7191
7192 7192 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7193 7193 switch (scf_error()) {
7194 7194 case SCF_ERROR_NOT_FOUND:
7195 7195 break;
7196 7196
7197 7197 case SCF_ERROR_CONNECTION_BROKEN:
7198 7198 goto connaborted;
7199 7199
7200 7200 case SCF_ERROR_INVALID_ARGUMENT:
7201 7201 case SCF_ERROR_HANDLE_MISMATCH:
7202 7202 case SCF_ERROR_NOT_BOUND:
7203 7203 case SCF_ERROR_NOT_SET:
7204 7204 default:
7205 7205 bad_error("scf_scope_get_service", scf_error());
7206 7206 }
7207 7207
7208 7208 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7209 7209 switch (scf_error()) {
7210 7210 case SCF_ERROR_CONNECTION_BROKEN:
7211 7211 goto connaborted;
7212 7212
7213 7213 case SCF_ERROR_NO_RESOURCES:
7214 7214 case SCF_ERROR_BACKEND_READONLY:
7215 7215 case SCF_ERROR_BACKEND_ACCESS:
7216 7216 r = stash_scferror(lcbdata);
7217 7217 goto deltemp;
7218 7218
7219 7219 case SCF_ERROR_EXISTS:
7220 7220 warn(gettext("Scope \"%s\" changed unexpectedly"
7221 7221 " (service \"%s\" added).\n"),
7222 7222 SCF_SCOPE_LOCAL, s->sc_name);
7223 7223 lcbdata->sc_err = EBUSY;
7224 7224 goto deltemp;
7225 7225
7226 7226 case SCF_ERROR_PERMISSION_DENIED:
7227 7227 warn(gettext("Could not create service \"%s\" "
7228 7228 "(permission denied).\n"), s->sc_name);
7229 7229 goto deltemp;
7230 7230
7231 7231 case SCF_ERROR_INVALID_ARGUMENT:
7232 7232 case SCF_ERROR_HANDLE_MISMATCH:
7233 7233 case SCF_ERROR_NOT_BOUND:
7234 7234 case SCF_ERROR_NOT_SET:
7235 7235 default:
7236 7236 bad_error("scf_scope_add_service", scf_error());
7237 7237 }
7238 7238 }
7239 7239
7240 7240 s->sc_import_state = IMPORT_PROP_BEGUN;
7241 7241
7242 7242 /* import service properties */
7243 7243 cbdata.sc_handle = lcbdata->sc_handle;
7244 7244 cbdata.sc_parent = imp_svc;
7245 7245 cbdata.sc_service = 1;
7246 7246 cbdata.sc_flags = lcbdata->sc_flags;
7247 7247 cbdata.sc_source_fmri = s->sc_fmri;
7248 7248 cbdata.sc_target_fmri = s->sc_fmri;
7249 7249
7250 7250 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7251 7251 &cbdata, UU_DEFAULT) != 0) {
7252 7252 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7253 7253 bad_error("uu_list_walk", uu_error());
7254 7254
7255 7255 lcbdata->sc_err = cbdata.sc_err;
7256 7256 switch (cbdata.sc_err) {
7257 7257 case ECONNABORTED:
7258 7258 goto connaborted;
7259 7259
7260 7260 case ECANCELED:
7261 7261 warn(s_deleted, s->sc_fmri);
7262 7262 lcbdata->sc_err = EBUSY;
7263 7263 return (UU_WALK_ERROR);
7264 7264
7265 7265 case EEXIST:
7266 7266 warn(gettext("%s changed unexpectedly "
7267 7267 "(property group added).\n"), s->sc_fmri);
7268 7268 lcbdata->sc_err = EBUSY;
7269 7269 return (UU_WALK_ERROR);
7270 7270
7271 7271 case EINVAL:
7272 7272 /* caught above */
7273 7273 bad_error("entity_pgroup_import",
7274 7274 cbdata.sc_err);
7275 7275 }
7276 7276
7277 7277 r = UU_WALK_ERROR;
7278 7278 goto deltemp;
7279 7279 }
7280 7280
7281 7281 cbdata.sc_trans = NULL;
7282 7282 cbdata.sc_flags = 0;
7283 7283 if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7284 7284 &cbdata, UU_DEFAULT) != 0) {
7285 7285 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7286 7286 bad_error("uu_list_walk", uu_error());
7287 7287
7288 7288 lcbdata->sc_err = cbdata.sc_err;
7289 7289 if (cbdata.sc_err == ECONNABORTED)
7290 7290 goto connaborted;
7291 7291 r = UU_WALK_ERROR;
7292 7292 goto deltemp;
7293 7293 }
7294 7294
7295 7295 s->sc_import_state = IMPORT_PROP_DONE;
7296 7296
7297 7297 /*
7298 7298 * This is a new service, so we can't take previous snapshots
7299 7299 * or upgrade service properties.
7300 7300 */
7301 7301 fresh = 1;
7302 7302 goto instances;
7303 7303 }
7304 7304
7305 7305 /* Clear sc_seen for the instances. */
7306 7306 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7307 7307 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7308 7308 bad_error("uu_list_walk", uu_error());
7309 7309
7310 7310 /*
7311 7311 * Take previous snapshots for all instances. Even for ones not
7312 7312 * mentioned in the bundle, since we might change their service
7313 7313 * properties.
7314 7314 */
7315 7315 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7316 7316 switch (scf_error()) {
7317 7317 case SCF_ERROR_CONNECTION_BROKEN:
7318 7318 goto connaborted;
7319 7319
7320 7320 case SCF_ERROR_DELETED:
7321 7321 warn(s_deleted, s->sc_fmri);
7322 7322 lcbdata->sc_err = EBUSY;
7323 7323 r = UU_WALK_ERROR;
7324 7324 goto deltemp;
7325 7325
7326 7326 case SCF_ERROR_HANDLE_MISMATCH:
7327 7327 case SCF_ERROR_NOT_BOUND:
7328 7328 case SCF_ERROR_NOT_SET:
7329 7329 default:
7330 7330 bad_error("scf_iter_service_instances", scf_error());
7331 7331 }
7332 7332 }
7333 7333
7334 7334 for (;;) {
7335 7335 r = scf_iter_next_instance(imp_iter, imp_inst);
7336 7336 if (r == 0)
7337 7337 break;
7338 7338 if (r != 1) {
7339 7339 switch (scf_error()) {
7340 7340 case SCF_ERROR_DELETED:
7341 7341 warn(s_deleted, s->sc_fmri);
7342 7342 lcbdata->sc_err = EBUSY;
7343 7343 r = UU_WALK_ERROR;
7344 7344 goto deltemp;
7345 7345
7346 7346 case SCF_ERROR_CONNECTION_BROKEN:
7347 7347 goto connaborted;
7348 7348
7349 7349 case SCF_ERROR_NOT_BOUND:
7350 7350 case SCF_ERROR_HANDLE_MISMATCH:
7351 7351 case SCF_ERROR_INVALID_ARGUMENT:
7352 7352 case SCF_ERROR_NOT_SET:
7353 7353 default:
7354 7354 bad_error("scf_iter_next_instance",
7355 7355 scf_error());
7356 7356 }
7357 7357 }
7358 7358
7359 7359 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7360 7360 switch (scf_error()) {
7361 7361 case SCF_ERROR_DELETED:
7362 7362 continue;
7363 7363
7364 7364 case SCF_ERROR_CONNECTION_BROKEN:
7365 7365 goto connaborted;
7366 7366
7367 7367 case SCF_ERROR_NOT_SET:
7368 7368 case SCF_ERROR_NOT_BOUND:
7369 7369 default:
7370 7370 bad_error("scf_instance_get_name", scf_error());
7371 7371 }
7372 7372 }
7373 7373
7374 7374 if (g_verbose)
7375 7375 warn(gettext(
7376 7376 "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7377 7377 snap_previous, s->sc_name, imp_str);
7378 7378
7379 7379 r = take_snap(imp_inst, snap_previous, imp_snap);
7380 7380 switch (r) {
7381 7381 case 0:
7382 7382 break;
7383 7383
7384 7384 case ECANCELED:
7385 7385 continue;
7386 7386
7387 7387 case ECONNABORTED:
7388 7388 goto connaborted;
7389 7389
7390 7390 case EPERM:
7391 7391 warn(gettext("Could not take \"%s\" snapshot of "
7392 7392 "svc:/%s:%s (permission denied).\n"),
7393 7393 snap_previous, s->sc_name, imp_str);
7394 7394 lcbdata->sc_err = r;
7395 7395 return (UU_WALK_ERROR);
7396 7396
7397 7397 case ENOSPC:
7398 7398 case -1:
7399 7399 lcbdata->sc_err = r;
7400 7400 r = UU_WALK_ERROR;
7401 7401 goto deltemp;
7402 7402
7403 7403 default:
7404 7404 bad_error("take_snap", r);
7405 7405 }
7406 7406
7407 7407 linst.sc_name = imp_str;
7408 7408 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7409 7409 &linst, NULL, NULL);
7410 7410 if (inst != NULL) {
7411 7411 inst->sc_import_state = IMPORT_PREVIOUS;
7412 7412 inst->sc_seen = 1;
7413 7413 }
7414 7414 }
7415 7415
7416 7416 /*
7417 7417 * Create the new instances and take previous snapshots of
7418 7418 * them. This is not necessary, but it maximizes data preservation.
7419 7419 */
7420 7420 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7421 7421 inst != NULL;
7422 7422 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7423 7423 inst)) {
7424 7424 if (inst->sc_seen)
7425 7425 continue;
7426 7426
7427 7427 if (scf_service_add_instance(imp_svc, inst->sc_name,
7428 7428 imp_inst) != 0) {
7429 7429 switch (scf_error()) {
7430 7430 case SCF_ERROR_CONNECTION_BROKEN:
7431 7431 goto connaborted;
7432 7432
7433 7433 case SCF_ERROR_BACKEND_READONLY:
7434 7434 case SCF_ERROR_BACKEND_ACCESS:
7435 7435 case SCF_ERROR_NO_RESOURCES:
7436 7436 r = stash_scferror(lcbdata);
7437 7437 goto deltemp;
7438 7438
7439 7439 case SCF_ERROR_EXISTS:
7440 7440 warn(gettext("%s changed unexpectedly "
7441 7441 "(instance \"%s\" added).\n"), s->sc_fmri,
7442 7442 inst->sc_name);
7443 7443 lcbdata->sc_err = EBUSY;
7444 7444 r = UU_WALK_ERROR;
7445 7445 goto deltemp;
7446 7446
7447 7447 case SCF_ERROR_INVALID_ARGUMENT:
7448 7448 warn(gettext("Service \"%s\" has instance with "
7449 7449 "invalid name \"%s\".\n"), s->sc_name,
7450 7450 inst->sc_name);
7451 7451 r = stash_scferror(lcbdata);
7452 7452 goto deltemp;
7453 7453
7454 7454 case SCF_ERROR_PERMISSION_DENIED:
7455 7455 warn(gettext("Could not create instance \"%s\" "
7456 7456 "in %s (permission denied).\n"),
7457 7457 inst->sc_name, s->sc_fmri);
7458 7458 r = stash_scferror(lcbdata);
7459 7459 goto deltemp;
7460 7460
7461 7461 case SCF_ERROR_HANDLE_MISMATCH:
7462 7462 case SCF_ERROR_NOT_BOUND:
7463 7463 case SCF_ERROR_NOT_SET:
7464 7464 default:
7465 7465 bad_error("scf_service_add_instance",
7466 7466 scf_error());
7467 7467 }
7468 7468 }
7469 7469
7470 7470 if (g_verbose)
7471 7471 warn(gettext("Taking \"%s\" snapshot for "
7472 7472 "new service %s.\n"), snap_previous, inst->sc_fmri);
7473 7473 r = take_snap(imp_inst, snap_previous, imp_snap);
7474 7474 switch (r) {
7475 7475 case 0:
7476 7476 break;
7477 7477
7478 7478 case ECANCELED:
7479 7479 warn(i_deleted, s->sc_fmri, inst->sc_name);
7480 7480 lcbdata->sc_err = EBUSY;
7481 7481 r = UU_WALK_ERROR;
7482 7482 goto deltemp;
7483 7483
7484 7484 case ECONNABORTED:
7485 7485 goto connaborted;
7486 7486
7487 7487 case EPERM:
7488 7488 warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7489 7489 lcbdata->sc_err = r;
7490 7490 r = UU_WALK_ERROR;
7491 7491 goto deltemp;
7492 7492
7493 7493 case ENOSPC:
7494 7494 case -1:
7495 7495 r = UU_WALK_ERROR;
7496 7496 goto deltemp;
7497 7497
7498 7498 default:
7499 7499 bad_error("take_snap", r);
7500 7500 }
7501 7501 }
7502 7502
7503 7503 s->sc_import_state = IMPORT_PREVIOUS;
7504 7504
7505 7505 /*
7506 7506 * Upgrade service properties, if we can find a last-import snapshot.
7507 7507 * Any will do because we don't support different service properties
7508 7508 * in different manifests, so all snaplevels of the service in all of
7509 7509 * the last-import snapshots of the instances should be the same.
7510 7510 */
7511 7511 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7512 7512 switch (scf_error()) {
7513 7513 case SCF_ERROR_CONNECTION_BROKEN:
7514 7514 goto connaborted;
7515 7515
7516 7516 case SCF_ERROR_DELETED:
7517 7517 warn(s_deleted, s->sc_fmri);
7518 7518 lcbdata->sc_err = EBUSY;
7519 7519 r = UU_WALK_ERROR;
7520 7520 goto deltemp;
7521 7521
7522 7522 case SCF_ERROR_HANDLE_MISMATCH:
7523 7523 case SCF_ERROR_NOT_BOUND:
7524 7524 case SCF_ERROR_NOT_SET:
7525 7525 default:
7526 7526 bad_error("scf_iter_service_instances", scf_error());
7527 7527 }
7528 7528 }
7529 7529
7530 7530 for (;;) {
7531 7531 r = scf_iter_next_instance(imp_iter, imp_inst);
7532 7532 if (r == -1) {
7533 7533 switch (scf_error()) {
7534 7534 case SCF_ERROR_DELETED:
7535 7535 warn(s_deleted, s->sc_fmri);
7536 7536 lcbdata->sc_err = EBUSY;
7537 7537 r = UU_WALK_ERROR;
7538 7538 goto deltemp;
7539 7539
7540 7540 case SCF_ERROR_CONNECTION_BROKEN:
7541 7541 goto connaborted;
7542 7542
7543 7543 case SCF_ERROR_NOT_BOUND:
7544 7544 case SCF_ERROR_HANDLE_MISMATCH:
7545 7545 case SCF_ERROR_INVALID_ARGUMENT:
7546 7546 case SCF_ERROR_NOT_SET:
7547 7547 default:
7548 7548 bad_error("scf_iter_next_instance",
7549 7549 scf_error());
7550 7550 }
7551 7551 }
7552 7552
7553 7553 if (r == 0) {
7554 7554 /*
7555 7555 * Didn't find any last-import snapshots. Override-
7556 7556 * import the properties. Unless one of the instances
7557 7557 * has a general/enabled property, in which case we're
7558 7558 * probably running a last-import-capable svccfg for
7559 7559 * the first time, and we should only take the
7560 7560 * last-import snapshot.
7561 7561 */
7562 7562 if (have_ge) {
7563 7563 pgroup_t *mfpg;
7564 7564 scf_callback_t mfcbdata;
7565 7565
7566 7566 li_only = 1;
7567 7567 no_refresh = 1;
7568 7568 /*
7569 7569 * Need to go ahead and import the manifestfiles
7570 7570 * pg if it exists. If the last-import snapshot
7571 7571 * upgrade code is ever removed this code can
7572 7572 * be removed as well.
7573 7573 */
7574 7574 mfpg = internal_pgroup_find(s,
7575 7575 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7576 7576
7577 7577 if (mfpg) {
7578 7578 mfcbdata.sc_handle = g_hndl;
7579 7579 mfcbdata.sc_parent = imp_svc;
7580 7580 mfcbdata.sc_service = 1;
7581 7581 mfcbdata.sc_flags = SCI_FORCE;
7582 7582 mfcbdata.sc_source_fmri = s->sc_fmri;
7583 7583 mfcbdata.sc_target_fmri = s->sc_fmri;
7584 7584 if (entity_pgroup_import(mfpg,
7585 7585 &mfcbdata) != UU_WALK_NEXT) {
7586 7586 warn(s_mfile_upd, s->sc_fmri);
7587 7587 r = UU_WALK_ERROR;
7588 7588 goto deltemp;
7589 7589 }
7590 7590 }
7591 7591 break;
7592 7592 }
7593 7593
7594 7594 s->sc_import_state = IMPORT_PROP_BEGUN;
7595 7595
7596 7596 cbdata.sc_handle = g_hndl;
7597 7597 cbdata.sc_parent = imp_svc;
7598 7598 cbdata.sc_service = 1;
7599 7599 cbdata.sc_flags = SCI_FORCE;
7600 7600 cbdata.sc_source_fmri = s->sc_fmri;
7601 7601 cbdata.sc_target_fmri = s->sc_fmri;
7602 7602 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7603 7603 &cbdata, UU_DEFAULT) != 0) {
7604 7604 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7605 7605 bad_error("uu_list_walk", uu_error());
7606 7606 lcbdata->sc_err = cbdata.sc_err;
7607 7607 switch (cbdata.sc_err) {
7608 7608 case ECONNABORTED:
7609 7609 goto connaborted;
7610 7610
7611 7611 case ECANCELED:
7612 7612 warn(s_deleted, s->sc_fmri);
7613 7613 lcbdata->sc_err = EBUSY;
7614 7614 break;
7615 7615
7616 7616 case EINVAL: /* caught above */
7617 7617 case EEXIST:
7618 7618 bad_error("entity_pgroup_import",
7619 7619 cbdata.sc_err);
7620 7620 }
7621 7621
7622 7622 r = UU_WALK_ERROR;
7623 7623 goto deltemp;
7624 7624 }
7625 7625
7626 7626 cbdata.sc_trans = NULL;
7627 7627 cbdata.sc_flags = 0;
7628 7628 if (uu_list_walk(s->sc_dependents,
7629 7629 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7630 7630 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7631 7631 bad_error("uu_list_walk", uu_error());
7632 7632 lcbdata->sc_err = cbdata.sc_err;
7633 7633 if (cbdata.sc_err == ECONNABORTED)
7634 7634 goto connaborted;
7635 7635 r = UU_WALK_ERROR;
7636 7636 goto deltemp;
7637 7637 }
7638 7638 break;
7639 7639 }
7640 7640
7641 7641 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7642 7642 imp_snap) != 0) {
7643 7643 switch (scf_error()) {
7644 7644 case SCF_ERROR_DELETED:
7645 7645 continue;
7646 7646
7647 7647 case SCF_ERROR_NOT_FOUND:
7648 7648 break;
7649 7649
7650 7650 case SCF_ERROR_CONNECTION_BROKEN:
7651 7651 goto connaborted;
7652 7652
7653 7653 case SCF_ERROR_HANDLE_MISMATCH:
7654 7654 case SCF_ERROR_NOT_BOUND:
7655 7655 case SCF_ERROR_INVALID_ARGUMENT:
7656 7656 case SCF_ERROR_NOT_SET:
7657 7657 default:
7658 7658 bad_error("scf_instance_get_snapshot",
7659 7659 scf_error());
7660 7660 }
7661 7661
7662 7662 if (have_ge)
7663 7663 continue;
7664 7664
7665 7665 /*
7666 7666 * Check for a general/enabled property. This is how
7667 7667 * we tell whether to import if there turn out to be
7668 7668 * no last-import snapshots.
7669 7669 */
7670 7670 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7671 7671 imp_pg) == 0) {
7672 7672 if (scf_pg_get_property(imp_pg,
7673 7673 SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7674 7674 have_ge = 1;
7675 7675 } else {
7676 7676 switch (scf_error()) {
7677 7677 case SCF_ERROR_DELETED:
7678 7678 case SCF_ERROR_NOT_FOUND:
7679 7679 continue;
7680 7680
7681 7681 case SCF_ERROR_INVALID_ARGUMENT:
7682 7682 case SCF_ERROR_HANDLE_MISMATCH:
7683 7683 case SCF_ERROR_CONNECTION_BROKEN:
7684 7684 case SCF_ERROR_NOT_BOUND:
7685 7685 case SCF_ERROR_NOT_SET:
7686 7686 default:
7687 7687 bad_error("scf_pg_get_property",
7688 7688 scf_error());
7689 7689 }
7690 7690 }
7691 7691 } else {
7692 7692 switch (scf_error()) {
7693 7693 case SCF_ERROR_DELETED:
7694 7694 case SCF_ERROR_NOT_FOUND:
7695 7695 continue;
7696 7696
7697 7697 case SCF_ERROR_CONNECTION_BROKEN:
7698 7698 goto connaborted;
7699 7699
7700 7700 case SCF_ERROR_NOT_BOUND:
7701 7701 case SCF_ERROR_NOT_SET:
7702 7702 case SCF_ERROR_INVALID_ARGUMENT:
7703 7703 case SCF_ERROR_HANDLE_MISMATCH:
7704 7704 default:
7705 7705 bad_error("scf_instance_get_pg",
7706 7706 scf_error());
7707 7707 }
7708 7708 }
7709 7709 continue;
7710 7710 }
7711 7711
7712 7712 /* find service snaplevel */
7713 7713 r = get_snaplevel(imp_snap, 1, imp_snpl);
7714 7714 switch (r) {
7715 7715 case 0:
7716 7716 break;
7717 7717
7718 7718 case ECONNABORTED:
7719 7719 goto connaborted;
7720 7720
7721 7721 case ECANCELED:
7722 7722 continue;
7723 7723
7724 7724 case ENOENT:
7725 7725 if (scf_instance_get_name(imp_inst, imp_str,
7726 7726 imp_str_sz) < 0)
7727 7727 (void) strcpy(imp_str, "?");
7728 7728 warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7729 7729 lcbdata->sc_err = EBADF;
7730 7730 r = UU_WALK_ERROR;
7731 7731 goto deltemp;
7732 7732
7733 7733 default:
7734 7734 bad_error("get_snaplevel", r);
7735 7735 }
7736 7736
7737 7737 if (scf_instance_get_snapshot(imp_inst, snap_running,
7738 7738 imp_rsnap) != 0) {
7739 7739 switch (scf_error()) {
7740 7740 case SCF_ERROR_DELETED:
7741 7741 continue;
7742 7742
7743 7743 case SCF_ERROR_NOT_FOUND:
7744 7744 break;
7745 7745
7746 7746 case SCF_ERROR_CONNECTION_BROKEN:
7747 7747 goto connaborted;
7748 7748
7749 7749 case SCF_ERROR_INVALID_ARGUMENT:
7750 7750 case SCF_ERROR_HANDLE_MISMATCH:
7751 7751 case SCF_ERROR_NOT_BOUND:
7752 7752 case SCF_ERROR_NOT_SET:
7753 7753 default:
7754 7754 bad_error("scf_instance_get_snapshot",
7755 7755 scf_error());
7756 7756 }
7757 7757 running = NULL;
7758 7758 } else {
7759 7759 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7760 7760 switch (r) {
7761 7761 case 0:
7762 7762 running = imp_rsnpl;
7763 7763 break;
7764 7764
7765 7765 case ECONNABORTED:
7766 7766 goto connaborted;
7767 7767
7768 7768 case ECANCELED:
7769 7769 continue;
7770 7770
7771 7771 case ENOENT:
7772 7772 if (scf_instance_get_name(imp_inst, imp_str,
7773 7773 imp_str_sz) < 0)
7774 7774 (void) strcpy(imp_str, "?");
7775 7775 warn(badsnap, snap_running, s->sc_name,
7776 7776 imp_str);
7777 7777 lcbdata->sc_err = EBADF;
7778 7778 r = UU_WALK_ERROR;
7779 7779 goto deltemp;
7780 7780
7781 7781 default:
7782 7782 bad_error("get_snaplevel", r);
7783 7783 }
7784 7784 }
7785 7785
7786 7786 if (g_verbose) {
7787 7787 if (scf_instance_get_name(imp_inst, imp_str,
7788 7788 imp_str_sz) < 0)
7789 7789 (void) strcpy(imp_str, "?");
7790 7790 warn(gettext("Upgrading properties of %s according to "
7791 7791 "instance \"%s\".\n"), s->sc_fmri, imp_str);
7792 7792 }
7793 7793
7794 7794 /* upgrade service properties */
7795 7795 r = upgrade_props(imp_svc, running, imp_snpl, s);
7796 7796 if (r == 0)
7797 7797 break;
7798 7798
7799 7799 switch (r) {
7800 7800 case ECONNABORTED:
7801 7801 goto connaborted;
7802 7802
7803 7803 case ECANCELED:
7804 7804 warn(s_deleted, s->sc_fmri);
7805 7805 lcbdata->sc_err = EBUSY;
7806 7806 break;
7807 7807
7808 7808 case ENODEV:
7809 7809 if (scf_instance_get_name(imp_inst, imp_str,
7810 7810 imp_str_sz) < 0)
7811 7811 (void) strcpy(imp_str, "?");
7812 7812 warn(i_deleted, s->sc_fmri, imp_str);
7813 7813 lcbdata->sc_err = EBUSY;
7814 7814 break;
7815 7815
7816 7816 default:
7817 7817 lcbdata->sc_err = r;
7818 7818 }
7819 7819
7820 7820 r = UU_WALK_ERROR;
7821 7821 goto deltemp;
7822 7822 }
7823 7823
7824 7824 s->sc_import_state = IMPORT_PROP_DONE;
7825 7825
7826 7826 instances:
7827 7827 /* import instances */
7828 7828 cbdata.sc_handle = lcbdata->sc_handle;
7829 7829 cbdata.sc_parent = imp_svc;
7830 7830 cbdata.sc_service = 1;
7831 7831 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7832 7832 cbdata.sc_general = NULL;
7833 7833
7834 7834 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7835 7835 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7836 7836 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7837 7837 bad_error("uu_list_walk", uu_error());
7838 7838
7839 7839 lcbdata->sc_err = cbdata.sc_err;
7840 7840 if (cbdata.sc_err == ECONNABORTED)
7841 7841 goto connaborted;
7842 7842 r = UU_WALK_ERROR;
7843 7843 goto deltemp;
7844 7844 }
7845 7845
7846 7846 s->sc_import_state = IMPORT_COMPLETE;
7847 7847 r = UU_WALK_NEXT;
7848 7848
7849 7849 deltemp:
7850 7850 /* delete temporary service */
7851 7851 if (scf_service_delete(imp_tsvc) != 0) {
7852 7852 switch (scf_error()) {
7853 7853 case SCF_ERROR_DELETED:
7854 7854 break;
7855 7855
7856 7856 case SCF_ERROR_CONNECTION_BROKEN:
7857 7857 goto connaborted;
7858 7858
7859 7859 case SCF_ERROR_EXISTS:
7860 7860 warn(gettext(
7861 7861 "Could not delete svc:/%s (instances exist).\n"),
7862 7862 imp_tsname);
7863 7863 break;
7864 7864
7865 7865 case SCF_ERROR_NOT_SET:
7866 7866 case SCF_ERROR_NOT_BOUND:
7867 7867 default:
7868 7868 bad_error("scf_service_delete", scf_error());
7869 7869 }
7870 7870 }
7871 7871
7872 7872 return (r);
7873 7873
7874 7874 connaborted:
7875 7875 warn(gettext("Could not delete svc:/%s "
7876 7876 "(repository connection broken).\n"), imp_tsname);
7877 7877 lcbdata->sc_err = ECONNABORTED;
7878 7878 return (UU_WALK_ERROR);
7879 7879 }
7880 7880
7881 7881 static const char *
7882 7882 import_progress(int st)
7883 7883 {
7884 7884 switch (st) {
7885 7885 case 0:
7886 7886 return (gettext("not reached."));
7887 7887
7888 7888 case IMPORT_PREVIOUS:
7889 7889 return (gettext("previous snapshot taken."));
7890 7890
7891 7891 case IMPORT_PROP_BEGUN:
7892 7892 return (gettext("some properties imported."));
7893 7893
7894 7894 case IMPORT_PROP_DONE:
7895 7895 return (gettext("properties imported."));
7896 7896
7897 7897 case IMPORT_COMPLETE:
7898 7898 return (gettext("imported."));
7899 7899
7900 7900 case IMPORT_REFRESHED:
7901 7901 return (gettext("refresh requested."));
7902 7902
7903 7903 default:
7904 7904 #ifndef NDEBUG
7905 7905 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7906 7906 __FILE__, __LINE__, st);
7907 7907 #endif
7908 7908 abort();
7909 7909 /* NOTREACHED */
7910 7910 }
7911 7911 }
7912 7912
7913 7913 /*
7914 7914 * Returns
7915 7915 * 0 - success
7916 7916 * - fmri wasn't found (error printed)
7917 7917 * - entity was deleted (error printed)
7918 7918 * - backend denied access (error printed)
7919 7919 * ENOMEM - out of memory (error printed)
7920 7920 * ECONNABORTED - repository connection broken (error printed)
7921 7921 * EPERM - permission denied (error printed)
7922 7922 * -1 - unknown libscf error (error printed)
7923 7923 */
7924 7924 static int
7925 7925 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7926 7926 {
7927 7927 scf_error_t serr;
7928 7928 void *ent;
7929 7929 int issvc;
7930 7930 int r;
7931 7931
7932 7932 const char *deleted = gettext("Could not refresh %s (deleted).\n");
7933 7933 const char *dpt_deleted = gettext("Could not refresh %s "
7934 7934 "(dependent \"%s\" of %s) (deleted).\n");
7935 7935
7936 7936 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7937 7937 switch (serr) {
7938 7938 case SCF_ERROR_NONE:
7939 7939 break;
7940 7940
7941 7941 case SCF_ERROR_NO_MEMORY:
7942 7942 if (name == NULL)
7943 7943 warn(gettext("Could not refresh %s (out of memory).\n"),
7944 7944 fmri);
7945 7945 else
7946 7946 warn(gettext("Could not refresh %s "
7947 7947 "(dependent \"%s\" of %s) (out of memory).\n"),
7948 7948 fmri, name, d_fmri);
7949 7949 return (ENOMEM);
7950 7950
7951 7951 case SCF_ERROR_NOT_FOUND:
7952 7952 if (name == NULL)
7953 7953 warn(deleted, fmri);
7954 7954 else
7955 7955 warn(dpt_deleted, fmri, name, d_fmri);
7956 7956 return (0);
7957 7957
7958 7958 case SCF_ERROR_INVALID_ARGUMENT:
7959 7959 case SCF_ERROR_CONSTRAINT_VIOLATED:
7960 7960 default:
7961 7961 bad_error("fmri_to_entity", serr);
7962 7962 }
7963 7963
7964 7964 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7965 7965 switch (r) {
7966 7966 case 0:
7967 7967 break;
7968 7968
7969 7969 case ECONNABORTED:
7970 7970 if (name != NULL)
7971 7971 warn(gettext("Could not refresh %s "
7972 7972 "(dependent \"%s\" of %s) "
7973 7973 "(repository connection broken).\n"), fmri, name,
7974 7974 d_fmri);
7975 7975 return (r);
7976 7976
7977 7977 case ECANCELED:
7978 7978 if (name == NULL)
7979 7979 warn(deleted, fmri);
7980 7980 else
7981 7981 warn(dpt_deleted, fmri, name, d_fmri);
7982 7982 return (0);
7983 7983
7984 7984 case EACCES:
7985 7985 if (!g_verbose)
7986 7986 return (0);
7987 7987 if (name == NULL)
7988 7988 warn(gettext("Could not refresh %s "
7989 7989 "(backend access denied).\n"), fmri);
7990 7990 else
7991 7991 warn(gettext("Could not refresh %s "
7992 7992 "(dependent \"%s\" of %s) "
7993 7993 "(backend access denied).\n"), fmri, name, d_fmri);
7994 7994 return (0);
7995 7995
7996 7996 case EPERM:
7997 7997 if (name == NULL)
7998 7998 warn(gettext("Could not refresh %s "
7999 7999 "(permission denied).\n"), fmri);
8000 8000 else
8001 8001 warn(gettext("Could not refresh %s "
8002 8002 "(dependent \"%s\" of %s) "
8003 8003 "(permission denied).\n"), fmri, name, d_fmri);
8004 8004 return (r);
8005 8005
8006 8006 case ENOSPC:
8007 8007 if (name == NULL)
8008 8008 warn(gettext("Could not refresh %s "
8009 8009 "(repository server out of resources).\n"),
8010 8010 fmri);
8011 8011 else
8012 8012 warn(gettext("Could not refresh %s "
8013 8013 "(dependent \"%s\" of %s) "
8014 8014 "(repository server out of resources).\n"),
8015 8015 fmri, name, d_fmri);
8016 8016 return (r);
8017 8017
8018 8018 case -1:
8019 8019 scfwarn();
8020 8020 return (r);
8021 8021
8022 8022 default:
8023 8023 bad_error("refresh_entity", r);
8024 8024 }
8025 8025
8026 8026 if (issvc)
8027 8027 scf_service_destroy(ent);
8028 8028 else
8029 8029 scf_instance_destroy(ent);
8030 8030
8031 8031 return (0);
8032 8032 }
8033 8033
8034 8034 static int
8035 8035 alloc_imp_globals()
8036 8036 {
8037 8037 int r;
8038 8038
8039 8039 const char * const emsg_nomem = gettext("Out of memory.\n");
8040 8040 const char * const emsg_nores =
8041 8041 gettext("svc.configd is out of resources.\n");
8042 8042
8043 8043 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8044 8044 max_scf_name_len : max_scf_fmri_len) + 1;
8045 8045
8046 8046 if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8047 8047 (imp_svc = scf_service_create(g_hndl)) == NULL ||
8048 8048 (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8049 8049 (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8050 8050 (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8051 8051 (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8052 8052 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8053 8053 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8054 8054 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8055 8055 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8056 8056 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8057 8057 (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8058 8058 (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8059 8059 (imp_prop = scf_property_create(g_hndl)) == NULL ||
8060 8060 (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8061 8061 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8062 8062 (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8063 8063 (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8064 8064 (imp_str = malloc(imp_str_sz)) == NULL ||
8065 8065 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8066 8066 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8067 8067 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8068 8068 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8069 8069 (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8070 8070 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8071 8071 (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8072 8072 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8073 8073 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8074 8074 (ud_prop = scf_property_create(g_hndl)) == NULL ||
8075 8075 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8076 8076 (ud_val = scf_value_create(g_hndl)) == NULL ||
8077 8077 (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8078 8078 (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8079 8079 (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8080 8080 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8081 8081 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8082 8082 (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8083 8083 if (scf_error() == SCF_ERROR_NO_RESOURCES)
8084 8084 warn(emsg_nores);
8085 8085 else
8086 8086 warn(emsg_nomem);
8087 8087
8088 8088 return (-1);
8089 8089 }
8090 8090
8091 8091 r = load_init();
8092 8092 switch (r) {
8093 8093 case 0:
8094 8094 break;
8095 8095
8096 8096 case ENOMEM:
8097 8097 warn(emsg_nomem);
8098 8098 return (-1);
8099 8099
8100 8100 default:
8101 8101 bad_error("load_init", r);
8102 8102 }
8103 8103
8104 8104 return (0);
8105 8105 }
8106 8106
8107 8107 static void
8108 8108 free_imp_globals()
8109 8109 {
8110 8110 pgroup_t *old_dpt;
8111 8111 void *cookie;
8112 8112
8113 8113 load_fini();
8114 8114
8115 8115 free(ud_ctarg);
8116 8116 free(ud_oldtarg);
8117 8117 free(ud_name);
8118 8118 ud_ctarg = ud_oldtarg = ud_name = NULL;
8119 8119
8120 8120 scf_transaction_destroy(ud_tx);
8121 8121 ud_tx = NULL;
8122 8122 scf_iter_destroy(ud_iter);
8123 8123 scf_iter_destroy(ud_iter2);
8124 8124 ud_iter = ud_iter2 = NULL;
8125 8125 scf_value_destroy(ud_val);
8126 8126 ud_val = NULL;
8127 8127 scf_property_destroy(ud_prop);
8128 8128 scf_property_destroy(ud_dpt_prop);
8129 8129 ud_prop = ud_dpt_prop = NULL;
8130 8130 scf_pg_destroy(ud_pg);
8131 8131 scf_pg_destroy(ud_cur_depts_pg);
8132 8132 scf_pg_destroy(ud_run_dpts_pg);
8133 8133 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8134 8134 scf_snaplevel_destroy(ud_snpl);
8135 8135 ud_snpl = NULL;
8136 8136 scf_instance_destroy(ud_inst);
8137 8137 ud_inst = NULL;
8138 8138
8139 8139 free(imp_str);
8140 8140 free(imp_tsname);
8141 8141 free(imp_fe1);
8142 8142 free(imp_fe2);
8143 8143 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8144 8144
8145 8145 cookie = NULL;
8146 8146 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8147 8147 NULL) {
8148 8148 free((char *)old_dpt->sc_pgroup_name);
8149 8149 free((char *)old_dpt->sc_pgroup_fmri);
8150 8150 internal_pgroup_free(old_dpt);
8151 8151 }
8152 8152 uu_list_destroy(imp_deleted_dpts);
8153 8153
8154 8154 scf_transaction_destroy(imp_tx);
8155 8155 imp_tx = NULL;
8156 8156 scf_iter_destroy(imp_iter);
8157 8157 scf_iter_destroy(imp_rpg_iter);
8158 8158 scf_iter_destroy(imp_up_iter);
8159 8159 imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8160 8160 scf_property_destroy(imp_prop);
8161 8161 imp_prop = NULL;
8162 8162 scf_pg_destroy(imp_pg);
8163 8163 scf_pg_destroy(imp_pg2);
8164 8164 imp_pg = imp_pg2 = NULL;
8165 8165 scf_snaplevel_destroy(imp_snpl);
8166 8166 scf_snaplevel_destroy(imp_rsnpl);
8167 8167 imp_snpl = imp_rsnpl = NULL;
8168 8168 scf_snapshot_destroy(imp_snap);
8169 8169 scf_snapshot_destroy(imp_lisnap);
8170 8170 scf_snapshot_destroy(imp_tlisnap);
8171 8171 scf_snapshot_destroy(imp_rsnap);
8172 8172 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8173 8173 scf_instance_destroy(imp_inst);
8174 8174 scf_instance_destroy(imp_tinst);
8175 8175 imp_inst = imp_tinst = NULL;
8176 8176 scf_service_destroy(imp_svc);
8177 8177 scf_service_destroy(imp_tsvc);
8178 8178 imp_svc = imp_tsvc = NULL;
8179 8179 scf_scope_destroy(imp_scope);
8180 8180 imp_scope = NULL;
8181 8181
8182 8182 load_fini();
8183 8183 }
8184 8184
8185 8185 int
8186 8186 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8187 8187 {
8188 8188 scf_callback_t cbdata;
8189 8189 int result = 0;
8190 8190 entity_t *svc, *inst;
8191 8191 uu_list_t *insts;
8192 8192 int r;
8193 8193 pgroup_t *old_dpt;
8194 8194 int annotation_set = 0;
8195 8195
8196 8196 const char * const emsg_nomem = gettext("Out of memory.\n");
8197 8197 const char * const emsg_nores =
8198 8198 gettext("svc.configd is out of resources.\n");
8199 8199
8200 8200 lscf_prep_hndl();
8201 8201
8202 8202 if (alloc_imp_globals())
8203 8203 goto out;
8204 8204
8205 8205 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8206 8206 switch (scf_error()) {
8207 8207 case SCF_ERROR_CONNECTION_BROKEN:
8208 8208 warn(gettext("Repository connection broken.\n"));
8209 8209 repository_teardown();
8210 8210 result = -1;
8211 8211 goto out;
8212 8212
8213 8213 case SCF_ERROR_NOT_FOUND:
8214 8214 case SCF_ERROR_INVALID_ARGUMENT:
8215 8215 case SCF_ERROR_NOT_BOUND:
8216 8216 case SCF_ERROR_HANDLE_MISMATCH:
8217 8217 default:
8218 8218 bad_error("scf_handle_get_scope", scf_error());
8219 8219 }
8220 8220 }
8221 8221
8222 8222 /* Set up the auditing annotation. */
8223 8223 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8224 8224 annotation_set = 1;
8225 8225 } else {
8226 8226 switch (scf_error()) {
8227 8227 case SCF_ERROR_CONNECTION_BROKEN:
8228 8228 warn(gettext("Repository connection broken.\n"));
8229 8229 repository_teardown();
8230 8230 result = -1;
8231 8231 goto out;
8232 8232
8233 8233 case SCF_ERROR_INVALID_ARGUMENT:
8234 8234 case SCF_ERROR_NOT_BOUND:
8235 8235 case SCF_ERROR_NO_RESOURCES:
8236 8236 case SCF_ERROR_INTERNAL:
8237 8237 bad_error("_scf_set_annotation", scf_error());
8238 8238 /* NOTREACHED */
8239 8239
8240 8240 default:
8241 8241 /*
8242 8242 * Do not terminate import because of inability to
8243 8243 * generate annotation audit event.
8244 8244 */
8245 8245 warn(gettext("_scf_set_annotation() unexpectedly "
8246 8246 "failed with return code of %d\n"), scf_error());
8247 8247 break;
8248 8248 }
8249 8249 }
8250 8250
8251 8251 /*
8252 8252 * Clear the sc_import_state's of all services & instances so we can
8253 8253 * report how far we got if we fail.
8254 8254 */
8255 8255 for (svc = uu_list_first(bndl->sc_bundle_services);
8256 8256 svc != NULL;
8257 8257 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8258 8258 svc->sc_import_state = 0;
8259 8259
8260 8260 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8261 8261 clear_int, (void *)offsetof(entity_t, sc_import_state),
8262 8262 UU_DEFAULT) != 0)
8263 8263 bad_error("uu_list_walk", uu_error());
8264 8264 }
8265 8265
8266 8266 cbdata.sc_handle = g_hndl;
8267 8267 cbdata.sc_parent = imp_scope;
8268 8268 cbdata.sc_flags = flags;
8269 8269 cbdata.sc_general = NULL;
8270 8270
8271 8271 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8272 8272 &cbdata, UU_DEFAULT) == 0) {
8273 8273 char *eptr;
8274 8274 /* Success. Refresh everything. */
8275 8275
8276 8276 if (flags & SCI_NOREFRESH || no_refresh) {
8277 8277 no_refresh = 0;
8278 8278 result = 0;
8279 8279 goto out;
8280 8280 }
8281 8281
8282 8282 for (svc = uu_list_first(bndl->sc_bundle_services);
8283 8283 svc != NULL;
8284 8284 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8285 8285 pgroup_t *dpt;
8286 8286
8287 8287 insts = svc->sc_u.sc_service.sc_service_instances;
8288 8288
8289 8289 for (inst = uu_list_first(insts);
8290 8290 inst != NULL;
8291 8291 inst = uu_list_next(insts, inst)) {
8292 8292 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8293 8293 switch (r) {
8294 8294 case 0:
8295 8295 break;
8296 8296
8297 8297 case ENOMEM:
8298 8298 case ECONNABORTED:
8299 8299 case EPERM:
8300 8300 case -1:
8301 8301 goto progress;
8302 8302
8303 8303 default:
8304 8304 bad_error("imp_refresh_fmri", r);
8305 8305 }
8306 8306
8307 8307 inst->sc_import_state = IMPORT_REFRESHED;
8308 8308
8309 8309 for (dpt = uu_list_first(inst->sc_dependents);
8310 8310 dpt != NULL;
8311 8311 dpt = uu_list_next(inst->sc_dependents,
8312 8312 dpt))
8313 8313 if (imp_refresh_fmri(
8314 8314 dpt->sc_pgroup_fmri,
8315 8315 dpt->sc_pgroup_name,
8316 8316 inst->sc_fmri) != 0)
8317 8317 goto progress;
8318 8318 }
8319 8319
8320 8320 for (dpt = uu_list_first(svc->sc_dependents);
8321 8321 dpt != NULL;
8322 8322 dpt = uu_list_next(svc->sc_dependents, dpt))
8323 8323 if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8324 8324 dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8325 8325 goto progress;
8326 8326 }
8327 8327
8328 8328 for (old_dpt = uu_list_first(imp_deleted_dpts);
8329 8329 old_dpt != NULL;
8330 8330 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8331 8331 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8332 8332 old_dpt->sc_pgroup_name,
8333 8333 old_dpt->sc_parent->sc_fmri) != 0)
8334 8334 goto progress;
8335 8335
8336 8336 result = 0;
8337 8337
8338 8338 /*
8339 8339 * This snippet of code assumes that we are running svccfg as we
8340 8340 * normally do -- witih svc.startd running. Of course, that is
8341 8341 * not actually the case all the time because we also use a
8342 8342 * varient of svc.configd and svccfg which are only meant to
8343 8343 * run during the build process. During this time we have no
8344 8344 * svc.startd, so this check would hang the build process.
8345 8345 *
8346 8346 * However, we've also given other consolidations, a bit of a
8347 8347 * means to tie themselves into a knot. They're not properly
8348 8348 * using the native build equivalents, but they've been getting
8349 8349 * away with it anyways. Therefore, if we've found that
8350 8350 * SVCCFG_REPOSITORY is set indicating that a separate configd
8351 8351 * should be spun up, then we have to assume it's not using a
8352 8352 * startd and we should not do this check.
8353 8353 */
8354 8354 #ifndef NATIVE_BUILD
8355 8355 /*
8356 8356 * Verify that the restarter group is preset
8357 8357 */
8358 8358 eptr = getenv("SVCCFG_REPOSITORY");
8359 8359 for (svc = uu_list_first(bndl->sc_bundle_services);
8360 8360 svc != NULL && eptr == NULL;
8361 8361 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8362 8362
8363 8363 insts = svc->sc_u.sc_service.sc_service_instances;
8364 8364
8365 8365 for (inst = uu_list_first(insts);
8366 8366 inst != NULL;
8367 8367 inst = uu_list_next(insts, inst)) {
8368 8368 if (lscf_instance_verify(imp_scope, svc,
8369 8369 inst) != 0)
8370 8370 goto progress;
8371 8371 }
8372 8372 }
8373 8373 #endif
8374 8374 goto out;
8375 8375
8376 8376 }
8377 8377
8378 8378 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8379 8379 bad_error("uu_list_walk", uu_error());
8380 8380
8381 8381 printerr:
8382 8382 /* If the error hasn't been printed yet, do so here. */
8383 8383 switch (cbdata.sc_err) {
8384 8384 case ECONNABORTED:
8385 8385 warn(gettext("Repository connection broken.\n"));
8386 8386 break;
8387 8387
8388 8388 case ENOMEM:
8389 8389 warn(emsg_nomem);
8390 8390 break;
8391 8391
8392 8392 case ENOSPC:
8393 8393 warn(emsg_nores);
8394 8394 break;
8395 8395
8396 8396 case EROFS:
8397 8397 warn(gettext("Repository is read-only.\n"));
8398 8398 break;
8399 8399
8400 8400 case EACCES:
8401 8401 warn(gettext("Repository backend denied access.\n"));
8402 8402 break;
8403 8403
8404 8404 case EPERM:
8405 8405 case EINVAL:
8406 8406 case EEXIST:
8407 8407 case EBUSY:
8408 8408 case EBADF:
8409 8409 case -1:
8410 8410 break;
8411 8411
8412 8412 default:
8413 8413 bad_error("lscf_service_import", cbdata.sc_err);
8414 8414 }
8415 8415
8416 8416 progress:
8417 8417 warn(gettext("Import of %s failed. Progress:\n"), filename);
8418 8418
8419 8419 for (svc = uu_list_first(bndl->sc_bundle_services);
8420 8420 svc != NULL;
8421 8421 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8422 8422 insts = svc->sc_u.sc_service.sc_service_instances;
8423 8423
8424 8424 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name,
8425 8425 import_progress(svc->sc_import_state));
8426 8426
8427 8427 for (inst = uu_list_first(insts);
8428 8428 inst != NULL;
8429 8429 inst = uu_list_next(insts, inst))
8430 8430 warn(gettext(" Instance \"%s\": %s\n"),
8431 8431 inst->sc_name,
8432 8432 import_progress(inst->sc_import_state));
8433 8433 }
8434 8434
8435 8435 if (cbdata.sc_err == ECONNABORTED)
8436 8436 repository_teardown();
8437 8437
8438 8438
8439 8439 result = -1;
8440 8440
8441 8441 out:
8442 8442 if (annotation_set != 0) {
8443 8443 /* Turn off annotation. It is no longer needed. */
8444 8444 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8445 8445 }
8446 8446
8447 8447 free_imp_globals();
8448 8448
8449 8449 return (result);
8450 8450 }
8451 8451
8452 8452 /*
8453 8453 * _lscf_import_err() summarize the error handling returned by
8454 8454 * lscf_import_{instance | service}_pgs
8455 8455 * Return values are:
8456 8456 * IMPORT_NEXT
8457 8457 * IMPORT_OUT
8458 8458 * IMPORT_BAD
8459 8459 */
8460 8460
8461 8461 #define IMPORT_BAD -1
8462 8462 #define IMPORT_NEXT 0
8463 8463 #define IMPORT_OUT 1
8464 8464
8465 8465 static int
8466 8466 _lscf_import_err(int err, const char *fmri)
8467 8467 {
8468 8468 switch (err) {
8469 8469 case 0:
8470 8470 if (g_verbose)
8471 8471 warn(gettext("%s updated.\n"), fmri);
8472 8472 return (IMPORT_NEXT);
8473 8473
8474 8474 case ECONNABORTED:
8475 8475 warn(gettext("Could not update %s "
8476 8476 "(repository connection broken).\n"), fmri);
8477 8477 return (IMPORT_OUT);
8478 8478
8479 8479 case ENOMEM:
8480 8480 warn(gettext("Could not update %s (out of memory).\n"), fmri);
8481 8481 return (IMPORT_OUT);
8482 8482
8483 8483 case ENOSPC:
8484 8484 warn(gettext("Could not update %s "
8485 8485 "(repository server out of resources).\n"), fmri);
8486 8486 return (IMPORT_OUT);
8487 8487
8488 8488 case ECANCELED:
8489 8489 warn(gettext(
8490 8490 "Could not update %s (deleted).\n"), fmri);
8491 8491 return (IMPORT_NEXT);
8492 8492
8493 8493 case EPERM:
8494 8494 case EINVAL:
8495 8495 case EBUSY:
8496 8496 return (IMPORT_NEXT);
8497 8497
8498 8498 case EROFS:
8499 8499 warn(gettext("Could not update %s (repository read-only).\n"),
8500 8500 fmri);
8501 8501 return (IMPORT_OUT);
8502 8502
8503 8503 case EACCES:
8504 8504 warn(gettext("Could not update %s "
8505 8505 "(backend access denied).\n"), fmri);
8506 8506 return (IMPORT_NEXT);
8507 8507
8508 8508 case EEXIST:
8509 8509 default:
8510 8510 return (IMPORT_BAD);
8511 8511 }
8512 8512
8513 8513 /*NOTREACHED*/
8514 8514 }
8515 8515
8516 8516 /*
8517 8517 * The global imp_svc and imp_inst should be set by the caller in the
8518 8518 * check to make sure the service and instance exist that the apply is
8519 8519 * working on.
8520 8520 */
8521 8521 static int
8522 8522 lscf_dependent_apply(void *dpg, void *e)
8523 8523 {
8524 8524 scf_callback_t cb;
8525 8525 pgroup_t *dpt_pgroup = dpg;
8526 8526 pgroup_t *deldpt;
8527 8527 entity_t *ent = e;
8528 8528 int tissvc;
8529 8529 void *sc_ent, *tent;
8530 8530 scf_error_t serr;
8531 8531 int r;
8532 8532
8533 8533 const char * const dependents = "dependents";
8534 8534 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8535 8535
8536 8536 if (issvc)
8537 8537 sc_ent = imp_svc;
8538 8538 else
8539 8539 sc_ent = imp_inst;
8540 8540
8541 8541 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8542 8542 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8543 8543 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8544 8544 imp_prop) != 0) {
8545 8545 switch (scf_error()) {
8546 8546 case SCF_ERROR_NOT_FOUND:
8547 8547 case SCF_ERROR_DELETED:
8548 8548 break;
8549 8549
8550 8550 case SCF_ERROR_CONNECTION_BROKEN:
8551 8551 case SCF_ERROR_NOT_SET:
8552 8552 case SCF_ERROR_INVALID_ARGUMENT:
8553 8553 case SCF_ERROR_HANDLE_MISMATCH:
8554 8554 case SCF_ERROR_NOT_BOUND:
8555 8555 default:
8556 8556 bad_error("entity_get_pg", scf_error());
8557 8557 }
8558 8558 } else {
8559 8559 /*
8560 8560 * Found the dependents/<wip dep> so check to
8561 8561 * see if the service is different. If so
8562 8562 * store the service for later refresh, and
8563 8563 * delete the wip dependency from the service
8564 8564 */
8565 8565 if (scf_property_get_value(imp_prop, ud_val) != 0) {
8566 8566 switch (scf_error()) {
8567 8567 case SCF_ERROR_DELETED:
8568 8568 break;
8569 8569
8570 8570 case SCF_ERROR_CONNECTION_BROKEN:
8571 8571 case SCF_ERROR_NOT_SET:
8572 8572 case SCF_ERROR_INVALID_ARGUMENT:
8573 8573 case SCF_ERROR_HANDLE_MISMATCH:
8574 8574 case SCF_ERROR_NOT_BOUND:
8575 8575 default:
8576 8576 bad_error("scf_property_get_value",
8577 8577 scf_error());
8578 8578 }
8579 8579 }
8580 8580
8581 8581 if (scf_value_get_as_string(ud_val, ud_oldtarg,
8582 8582 max_scf_value_len + 1) < 0)
8583 8583 bad_error("scf_value_get_as_string", scf_error());
8584 8584
8585 8585 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8586 8586 switch (r) {
8587 8587 case 1:
8588 8588 break;
8589 8589 case 0:
8590 8590 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8591 8591 &tissvc)) != SCF_ERROR_NONE) {
8592 8592 if (serr == SCF_ERROR_NOT_FOUND) {
8593 8593 break;
8594 8594 } else {
8595 8595 bad_error("fmri_to_entity", serr);
8596 8596 }
8597 8597 }
8598 8598
8599 8599 if (entity_get_pg(tent, tissvc,
8600 8600 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8601 8601 serr = scf_error();
8602 8602 if (serr == SCF_ERROR_NOT_FOUND ||
8603 8603 serr == SCF_ERROR_DELETED) {
8604 8604 break;
8605 8605 } else {
8606 8606 bad_error("entity_get_pg", scf_error());
8607 8607 }
8608 8608 }
8609 8609
8610 8610 if (scf_pg_delete(imp_pg) != 0) {
8611 8611 serr = scf_error();
8612 8612 if (serr == SCF_ERROR_NOT_FOUND ||
8613 8613 serr == SCF_ERROR_DELETED) {
8614 8614 break;
8615 8615 } else {
8616 8616 bad_error("scf_pg_delete", scf_error());
8617 8617 }
8618 8618 }
8619 8619
8620 8620 deldpt = internal_pgroup_new();
8621 8621 if (deldpt == NULL)
8622 8622 return (ENOMEM);
8623 8623 deldpt->sc_pgroup_name =
8624 8624 strdup(dpt_pgroup->sc_pgroup_name);
8625 8625 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8626 8626 if (deldpt->sc_pgroup_name == NULL ||
8627 8627 deldpt->sc_pgroup_fmri == NULL)
8628 8628 return (ENOMEM);
8629 8629 deldpt->sc_parent = (entity_t *)ent;
8630 8630 if (uu_list_insert_after(imp_deleted_dpts, NULL,
8631 8631 deldpt) != 0)
8632 8632 uu_die(gettext("libuutil error: %s\n"),
8633 8633 uu_strerror(uu_error()));
8634 8634
8635 8635 break;
8636 8636 default:
8637 8637 bad_error("fmri_equal", r);
8638 8638 }
8639 8639 }
8640 8640
8641 8641 cb.sc_handle = g_hndl;
8642 8642 cb.sc_parent = ent;
8643 8643 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8644 8644 cb.sc_source_fmri = ent->sc_fmri;
8645 8645 cb.sc_target_fmri = ent->sc_fmri;
8646 8646 cb.sc_trans = NULL;
8647 8647 cb.sc_flags = SCI_FORCE;
8648 8648
8649 8649 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8650 8650 return (UU_WALK_ERROR);
8651 8651
8652 8652 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8653 8653 switch (r) {
8654 8654 case 0:
8655 8655 break;
8656 8656
8657 8657 case ENOMEM:
8658 8658 case ECONNABORTED:
8659 8659 case EPERM:
8660 8660 case -1:
8661 8661 warn(gettext("Unable to refresh \"%s\"\n"),
8662 8662 dpt_pgroup->sc_pgroup_fmri);
8663 8663 return (UU_WALK_ERROR);
8664 8664
8665 8665 default:
8666 8666 bad_error("imp_refresh_fmri", r);
8667 8667 }
8668 8668
8669 8669 return (UU_WALK_NEXT);
8670 8670 }
8671 8671
8672 8672 /*
8673 8673 * Returns
8674 8674 * 0 - success
8675 8675 * -1 - lscf_import_instance_pgs() failed.
8676 8676 */
8677 8677 int
8678 8678 lscf_bundle_apply(bundle_t *bndl, const char *file)
8679 8679 {
8680 8680 pgroup_t *old_dpt;
8681 8681 entity_t *svc, *inst;
8682 8682 int annotation_set = 0;
8683 8683 int ret = 0;
8684 8684 int r = 0;
8685 8685
8686 8686 lscf_prep_hndl();
8687 8687
8688 8688 if ((ret = alloc_imp_globals()))
8689 8689 goto out;
8690 8690
8691 8691 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8692 8692 scfdie();
8693 8693
8694 8694 /*
8695 8695 * Set the strings to be used for the security audit annotation
8696 8696 * event.
8697 8697 */
8698 8698 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8699 8699 annotation_set = 1;
8700 8700 } else {
8701 8701 switch (scf_error()) {
8702 8702 case SCF_ERROR_CONNECTION_BROKEN:
8703 8703 warn(gettext("Repository connection broken.\n"));
8704 8704 goto out;
8705 8705
8706 8706 case SCF_ERROR_INVALID_ARGUMENT:
8707 8707 case SCF_ERROR_NOT_BOUND:
8708 8708 case SCF_ERROR_NO_RESOURCES:
8709 8709 case SCF_ERROR_INTERNAL:
8710 8710 bad_error("_scf_set_annotation", scf_error());
8711 8711 /* NOTREACHED */
8712 8712
8713 8713 default:
8714 8714 /*
8715 8715 * Do not abort apply operation because of
8716 8716 * inability to create annotation audit event.
8717 8717 */
8718 8718 warn(gettext("_scf_set_annotation() unexpectedly "
8719 8719 "failed with return code of %d\n"), scf_error());
8720 8720 break;
8721 8721 }
8722 8722 }
8723 8723
8724 8724 for (svc = uu_list_first(bndl->sc_bundle_services);
8725 8725 svc != NULL;
8726 8726 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8727 8727 int refresh = 0;
8728 8728
8729 8729 if (scf_scope_get_service(imp_scope, svc->sc_name,
8730 8730 imp_svc) != 0) {
8731 8731 switch (scf_error()) {
8732 8732 case SCF_ERROR_NOT_FOUND:
8733 8733 if (g_verbose)
8734 8734 warn(gettext("Ignoring nonexistent "
8735 8735 "service %s.\n"), svc->sc_name);
8736 8736 continue;
8737 8737
8738 8738 default:
8739 8739 scfdie();
8740 8740 }
8741 8741 }
8742 8742
8743 8743 /*
8744 8744 * If there were missing types in the profile, then need to
8745 8745 * attempt to find the types.
8746 8746 */
8747 8747 if (svc->sc_miss_type) {
8748 8748 if (uu_list_numnodes(svc->sc_pgroups) &&
8749 8749 uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8750 8750 svc, UU_DEFAULT) != 0) {
8751 8751 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8752 8752 bad_error("uu_list_walk", uu_error());
8753 8753
8754 8754 ret = -1;
8755 8755 continue;
8756 8756 }
8757 8757
8758 8758 for (inst = uu_list_first(
8759 8759 svc->sc_u.sc_service.sc_service_instances);
8760 8760 inst != NULL;
8761 8761 inst = uu_list_next(
8762 8762 svc->sc_u.sc_service.sc_service_instances, inst)) {
8763 8763 /*
8764 8764 * If the instance doesn't exist just
8765 8765 * skip to the next instance and let the
8766 8766 * import note the missing instance.
8767 8767 */
8768 8768 if (scf_service_get_instance(imp_svc,
8769 8769 inst->sc_name, imp_inst) != 0)
8770 8770 continue;
8771 8771
8772 8772 if (uu_list_walk(inst->sc_pgroups,
8773 8773 find_current_pg_type, inst,
8774 8774 UU_DEFAULT) != 0) {
8775 8775 if (uu_error() !=
8776 8776 UU_ERROR_CALLBACK_FAILED)
8777 8777 bad_error("uu_list_walk",
8778 8778 uu_error());
8779 8779
8780 8780 ret = -1;
8781 8781 inst->sc_miss_type = B_TRUE;
8782 8782 }
8783 8783 }
8784 8784 }
8785 8785
8786 8786 /*
8787 8787 * if we have pgs in the profile, we need to refresh ALL
8788 8788 * instances of the service
8789 8789 */
8790 8790 if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8791 8791 refresh = 1;
8792 8792 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8793 8793 SCI_FORCE | SCI_KEEP);
8794 8794 switch (_lscf_import_err(r, svc->sc_fmri)) {
8795 8795 case IMPORT_NEXT:
8796 8796 break;
8797 8797
8798 8798 case IMPORT_OUT:
8799 8799 goto out;
8800 8800
8801 8801 case IMPORT_BAD:
8802 8802 default:
8803 8803 bad_error("lscf_import_service_pgs", r);
8804 8804 }
8805 8805 }
8806 8806
8807 8807 if (uu_list_numnodes(svc->sc_dependents) != 0) {
8808 8808 uu_list_walk(svc->sc_dependents,
8809 8809 lscf_dependent_apply, svc, UU_DEFAULT);
8810 8810 }
8811 8811
8812 8812 for (inst = uu_list_first(
8813 8813 svc->sc_u.sc_service.sc_service_instances);
8814 8814 inst != NULL;
8815 8815 inst = uu_list_next(
8816 8816 svc->sc_u.sc_service.sc_service_instances, inst)) {
8817 8817 /*
8818 8818 * This instance still has missing types
8819 8819 * so skip it.
8820 8820 */
8821 8821 if (inst->sc_miss_type) {
8822 8822 if (g_verbose)
8823 8823 warn(gettext("Ignoring instance "
8824 8824 "%s:%s with missing types\n"),
8825 8825 inst->sc_parent->sc_name,
8826 8826 inst->sc_name);
8827 8827
8828 8828 continue;
8829 8829 }
8830 8830
8831 8831 if (scf_service_get_instance(imp_svc, inst->sc_name,
8832 8832 imp_inst) != 0) {
8833 8833 switch (scf_error()) {
8834 8834 case SCF_ERROR_NOT_FOUND:
8835 8835 if (g_verbose)
8836 8836 warn(gettext("Ignoring "
8837 8837 "nonexistant instance "
8838 8838 "%s:%s.\n"),
8839 8839 inst->sc_parent->sc_name,
8840 8840 inst->sc_name);
8841 8841 continue;
8842 8842
8843 8843 default:
8844 8844 scfdie();
8845 8845 }
8846 8846 }
8847 8847
8848 8848 /*
8849 8849 * If the instance does not have a general/enabled
8850 8850 * property and no last-import snapshot then the
8851 8851 * instance is not a fully installed instance and
8852 8852 * should not have a profile applied to it.
8853 8853 *
8854 8854 * This could happen if a service/instance declares
8855 8855 * a dependent on behalf of another service/instance.
8856 8856 *
8857 8857 */
8858 8858 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8859 8859 imp_snap) != 0) {
8860 8860 if (scf_instance_get_pg(imp_inst,
8861 8861 SCF_PG_GENERAL, imp_pg) != 0 ||
8862 8862 scf_pg_get_property(imp_pg,
8863 8863 SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8864 8864 if (g_verbose)
8865 8865 warn(gettext("Ignoreing "
8866 8866 "partial instance "
8867 8867 "%s:%s.\n"),
8868 8868 inst->sc_parent->sc_name,
8869 8869 inst->sc_name);
8870 8870 continue;
8871 8871 }
8872 8872 }
8873 8873
8874 8874 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8875 8875 inst, SCI_FORCE | SCI_KEEP);
8876 8876 switch (_lscf_import_err(r, inst->sc_fmri)) {
8877 8877 case IMPORT_NEXT:
8878 8878 break;
8879 8879
8880 8880 case IMPORT_OUT:
8881 8881 goto out;
8882 8882
8883 8883 case IMPORT_BAD:
8884 8884 default:
8885 8885 bad_error("lscf_import_instance_pgs", r);
8886 8886 }
8887 8887
8888 8888 if (uu_list_numnodes(inst->sc_dependents) != 0) {
8889 8889 uu_list_walk(inst->sc_dependents,
8890 8890 lscf_dependent_apply, inst, UU_DEFAULT);
8891 8891 }
8892 8892
8893 8893 /* refresh only if there is no pgs in the service */
8894 8894 if (refresh == 0)
8895 8895 (void) refresh_entity(0, imp_inst,
8896 8896 inst->sc_fmri, NULL, NULL, NULL);
8897 8897 }
8898 8898
8899 8899 if (refresh == 1) {
8900 8900 char *name_buf = safe_malloc(max_scf_name_len + 1);
8901 8901
8902 8902 (void) refresh_entity(1, imp_svc, svc->sc_name,
8903 8903 imp_inst, imp_iter, name_buf);
8904 8904 free(name_buf);
8905 8905 }
8906 8906
8907 8907 for (old_dpt = uu_list_first(imp_deleted_dpts);
8908 8908 old_dpt != NULL;
8909 8909 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8910 8910 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8911 8911 old_dpt->sc_pgroup_name,
8912 8912 old_dpt->sc_parent->sc_fmri) != 0) {
8913 8913 warn(gettext("Unable to refresh \"%s\"\n"),
8914 8914 old_dpt->sc_pgroup_fmri);
8915 8915 }
8916 8916 }
8917 8917 }
8918 8918
8919 8919 out:
8920 8920 if (annotation_set) {
8921 8921 /* Remove security audit annotation strings. */
8922 8922 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8923 8923 }
8924 8924
8925 8925 free_imp_globals();
8926 8926 return (ret);
8927 8927 }
8928 8928
8929 8929
8930 8930 /*
8931 8931 * Export. These functions create and output an XML tree of a service
8932 8932 * description from the repository. This is largely the inverse of
8933 8933 * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8934 8934 *
8935 8935 * - We must include any properties which are not represented specifically by
8936 8936 * a service manifest, e.g., properties created by an admin post-import. To
8937 8937 * do so we'll iterate through all properties and deal with each
8938 8938 * apropriately.
8939 8939 *
8940 8940 * - Children of services and instances must must be in the order set by the
8941 8941 * DTD, but we iterate over the properties in undefined order. The elements
8942 8942 * are not easily (or efficiently) sortable by name. Since there's a fixed
8943 8943 * number of classes of them, however, we'll keep the classes separate and
8944 8944 * assemble them in order.
8945 8945 */
8946 8946
8947 8947 /*
8948 8948 * Convenience function to handle xmlSetProp errors (and type casting).
8949 8949 */
8950 8950 static void
8951 8951 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8952 8952 {
8953 8953 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8954 8954 uu_die(gettext("Could not set XML property.\n"));
8955 8955 }
8956 8956
8957 8957 /*
8958 8958 * Convenience function to set an XML attribute to the single value of an
8959 8959 * astring property. If the value happens to be the default, don't set the
8960 8960 * attribute. "dval" should be the default value supplied by the DTD, or
8961 8961 * NULL for no default.
8962 8962 */
8963 8963 static int
8964 8964 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8965 8965 const char *name, const char *dval)
8966 8966 {
8967 8967 scf_value_t *val;
8968 8968 ssize_t len;
8969 8969 char *str;
8970 8970
8971 8971 val = scf_value_create(g_hndl);
8972 8972 if (val == NULL)
8973 8973 scfdie();
8974 8974
8975 8975 if (prop_get_val(prop, val) != 0) {
8976 8976 scf_value_destroy(val);
8977 8977 return (-1);
8978 8978 }
8979 8979
8980 8980 len = scf_value_get_as_string(val, NULL, 0);
8981 8981 if (len < 0)
8982 8982 scfdie();
8983 8983
8984 8984 str = safe_malloc(len + 1);
8985 8985
8986 8986 if (scf_value_get_as_string(val, str, len + 1) < 0)
8987 8987 scfdie();
8988 8988
8989 8989 scf_value_destroy(val);
8990 8990
8991 8991 if (dval == NULL || strcmp(str, dval) != 0)
8992 8992 safe_setprop(n, name, str);
8993 8993
8994 8994 free(str);
8995 8995
8996 8996 return (0);
8997 8997 }
8998 8998
8999 8999 /*
9000 9000 * As above, but the attribute is always set.
9001 9001 */
9002 9002 static int
9003 9003 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
9004 9004 {
9005 9005 return (set_attr_from_prop_default(prop, n, name, NULL));
9006 9006 }
9007 9007
9008 9008 /*
9009 9009 * Dump the given document onto f, with "'s replaced by ''s.
9010 9010 */
9011 9011 static int
9012 9012 write_service_bundle(xmlDocPtr doc, FILE *f)
9013 9013 {
9014 9014 xmlChar *mem;
9015 9015 int sz, i;
9016 9016
9017 9017 mem = NULL;
9018 9018 xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9019 9019
9020 9020 if (mem == NULL) {
9021 9021 semerr(gettext("Could not dump XML tree.\n"));
9022 9022 return (-1);
9023 9023 }
9024 9024
9025 9025 /*
9026 9026 * Fortunately libxml produces " instead of ", so we can blindly
9027 9027 * replace all " with '. Cursed libxml2! Why must you #ifdef out the
9028 9028 * ' code?!
9029 9029 */
9030 9030 for (i = 0; i < sz; ++i) {
9031 9031 char c = (char)mem[i];
9032 9032
9033 9033 if (c == '"')
9034 9034 (void) fputc('\'', f);
9035 9035 else if (c == '\'')
9036 9036 (void) fwrite("'", sizeof ("'") - 1, 1, f);
9037 9037 else
9038 9038 (void) fputc(c, f);
9039 9039 }
9040 9040
9041 9041 return (0);
9042 9042 }
9043 9043
9044 9044 /*
9045 9045 * Create the DOM elements in elts necessary to (generically) represent prop
9046 9046 * (i.e., a property or propval element). If the name of the property is
9047 9047 * known, it should be passed as name_arg. Otherwise, pass NULL.
9048 9048 */
9049 9049 static void
9050 9050 export_property(scf_property_t *prop, const char *name_arg,
9051 9051 struct pg_elts *elts, int flags)
9052 9052 {
9053 9053 const char *type;
9054 9054 scf_error_t err = 0;
9055 9055 xmlNodePtr pnode, lnode;
9056 9056 char *lnname;
9057 9057 int ret;
9058 9058
9059 9059 /* name */
9060 9060 if (name_arg != NULL) {
9061 9061 (void) strcpy(exp_str, name_arg);
9062 9062 } else {
9063 9063 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9064 9064 scfdie();
9065 9065 }
9066 9066
9067 9067 /* type */
9068 9068 type = prop_to_typestr(prop);
9069 9069 if (type == NULL)
9070 9070 uu_die(gettext("Can't export property %s: unknown type.\n"),
9071 9071 exp_str);
9072 9072
9073 9073 /* If we're exporting values, and there's just one, export it here. */
9074 9074 if (!(flags & SCE_ALL_VALUES))
9075 9075 goto empty;
9076 9076
9077 9077 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9078 9078 xmlNodePtr n;
9079 9079
9080 9080 /* Single value, so use propval */
9081 9081 n = xmlNewNode(NULL, (xmlChar *)"propval");
9082 9082 if (n == NULL)
9083 9083 uu_die(emsg_create_xml);
9084 9084
9085 9085 safe_setprop(n, name_attr, exp_str);
9086 9086 safe_setprop(n, type_attr, type);
9087 9087
9088 9088 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9089 9089 scfdie();
9090 9090 safe_setprop(n, value_attr, exp_str);
9091 9091
9092 9092 if (elts->propvals == NULL)
9093 9093 elts->propvals = n;
9094 9094 else
9095 9095 (void) xmlAddSibling(elts->propvals, n);
9096 9096
9097 9097 return;
9098 9098 }
9099 9099
9100 9100 err = scf_error();
9101 9101
9102 9102 if (err == SCF_ERROR_PERMISSION_DENIED) {
9103 9103 semerr(emsg_permission_denied);
9104 9104 return;
9105 9105 }
9106 9106
9107 9107 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9108 9108 err != SCF_ERROR_NOT_FOUND &&
9109 9109 err != SCF_ERROR_PERMISSION_DENIED)
9110 9110 scfdie();
9111 9111
9112 9112 empty:
9113 9113 /* Multiple (or no) values, so use property */
9114 9114 pnode = xmlNewNode(NULL, (xmlChar *)"property");
9115 9115 if (pnode == NULL)
9116 9116 uu_die(emsg_create_xml);
9117 9117
9118 9118 safe_setprop(pnode, name_attr, exp_str);
9119 9119 safe_setprop(pnode, type_attr, type);
9120 9120
9121 9121 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9122 9122 lnname = uu_msprintf("%s_list", type);
9123 9123 if (lnname == NULL)
9124 9124 uu_die(gettext("Could not create string"));
9125 9125
9126 9126 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9127 9127 if (lnode == NULL)
9128 9128 uu_die(emsg_create_xml);
9129 9129
9130 9130 uu_free(lnname);
9131 9131
9132 9132 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9133 9133 scfdie();
9134 9134
9135 9135 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9136 9136 1) {
9137 9137 xmlNodePtr vn;
9138 9138
9139 9139 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9140 9140 NULL);
9141 9141 if (vn == NULL)
9142 9142 uu_die(emsg_create_xml);
9143 9143
9144 9144 if (scf_value_get_as_string(exp_val, exp_str,
9145 9145 exp_str_sz) < 0)
9146 9146 scfdie();
9147 9147 safe_setprop(vn, value_attr, exp_str);
9148 9148 }
9149 9149 if (ret != 0)
9150 9150 scfdie();
9151 9151 }
9152 9152
9153 9153 if (elts->properties == NULL)
9154 9154 elts->properties = pnode;
9155 9155 else
9156 9156 (void) xmlAddSibling(elts->properties, pnode);
9157 9157 }
9158 9158
9159 9159 /*
9160 9160 * Add a property_group element for this property group to elts.
9161 9161 */
9162 9162 static void
9163 9163 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9164 9164 {
9165 9165 xmlNodePtr n;
9166 9166 struct pg_elts elts;
9167 9167 int ret;
9168 9168 boolean_t read_protected;
9169 9169
9170 9170 n = xmlNewNode(NULL, (xmlChar *)"property_group");
9171 9171
9172 9172 /* name */
9173 9173 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9174 9174 scfdie();
9175 9175 safe_setprop(n, name_attr, exp_str);
9176 9176
9177 9177 /* type */
9178 9178 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9179 9179 scfdie();
9180 9180 safe_setprop(n, type_attr, exp_str);
9181 9181
9182 9182 /* properties */
9183 9183 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9184 9184 scfdie();
9185 9185
9186 9186 (void) memset(&elts, 0, sizeof (elts));
9187 9187
9188 9188 /*
9189 9189 * If this property group is not read protected, we always want to
9190 9190 * output all the values. Otherwise, we only output the values if the
9191 9191 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9192 9192 */
9193 9193 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9194 9194 scfdie();
9195 9195
9196 9196 if (!read_protected)
9197 9197 flags |= SCE_ALL_VALUES;
9198 9198
9199 9199 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9200 9200 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9201 9201 scfdie();
9202 9202
9203 9203 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9204 9204 xmlNodePtr m;
9205 9205
9206 9206 m = xmlNewNode(NULL, (xmlChar *)"stability");
9207 9207 if (m == NULL)
9208 9208 uu_die(emsg_create_xml);
9209 9209
9210 9210 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9211 9211 elts.stability = m;
9212 9212 continue;
9213 9213 }
9214 9214
9215 9215 xmlFreeNode(m);
9216 9216 }
9217 9217
9218 9218 export_property(exp_prop, NULL, &elts, flags);
9219 9219 }
9220 9220 if (ret == -1)
9221 9221 scfdie();
9222 9222
9223 9223 (void) xmlAddChild(n, elts.stability);
9224 9224 (void) xmlAddChildList(n, elts.propvals);
9225 9225 (void) xmlAddChildList(n, elts.properties);
9226 9226
9227 9227 if (eelts->property_groups == NULL)
9228 9228 eelts->property_groups = n;
9229 9229 else
9230 9230 (void) xmlAddSibling(eelts->property_groups, n);
9231 9231 }
9232 9232
9233 9233 /*
9234 9234 * Create an XML node representing the dependency described by the given
9235 9235 * property group and put it in eelts. Unless the dependency is not valid, in
9236 9236 * which case create a generic property_group element which represents it and
9237 9237 * put it in eelts.
9238 9238 */
9239 9239 static void
9240 9240 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9241 9241 {
9242 9242 xmlNodePtr n;
9243 9243 int err = 0, ret;
9244 9244 struct pg_elts elts;
9245 9245
9246 9246 n = xmlNewNode(NULL, (xmlChar *)"dependency");
9247 9247 if (n == NULL)
9248 9248 uu_die(emsg_create_xml);
9249 9249
9250 9250 /*
9251 9251 * If the external flag is present, skip this dependency because it
9252 9252 * should have been created by another manifest.
9253 9253 */
9254 9254 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9255 9255 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9256 9256 prop_get_val(exp_prop, exp_val) == 0) {
9257 9257 uint8_t b;
9258 9258
9259 9259 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9260 9260 scfdie();
9261 9261
9262 9262 if (b)
9263 9263 return;
9264 9264 }
9265 9265 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
9266 9266 scfdie();
9267 9267
9268 9268 /* Get the required attributes. */
9269 9269
9270 9270 /* name */
9271 9271 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9272 9272 scfdie();
9273 9273 safe_setprop(n, name_attr, exp_str);
9274 9274
9275 9275 /* grouping */
9276 9276 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9277 9277 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9278 9278 err = 1;
9279 9279
9280 9280 /* restart_on */
9281 9281 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9282 9282 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9283 9283 err = 1;
9284 9284
9285 9285 /* type */
9286 9286 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9287 9287 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9288 9288 err = 1;
9289 9289
9290 9290 /*
9291 9291 * entities: Not required, but if we create no children, it will be
9292 9292 * created as empty on import, so fail if it's missing.
9293 9293 */
9294 9294 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9295 9295 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9296 9296 scf_iter_t *eiter;
9297 9297 int ret2;
9298 9298
9299 9299 eiter = scf_iter_create(g_hndl);
9300 9300 if (eiter == NULL)
9301 9301 scfdie();
9302 9302
9303 9303 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9304 9304 scfdie();
9305 9305
9306 9306 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9307 9307 xmlNodePtr ch;
9308 9308
9309 9309 if (scf_value_get_astring(exp_val, exp_str,
9310 9310 exp_str_sz) < 0)
9311 9311 scfdie();
9312 9312
9313 9313 /*
9314 9314 * service_fmri's must be first, so we can add them
9315 9315 * here.
9316 9316 */
9317 9317 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9318 9318 NULL);
9319 9319 if (ch == NULL)
9320 9320 uu_die(emsg_create_xml);
9321 9321
9322 9322 safe_setprop(ch, value_attr, exp_str);
9323 9323 }
9324 9324 if (ret2 == -1)
9325 9325 scfdie();
9326 9326
9327 9327 scf_iter_destroy(eiter);
9328 9328 } else
9329 9329 err = 1;
9330 9330
9331 9331 if (err) {
9332 9332 xmlFreeNode(n);
9333 9333
9334 9334 export_pg(pg, eelts, SCE_ALL_VALUES);
9335 9335
9336 9336 return;
9337 9337 }
9338 9338
9339 9339 /* Iterate through the properties & handle each. */
9340 9340 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9341 9341 scfdie();
9342 9342
9343 9343 (void) memset(&elts, 0, sizeof (elts));
9344 9344
9345 9345 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9346 9346 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9347 9347 scfdie();
9348 9348
9349 9349 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9350 9350 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9351 9351 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9352 9352 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9353 9353 continue;
9354 9354 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9355 9355 xmlNodePtr m;
9356 9356
9357 9357 m = xmlNewNode(NULL, (xmlChar *)"stability");
9358 9358 if (m == NULL)
9359 9359 uu_die(emsg_create_xml);
9360 9360
9361 9361 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9362 9362 elts.stability = m;
9363 9363 continue;
9364 9364 }
9365 9365
9366 9366 xmlFreeNode(m);
9367 9367 }
9368 9368
9369 9369 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9370 9370 }
9371 9371 if (ret == -1)
9372 9372 scfdie();
9373 9373
9374 9374 (void) xmlAddChild(n, elts.stability);
9375 9375 (void) xmlAddChildList(n, elts.propvals);
9376 9376 (void) xmlAddChildList(n, elts.properties);
9377 9377
9378 9378 if (eelts->dependencies == NULL)
9379 9379 eelts->dependencies = n;
9380 9380 else
9381 9381 (void) xmlAddSibling(eelts->dependencies, n);
9382 9382 }
9383 9383
9384 9384 static xmlNodePtr
9385 9385 export_method_environment(scf_propertygroup_t *pg)
9386 9386 {
9387 9387 xmlNodePtr env;
9388 9388 int ret;
9389 9389 int children = 0;
9390 9390
9391 9391 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9392 9392 return (NULL);
9393 9393
9394 9394 env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9395 9395 if (env == NULL)
9396 9396 uu_die(emsg_create_xml);
9397 9397
9398 9398 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9399 9399 scfdie();
9400 9400
9401 9401 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9402 9402 scfdie();
9403 9403
9404 9404 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9405 9405 xmlNodePtr ev;
9406 9406 char *cp;
9407 9407
9408 9408 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9409 9409 scfdie();
9410 9410
9411 9411 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9412 9412 warn(gettext("Invalid environment variable \"%s\".\n"),
9413 9413 exp_str);
9414 9414 continue;
9415 9415 } else if (strncmp(exp_str, "SMF_", 4) == 0) {
9416 9416 warn(gettext("Invalid environment variable \"%s\"; "
9417 9417 "\"SMF_\" prefix is reserved.\n"), exp_str);
9418 9418 continue;
9419 9419 }
9420 9420
9421 9421 *cp = '\0';
9422 9422 cp++;
9423 9423
9424 9424 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9425 9425 if (ev == NULL)
9426 9426 uu_die(emsg_create_xml);
9427 9427
9428 9428 safe_setprop(ev, name_attr, exp_str);
9429 9429 safe_setprop(ev, value_attr, cp);
9430 9430 children++;
9431 9431 }
9432 9432
9433 9433 if (ret != 0)
9434 9434 scfdie();
9435 9435
9436 9436 if (children == 0) {
9437 9437 xmlFreeNode(env);
9438 9438 return (NULL);
9439 9439 }
9440 9440
9441 9441 return (env);
9442 9442 }
9443 9443
9444 9444 /*
9445 9445 * As above, but for a method property group.
9446 9446 */
9447 9447 static void
9448 9448 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9449 9449 {
9450 9450 xmlNodePtr n, env;
9451 9451 char *str;
9452 9452 int err = 0, nonenv, ret;
9453 9453 uint8_t use_profile;
9454 9454 struct pg_elts elts;
9455 9455 xmlNodePtr ctxt = NULL;
9456 9456
9457 9457 n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9458 9458
9459 9459 /* Get the required attributes. */
9460 9460
9461 9461 /* name */
9462 9462 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9463 9463 scfdie();
9464 9464 safe_setprop(n, name_attr, exp_str);
9465 9465
9466 9466 /* type */
9467 9467 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9468 9468 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9469 9469 err = 1;
9470 9470
9471 9471 /* exec */
9472 9472 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9473 9473 set_attr_from_prop(exp_prop, n, "exec") != 0)
9474 9474 err = 1;
9475 9475
9476 9476 /* timeout */
9477 9477 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9478 9478 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9479 9479 prop_get_val(exp_prop, exp_val) == 0) {
9480 9480 uint64_t c;
9481 9481
9482 9482 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9483 9483 scfdie();
9484 9484
9485 9485 str = uu_msprintf("%llu", c);
9486 9486 if (str == NULL)
9487 9487 uu_die(gettext("Could not create string"));
9488 9488
9489 9489 safe_setprop(n, "timeout_seconds", str);
9490 9490 free(str);
9491 9491 } else
9492 9492 err = 1;
9493 9493
9494 9494 if (err) {
9495 9495 xmlFreeNode(n);
9496 9496
9497 9497 export_pg(pg, eelts, SCE_ALL_VALUES);
9498 9498
9499 9499 return;
9500 9500 }
9501 9501
9502 9502
9503 9503 /*
9504 9504 * If we're going to have a method_context child, we need to know
9505 9505 * before we iterate through the properties. Since method_context's
9506 9506 * are optional, we don't want to complain about any properties
9507 9507 * missing if none of them are there. Thus we can't use the
9508 9508 * convenience functions.
9509 9509 */
9510 9510 nonenv =
9511 9511 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9512 9512 SCF_SUCCESS ||
9513 9513 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9514 9514 SCF_SUCCESS ||
9515 9515 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9516 9516 SCF_SUCCESS ||
9517 9517 scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) ==
9518 9518 SCF_SUCCESS ||
9519 9519 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9520 9520 SCF_SUCCESS;
9521 9521
9522 9522 if (nonenv) {
9523 9523 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9524 9524 if (ctxt == NULL)
9525 9525 uu_die(emsg_create_xml);
9526 9526
9527 9527 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9528 9528 0 &&
9529 9529 set_attr_from_prop_default(exp_prop, ctxt,
9530 9530 "working_directory", ":default") != 0)
9531 9531 err = 1;
9532 9532
9533 9533 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9534 9534 set_attr_from_prop_default(exp_prop, ctxt, "project",
9535 9535 ":default") != 0)
9536 9536 err = 1;
9537 9537
9538 9538 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9539 9539 0 &&
9540 9540 set_attr_from_prop_default(exp_prop, ctxt,
9541 9541 "resource_pool", ":default") != 0)
9542 9542 err = 1;
9543 9543
9544 9544 if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 &&
9545 9545 set_attr_from_prop_default(exp_prop, ctxt,
9546 9546 "security_flags", ":default") != 0)
9547 9547 err = 1;
9548 9548
9549 9549 /*
9550 9550 * We only want to complain about profile or credential
9551 9551 * properties if we will use them. To determine that we must
9552 9552 * examine USE_PROFILE.
9553 9553 */
9554 9554 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9555 9555 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9556 9556 prop_get_val(exp_prop, exp_val) == 0) {
9557 9557 if (scf_value_get_boolean(exp_val, &use_profile) !=
9558 9558 SCF_SUCCESS) {
9559 9559 scfdie();
9560 9560 }
9561 9561
9562 9562 if (use_profile) {
9563 9563 xmlNodePtr prof;
9564 9564
9565 9565 prof = xmlNewChild(ctxt, NULL,
9566 9566 (xmlChar *)"method_profile", NULL);
9567 9567 if (prof == NULL)
9568 9568 uu_die(emsg_create_xml);
9569 9569
9570 9570 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9571 9571 exp_prop) != 0 ||
9572 9572 set_attr_from_prop(exp_prop, prof,
9573 9573 name_attr) != 0)
9574 9574 err = 1;
9575 9575 } else {
9576 9576 xmlNodePtr cred;
9577 9577
9578 9578 cred = xmlNewChild(ctxt, NULL,
9579 9579 (xmlChar *)"method_credential", NULL);
9580 9580 if (cred == NULL)
9581 9581 uu_die(emsg_create_xml);
9582 9582
9583 9583 if (pg_get_prop(pg, SCF_PROPERTY_USER,
9584 9584 exp_prop) != 0 ||
9585 9585 set_attr_from_prop(exp_prop, cred,
9586 9586 "user") != 0) {
9587 9587 err = 1;
9588 9588 }
9589 9589
9590 9590 if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9591 9591 exp_prop) == 0 &&
9592 9592 set_attr_from_prop_default(exp_prop, cred,
9593 9593 "group", ":default") != 0)
9594 9594 err = 1;
9595 9595
9596 9596 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9597 9597 exp_prop) == 0 &&
9598 9598 set_attr_from_prop_default(exp_prop, cred,
9599 9599 "supp_groups", ":default") != 0)
9600 9600 err = 1;
9601 9601
9602 9602 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9603 9603 exp_prop) == 0 &&
9604 9604 set_attr_from_prop_default(exp_prop, cred,
9605 9605 "privileges", ":default") != 0)
9606 9606 err = 1;
9607 9607
9608 9608 if (pg_get_prop(pg,
9609 9609 SCF_PROPERTY_LIMIT_PRIVILEGES,
9610 9610 exp_prop) == 0 &&
9611 9611 set_attr_from_prop_default(exp_prop, cred,
9612 9612 "limit_privileges", ":default") != 0)
9613 9613 err = 1;
9614 9614 }
9615 9615 }
9616 9616 }
9617 9617
9618 9618 if ((env = export_method_environment(pg)) != NULL) {
9619 9619 if (ctxt == NULL) {
9620 9620 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9621 9621 if (ctxt == NULL)
9622 9622 uu_die(emsg_create_xml);
9623 9623 }
9624 9624 (void) xmlAddChild(ctxt, env);
9625 9625 }
9626 9626
9627 9627 if (env != NULL || (nonenv && err == 0))
9628 9628 (void) xmlAddChild(n, ctxt);
9629 9629 else
9630 9630 xmlFreeNode(ctxt);
9631 9631
9632 9632 nonenv = (err == 0);
9633 9633
9634 9634 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9635 9635 scfdie();
9636 9636
9637 9637 (void) memset(&elts, 0, sizeof (elts));
9638 9638
9639 9639 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9640 9640 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9641 9641 scfdie();
9642 9642
9643 9643 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9644 9644 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9645 9645 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9646 9646 continue;
9647 9647 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9648 9648 xmlNodePtr m;
9649 9649
9650 9650 m = xmlNewNode(NULL, (xmlChar *)"stability");
9651 9651 if (m == NULL)
9652 9652 uu_die(emsg_create_xml);
9653 9653
9654 9654 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9655 9655 elts.stability = m;
9656 9656 continue;
9657 9657 }
9658 9658
9659 9659 xmlFreeNode(m);
9660 9660 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9661 9661 0 ||
9662 9662 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9663 9663 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9664 9664 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9665 9665 if (nonenv)
9666 9666 continue;
9667 9667 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9668 9668 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9669 9669 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9670 9670 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9671 9671 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 ||
9672 9672 strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9673 9673 if (nonenv && !use_profile)
9674 9674 continue;
9675 9675 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9676 9676 if (nonenv && use_profile)
9677 9677 continue;
9678 9678 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9679 9679 if (env != NULL)
9680 9680 continue;
9681 9681 }
9682 9682
9683 9683 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9684 9684 }
9685 9685 if (ret == -1)
9686 9686 scfdie();
9687 9687
9688 9688 (void) xmlAddChild(n, elts.stability);
9689 9689 (void) xmlAddChildList(n, elts.propvals);
9690 9690 (void) xmlAddChildList(n, elts.properties);
9691 9691
9692 9692 if (eelts->exec_methods == NULL)
9693 9693 eelts->exec_methods = n;
9694 9694 else
9695 9695 (void) xmlAddSibling(eelts->exec_methods, n);
9696 9696 }
9697 9697
9698 9698 static void
9699 9699 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9700 9700 struct entity_elts *eelts)
9701 9701 {
9702 9702 xmlNodePtr pgnode;
9703 9703
9704 9704 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9705 9705 if (pgnode == NULL)
9706 9706 uu_die(emsg_create_xml);
9707 9707
9708 9708 safe_setprop(pgnode, name_attr, name);
9709 9709 safe_setprop(pgnode, type_attr, type);
9710 9710
9711 9711 (void) xmlAddChildList(pgnode, elts->propvals);
9712 9712 (void) xmlAddChildList(pgnode, elts->properties);
9713 9713
9714 9714 if (eelts->property_groups == NULL)
9715 9715 eelts->property_groups = pgnode;
9716 9716 else
9717 9717 (void) xmlAddSibling(eelts->property_groups, pgnode);
9718 9718 }
9719 9719
9720 9720 /*
9721 9721 * Process the general property group for a service. This is the one with the
9722 9722 * goodies.
9723 9723 */
9724 9724 static void
9725 9725 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9726 9726 {
9727 9727 struct pg_elts elts;
9728 9728 int ret;
9729 9729
9730 9730 /*
9731 9731 * In case there are properties which don't correspond to child
9732 9732 * entities of the service entity, we'll set up a pg_elts structure to
9733 9733 * put them in.
9734 9734 */
9735 9735 (void) memset(&elts, 0, sizeof (elts));
9736 9736
9737 9737 /* Walk the properties, looking for special ones. */
9738 9738 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9739 9739 scfdie();
9740 9740
9741 9741 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9742 9742 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9743 9743 scfdie();
9744 9744
9745 9745 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9746 9746 /*
9747 9747 * Unimplemented and obsolete, but we still process it
9748 9748 * for compatibility purposes.
9749 9749 */
9750 9750 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9751 9751 prop_get_val(exp_prop, exp_val) == 0) {
9752 9752 uint8_t b;
9753 9753
9754 9754 if (scf_value_get_boolean(exp_val, &b) !=
9755 9755 SCF_SUCCESS)
9756 9756 scfdie();
9757 9757
9758 9758 if (b) {
9759 9759 selts->single_instance =
9760 9760 xmlNewNode(NULL,
9761 9761 (xmlChar *)"single_instance");
9762 9762 if (selts->single_instance == NULL)
9763 9763 uu_die(emsg_create_xml);
9764 9764 }
9765 9765
9766 9766 continue;
9767 9767 }
9768 9768 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9769 9769 xmlNodePtr rnode, sfnode;
9770 9770
9771 9771 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9772 9772 if (rnode == NULL)
9773 9773 uu_die(emsg_create_xml);
9774 9774
9775 9775 sfnode = xmlNewChild(rnode, NULL,
9776 9776 (xmlChar *)"service_fmri", NULL);
9777 9777 if (sfnode == NULL)
9778 9778 uu_die(emsg_create_xml);
9779 9779
9780 9780 if (set_attr_from_prop(exp_prop, sfnode,
9781 9781 value_attr) == 0) {
9782 9782 selts->restarter = rnode;
9783 9783 continue;
9784 9784 }
9785 9785
9786 9786 xmlFreeNode(rnode);
9787 9787 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9788 9788 0) {
9789 9789 xmlNodePtr s;
9790 9790
9791 9791 s = xmlNewNode(NULL, (xmlChar *)"stability");
9792 9792 if (s == NULL)
9793 9793 uu_die(emsg_create_xml);
9794 9794
9795 9795 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9796 9796 selts->stability = s;
9797 9797 continue;
9798 9798 }
9799 9799
9800 9800 xmlFreeNode(s);
9801 9801 }
9802 9802
9803 9803 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9804 9804 }
9805 9805 if (ret == -1)
9806 9806 scfdie();
9807 9807
9808 9808 if (elts.propvals != NULL || elts.properties != NULL)
9809 9809 export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9810 9810 selts);
9811 9811 }
9812 9812
9813 9813 static void
9814 9814 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9815 9815 {
9816 9816 xmlNodePtr n, prof, cred, env;
9817 9817 uint8_t use_profile;
9818 9818 int ret, err = 0;
9819 9819
9820 9820 n = xmlNewNode(NULL, (xmlChar *)"method_context");
9821 9821
9822 9822 env = export_method_environment(pg);
9823 9823
9824 9824 /* Need to know whether we'll use a profile or not. */
9825 9825 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9826 9826 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9827 9827 prop_get_val(exp_prop, exp_val) == 0) {
9828 9828 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9829 9829 scfdie();
9830 9830
9831 9831 if (use_profile)
9832 9832 prof =
9833 9833 xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9834 9834 NULL);
9835 9835 else
9836 9836 cred =
9837 9837 xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9838 9838 NULL);
9839 9839 }
9840 9840
9841 9841 if (env != NULL)
9842 9842 (void) xmlAddChild(n, env);
9843 9843
9844 9844 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9845 9845 scfdie();
9846 9846
9847 9847 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9848 9848 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9849 9849 scfdie();
9850 9850
9851 9851 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9852 9852 if (set_attr_from_prop(exp_prop, n,
9853 9853 "working_directory") != 0)
9854 9854 err = 1;
9855 9855 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9856 9856 if (set_attr_from_prop(exp_prop, n, "project") != 0)
9857 9857 err = 1;
9858 9858 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9859 9859 if (set_attr_from_prop(exp_prop, n,
9860 9860 "resource_pool") != 0)
9861 9861 err = 1;
9862 9862 } else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9863 9863 if (set_attr_from_prop(exp_prop, n,
9864 9864 "security_flags") != 0)
9865 9865 err = 1;
9866 9866 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9867 9867 /* EMPTY */
9868 9868 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9869 9869 if (use_profile ||
9870 9870 set_attr_from_prop(exp_prop, cred, "user") != 0)
9871 9871 err = 1;
9872 9872 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9873 9873 if (use_profile ||
9874 9874 set_attr_from_prop(exp_prop, cred, "group") != 0)
9875 9875 err = 1;
9876 9876 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9877 9877 if (use_profile || set_attr_from_prop(exp_prop, cred,
9878 9878 "supp_groups") != 0)
9879 9879 err = 1;
9880 9880 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9881 9881 if (use_profile || set_attr_from_prop(exp_prop, cred,
9882 9882 "privileges") != 0)
9883 9883 err = 1;
9884 9884 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9885 9885 0) {
9886 9886 if (use_profile || set_attr_from_prop(exp_prop, cred,
9887 9887 "limit_privileges") != 0)
9888 9888 err = 1;
9889 9889 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9890 9890 if (!use_profile || set_attr_from_prop(exp_prop,
9891 9891 prof, name_attr) != 0)
9892 9892 err = 1;
9893 9893 } else {
9894 9894 /* Can't have generic properties in method_context's */
9895 9895 err = 1;
9896 9896 }
9897 9897 }
9898 9898 if (ret == -1)
9899 9899 scfdie();
9900 9900
9901 9901 if (err && env == NULL) {
9902 9902 xmlFreeNode(n);
9903 9903 export_pg(pg, elts, SCE_ALL_VALUES);
9904 9904 return;
9905 9905 }
9906 9906
9907 9907 elts->method_context = n;
9908 9908 }
9909 9909
9910 9910 /*
9911 9911 * Given a dependency property group in the tfmri entity (target fmri), return
9912 9912 * a dependent element which represents it.
9913 9913 */
9914 9914 static xmlNodePtr
9915 9915 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9916 9916 {
9917 9917 uint8_t b;
9918 9918 xmlNodePtr n, sf;
9919 9919 int err = 0, ret;
9920 9920 struct pg_elts pgelts;
9921 9921
9922 9922 /*
9923 9923 * If external isn't set to true then exporting the service will
9924 9924 * export this as a normal dependency, so we should stop to avoid
9925 9925 * duplication.
9926 9926 */
9927 9927 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9928 9928 scf_property_get_value(exp_prop, exp_val) != 0 ||
9929 9929 scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9930 9930 if (g_verbose) {
9931 9931 warn(gettext("Dependent \"%s\" cannot be exported "
9932 9932 "properly because the \"%s\" property of the "
9933 9933 "\"%s\" dependency of %s is not set to true.\n"),
9934 9934 name, scf_property_external, name, tfmri);
9935 9935 }
9936 9936
9937 9937 return (NULL);
9938 9938 }
9939 9939
9940 9940 n = xmlNewNode(NULL, (xmlChar *)"dependent");
9941 9941 if (n == NULL)
9942 9942 uu_die(emsg_create_xml);
9943 9943
9944 9944 safe_setprop(n, name_attr, name);
9945 9945
9946 9946 /* Get the required attributes */
9947 9947 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9948 9948 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9949 9949 err = 1;
9950 9950
9951 9951 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9952 9952 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9953 9953 err = 1;
9954 9954
9955 9955 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9956 9956 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9957 9957 prop_get_val(exp_prop, exp_val) == 0) {
9958 9958 /* EMPTY */
9959 9959 } else
9960 9960 err = 1;
9961 9961
9962 9962 if (err) {
9963 9963 xmlFreeNode(n);
9964 9964 return (NULL);
9965 9965 }
9966 9966
9967 9967 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9968 9968 if (sf == NULL)
9969 9969 uu_die(emsg_create_xml);
9970 9970
9971 9971 safe_setprop(sf, value_attr, tfmri);
9972 9972
9973 9973 /*
9974 9974 * Now add elements for the other properties.
9975 9975 */
9976 9976 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9977 9977 scfdie();
9978 9978
9979 9979 (void) memset(&pgelts, 0, sizeof (pgelts));
9980 9980
9981 9981 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9982 9982 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9983 9983 scfdie();
9984 9984
9985 9985 if (strcmp(exp_str, scf_property_external) == 0 ||
9986 9986 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9987 9987 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9988 9988 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9989 9989 continue;
9990 9990 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9991 9991 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9992 9992 prop_get_val(exp_prop, exp_val) == 0) {
9993 9993 char type[sizeof ("service") + 1];
9994 9994
9995 9995 if (scf_value_get_astring(exp_val, type,
9996 9996 sizeof (type)) < 0)
9997 9997 scfdie();
9998 9998
9999 9999 if (strcmp(type, "service") == 0)
10000 10000 continue;
10001 10001 }
10002 10002 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
10003 10003 xmlNodePtr s;
10004 10004
10005 10005 s = xmlNewNode(NULL, (xmlChar *)"stability");
10006 10006 if (s == NULL)
10007 10007 uu_die(emsg_create_xml);
10008 10008
10009 10009 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
10010 10010 pgelts.stability = s;
10011 10011 continue;
10012 10012 }
10013 10013
10014 10014 xmlFreeNode(s);
10015 10015 }
10016 10016
10017 10017 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10018 10018 }
10019 10019 if (ret == -1)
10020 10020 scfdie();
10021 10021
10022 10022 (void) xmlAddChild(n, pgelts.stability);
10023 10023 (void) xmlAddChildList(n, pgelts.propvals);
10024 10024 (void) xmlAddChildList(n, pgelts.properties);
10025 10025
10026 10026 return (n);
10027 10027 }
10028 10028
10029 10029 static void
10030 10030 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10031 10031 {
10032 10032 scf_propertygroup_t *opg;
10033 10033 scf_iter_t *iter;
10034 10034 char *type, *fmri;
10035 10035 int ret;
10036 10036 struct pg_elts pgelts;
10037 10037 xmlNodePtr n;
10038 10038 scf_error_t serr;
10039 10039
10040 10040 if ((opg = scf_pg_create(g_hndl)) == NULL ||
10041 10041 (iter = scf_iter_create(g_hndl)) == NULL)
10042 10042 scfdie();
10043 10043
10044 10044 /* Can't use exp_prop_iter due to export_dependent(). */
10045 10045 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10046 10046 scfdie();
10047 10047
10048 10048 type = safe_malloc(max_scf_pg_type_len + 1);
10049 10049
10050 10050 /* Get an extra byte so we can tell if values are too long. */
10051 10051 fmri = safe_malloc(max_scf_fmri_len + 2);
10052 10052
10053 10053 (void) memset(&pgelts, 0, sizeof (pgelts));
10054 10054
10055 10055 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10056 10056 void *entity;
10057 10057 int isservice;
10058 10058 scf_type_t ty;
10059 10059
10060 10060 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10061 10061 scfdie();
10062 10062
10063 10063 if ((ty != SCF_TYPE_ASTRING &&
10064 10064 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10065 10065 prop_get_val(exp_prop, exp_val) != 0) {
10066 10066 export_property(exp_prop, NULL, &pgelts,
10067 10067 SCE_ALL_VALUES);
10068 10068 continue;
10069 10069 }
10070 10070
10071 10071 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10072 10072 scfdie();
10073 10073
10074 10074 if (scf_value_get_astring(exp_val, fmri,
10075 10075 max_scf_fmri_len + 2) < 0)
10076 10076 scfdie();
10077 10077
10078 10078 /* Look for a dependency group in the target fmri. */
10079 10079 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10080 10080 switch (serr) {
10081 10081 case SCF_ERROR_NONE:
10082 10082 break;
10083 10083
10084 10084 case SCF_ERROR_NO_MEMORY:
10085 10085 uu_die(gettext("Out of memory.\n"));
10086 10086 /* NOTREACHED */
10087 10087
10088 10088 case SCF_ERROR_INVALID_ARGUMENT:
10089 10089 if (g_verbose) {
10090 10090 if (scf_property_to_fmri(exp_prop, fmri,
10091 10091 max_scf_fmri_len + 2) < 0)
10092 10092 scfdie();
10093 10093
10094 10094 warn(gettext("The value of %s is not a valid "
10095 10095 "FMRI.\n"), fmri);
10096 10096 }
10097 10097
10098 10098 export_property(exp_prop, exp_str, &pgelts,
10099 10099 SCE_ALL_VALUES);
10100 10100 continue;
10101 10101
10102 10102 case SCF_ERROR_CONSTRAINT_VIOLATED:
10103 10103 if (g_verbose) {
10104 10104 if (scf_property_to_fmri(exp_prop, fmri,
10105 10105 max_scf_fmri_len + 2) < 0)
10106 10106 scfdie();
10107 10107
10108 10108 warn(gettext("The value of %s does not specify "
10109 10109 "a service or an instance.\n"), fmri);
10110 10110 }
10111 10111
10112 10112 export_property(exp_prop, exp_str, &pgelts,
10113 10113 SCE_ALL_VALUES);
10114 10114 continue;
10115 10115
10116 10116 case SCF_ERROR_NOT_FOUND:
10117 10117 if (g_verbose) {
10118 10118 if (scf_property_to_fmri(exp_prop, fmri,
10119 10119 max_scf_fmri_len + 2) < 0)
10120 10120 scfdie();
10121 10121
10122 10122 warn(gettext("The entity specified by %s does "
10123 10123 "not exist.\n"), fmri);
10124 10124 }
10125 10125
10126 10126 export_property(exp_prop, exp_str, &pgelts,
10127 10127 SCE_ALL_VALUES);
10128 10128 continue;
10129 10129
10130 10130 default:
10131 10131 #ifndef NDEBUG
10132 10132 (void) fprintf(stderr, "%s:%d: %s() failed with "
10133 10133 "unexpected error %d.\n", __FILE__, __LINE__,
10134 10134 "fmri_to_entity", serr);
10135 10135 #endif
10136 10136 abort();
10137 10137 }
10138 10138
10139 10139 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10140 10140 if (scf_error() != SCF_ERROR_NOT_FOUND)
10141 10141 scfdie();
10142 10142
10143 10143 warn(gettext("Entity %s is missing dependency property "
10144 10144 "group %s.\n"), fmri, exp_str);
10145 10145
10146 10146 export_property(exp_prop, NULL, &pgelts,
10147 10147 SCE_ALL_VALUES);
10148 10148 continue;
10149 10149 }
10150 10150
10151 10151 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10152 10152 scfdie();
10153 10153
10154 10154 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10155 10155 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10156 10156 scfdie();
10157 10157
10158 10158 warn(gettext("Property group %s is not of "
10159 10159 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10160 10160
10161 10161 export_property(exp_prop, NULL, &pgelts,
10162 10162 SCE_ALL_VALUES);
10163 10163 continue;
10164 10164 }
10165 10165
10166 10166 n = export_dependent(opg, exp_str, fmri);
10167 10167 if (n == NULL) {
10168 10168 export_property(exp_prop, exp_str, &pgelts,
10169 10169 SCE_ALL_VALUES);
10170 10170 } else {
10171 10171 if (eelts->dependents == NULL)
10172 10172 eelts->dependents = n;
10173 10173 else
10174 10174 (void) xmlAddSibling(eelts->dependents,
10175 10175 n);
10176 10176 }
10177 10177 }
10178 10178 if (ret == -1)
10179 10179 scfdie();
10180 10180
10181 10181 free(fmri);
10182 10182 free(type);
10183 10183
10184 10184 scf_iter_destroy(iter);
10185 10185 scf_pg_destroy(opg);
10186 10186
10187 10187 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10188 10188 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10189 10189 eelts);
10190 10190 }
10191 10191
10192 10192 static void
10193 10193 make_node(xmlNodePtr *nodep, const char *name)
10194 10194 {
10195 10195 if (*nodep == NULL) {
10196 10196 *nodep = xmlNewNode(NULL, (xmlChar *)name);
10197 10197 if (*nodep == NULL)
10198 10198 uu_die(emsg_create_xml);
10199 10199 }
10200 10200 }
10201 10201
10202 10202 static xmlNodePtr
10203 10203 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10204 10204 {
10205 10205 int ret;
10206 10206 xmlNodePtr parent = NULL;
10207 10207 xmlNodePtr loctext = NULL;
10208 10208
10209 10209 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10210 10210 scfdie();
10211 10211
10212 10212 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10213 10213 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10214 10214 prop_get_val(exp_prop, exp_val) != 0)
10215 10215 continue;
10216 10216
10217 10217 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10218 10218 scfdie();
10219 10219
10220 10220 make_node(&parent, parname);
10221 10221 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10222 10222 (xmlChar *)exp_str);
10223 10223 if (loctext == NULL)
10224 10224 uu_die(emsg_create_xml);
10225 10225
10226 10226 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10227 10227 scfdie();
10228 10228
10229 10229 safe_setprop(loctext, "xml:lang", exp_str);
10230 10230 }
10231 10231
10232 10232 if (ret == -1)
10233 10233 scfdie();
10234 10234
10235 10235 return (parent);
10236 10236 }
10237 10237
10238 10238 static xmlNodePtr
10239 10239 export_tm_manpage(scf_propertygroup_t *pg)
10240 10240 {
10241 10241 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10242 10242 if (manpage == NULL)
10243 10243 uu_die(emsg_create_xml);
10244 10244
10245 10245 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10246 10246 set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10247 10247 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10248 10248 set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10249 10249 xmlFreeNode(manpage);
10250 10250 return (NULL);
10251 10251 }
10252 10252
10253 10253 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10254 10254 (void) set_attr_from_prop_default(exp_prop,
10255 10255 manpage, "manpath", ":default");
10256 10256
10257 10257 return (manpage);
10258 10258 }
10259 10259
10260 10260 static xmlNodePtr
10261 10261 export_tm_doc_link(scf_propertygroup_t *pg)
10262 10262 {
10263 10263 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10264 10264 if (doc_link == NULL)
10265 10265 uu_die(emsg_create_xml);
10266 10266
10267 10267 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10268 10268 set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10269 10269 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10270 10270 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10271 10271 xmlFreeNode(doc_link);
10272 10272 return (NULL);
10273 10273 }
10274 10274 return (doc_link);
10275 10275 }
10276 10276
10277 10277 /*
10278 10278 * Process template information for a service or instances.
10279 10279 */
10280 10280 static void
10281 10281 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10282 10282 struct template_elts *telts)
10283 10283 {
10284 10284 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10285 10285 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10286 10286 xmlNodePtr child = NULL;
10287 10287
10288 10288 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10289 10289 scfdie();
10290 10290
10291 10291 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10292 10292 telts->common_name = export_tm_loctext(pg, "common_name");
10293 10293 if (telts->common_name == NULL)
10294 10294 export_pg(pg, elts, SCE_ALL_VALUES);
10295 10295 return;
10296 10296 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10297 10297 telts->description = export_tm_loctext(pg, "description");
10298 10298 if (telts->description == NULL)
10299 10299 export_pg(pg, elts, SCE_ALL_VALUES);
10300 10300 return;
10301 10301 }
10302 10302
10303 10303 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10304 10304 child = export_tm_manpage(pg);
10305 10305 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10306 10306 child = export_tm_doc_link(pg);
10307 10307 }
10308 10308
10309 10309 if (child != NULL) {
10310 10310 make_node(&telts->documentation, "documentation");
10311 10311 (void) xmlAddChild(telts->documentation, child);
10312 10312 } else {
10313 10313 export_pg(pg, elts, SCE_ALL_VALUES);
10314 10314 }
10315 10315 }
10316 10316
10317 10317 /*
10318 10318 * Process parameter and paramval elements
10319 10319 */
10320 10320 static void
10321 10321 export_parameter(scf_property_t *prop, const char *name,
10322 10322 struct params_elts *elts)
10323 10323 {
10324 10324 xmlNodePtr param;
10325 10325 scf_error_t err = 0;
10326 10326 int ret;
10327 10327
10328 10328 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10329 10329 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10330 10330 uu_die(emsg_create_xml);
10331 10331
10332 10332 safe_setprop(param, name_attr, name);
10333 10333
10334 10334 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10335 10335 scfdie();
10336 10336 safe_setprop(param, value_attr, exp_str);
10337 10337
10338 10338 if (elts->paramval == NULL)
10339 10339 elts->paramval = param;
10340 10340 else
10341 10341 (void) xmlAddSibling(elts->paramval, param);
10342 10342
10343 10343 return;
10344 10344 }
10345 10345
10346 10346 err = scf_error();
10347 10347
10348 10348 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10349 10349 err != SCF_ERROR_NOT_FOUND)
10350 10350 scfdie();
10351 10351
10352 10352 if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10353 10353 uu_die(emsg_create_xml);
10354 10354
10355 10355 safe_setprop(param, name_attr, name);
10356 10356
10357 10357 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10358 10358 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10359 10359 scfdie();
10360 10360
10361 10361 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10362 10362 1) {
10363 10363 xmlNodePtr vn;
10364 10364
10365 10365 if ((vn = xmlNewChild(param, NULL,
10366 10366 (xmlChar *)"value_node", NULL)) == NULL)
10367 10367 uu_die(emsg_create_xml);
10368 10368
10369 10369 if (scf_value_get_as_string(exp_val, exp_str,
10370 10370 exp_str_sz) < 0)
10371 10371 scfdie();
10372 10372
10373 10373 safe_setprop(vn, value_attr, exp_str);
10374 10374 }
10375 10375 if (ret != 0)
10376 10376 scfdie();
10377 10377 }
10378 10378
10379 10379 if (elts->parameter == NULL)
10380 10380 elts->parameter = param;
10381 10381 else
10382 10382 (void) xmlAddSibling(elts->parameter, param);
10383 10383 }
10384 10384
10385 10385 /*
10386 10386 * Process notification parameters for a service or instance
10387 10387 */
10388 10388 static void
10389 10389 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10390 10390 {
10391 10391 xmlNodePtr n, event, *type;
10392 10392 struct params_elts *eelts;
10393 10393 int ret, err, i;
10394 10394 char *s;
10395 10395
10396 10396 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10397 10397 event = xmlNewNode(NULL, (xmlChar *)"event");
10398 10398 if (n == NULL || event == NULL)
10399 10399 uu_die(emsg_create_xml);
10400 10400
10401 10401 /* event value */
10402 10402 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10403 10403 scfdie();
10404 10404 /* trim SCF_NOTIFY_PG_POSTFIX appended to name on import */
10405 10405 if ((s = strchr(exp_str, ',')) != NULL)
10406 10406 *s = '\0';
10407 10407 safe_setprop(event, value_attr, exp_str);
10408 10408
10409 10409 (void) xmlAddChild(n, event);
10410 10410
10411 10411 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10412 10412 (eelts = calloc(URI_SCHEME_NUM,
10413 10413 sizeof (struct params_elts))) == NULL)
10414 10414 uu_die(gettext("Out of memory.\n"));
10415 10415
10416 10416 err = 0;
10417 10417
10418 10418 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10419 10419 scfdie();
10420 10420
10421 10421 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10422 10422 char *t, *p;
10423 10423
10424 10424 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10425 10425 scfdie();
10426 10426
10427 10427 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10428 10428 /*
10429 10429 * this is not a well formed notification parameters
10430 10430 * element, we should export as regular pg
10431 10431 */
10432 10432 err = 1;
10433 10433 break;
10434 10434 }
10435 10435
10436 10436 if ((i = check_uri_protocol(t)) < 0) {
10437 10437 err = 1;
10438 10438 break;
10439 10439 }
10440 10440
10441 10441 if (type[i] == NULL) {
10442 10442 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10443 10443 NULL)
10444 10444 uu_die(emsg_create_xml);
10445 10445
10446 10446 safe_setprop(type[i], name_attr, t);
10447 10447 }
10448 10448 if (strcmp(p, active_attr) == 0) {
10449 10449 if (set_attr_from_prop(exp_prop, type[i],
10450 10450 active_attr) != 0) {
10451 10451 err = 1;
10452 10452 break;
10453 10453 }
10454 10454 continue;
10455 10455 }
10456 10456 /*
10457 10457 * We export the parameter
10458 10458 */
10459 10459 export_parameter(exp_prop, p, &eelts[i]);
10460 10460 }
10461 10461
10462 10462 if (ret == -1)
10463 10463 scfdie();
10464 10464
10465 10465 if (err == 1) {
10466 10466 for (i = 0; i < URI_SCHEME_NUM; ++i)
10467 10467 xmlFree(type[i]);
10468 10468 free(type);
10469 10469
10470 10470 export_pg(pg, elts, SCE_ALL_VALUES);
10471 10471
10472 10472 return;
10473 10473 } else {
10474 10474 for (i = 0; i < URI_SCHEME_NUM; ++i)
10475 10475 if (type[i] != NULL) {
10476 10476 (void) xmlAddChildList(type[i],
10477 10477 eelts[i].paramval);
10478 10478 (void) xmlAddChildList(type[i],
10479 10479 eelts[i].parameter);
10480 10480 (void) xmlAddSibling(event, type[i]);
10481 10481 }
10482 10482 }
10483 10483 free(type);
10484 10484
10485 10485 if (elts->notify_params == NULL)
10486 10486 elts->notify_params = n;
10487 10487 else
10488 10488 (void) xmlAddSibling(elts->notify_params, n);
10489 10489 }
10490 10490
10491 10491 /*
10492 10492 * Process the general property group for an instance.
10493 10493 */
10494 10494 static void
10495 10495 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10496 10496 struct entity_elts *elts)
10497 10497 {
10498 10498 uint8_t enabled;
10499 10499 struct pg_elts pgelts;
10500 10500 int ret;
10501 10501
10502 10502 /* enabled */
10503 10503 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10504 10504 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10505 10505 prop_get_val(exp_prop, exp_val) == 0) {
10506 10506 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10507 10507 scfdie();
10508 10508 } else {
10509 10509 enabled = 0;
10510 10510 }
10511 10511
10512 10512 safe_setprop(inode, enabled_attr, enabled ? true : false);
10513 10513
10514 10514 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
↓ open down ↓ |
10480 lines elided |
↑ open up ↑ |
10515 10515 scfdie();
10516 10516
10517 10517 (void) memset(&pgelts, 0, sizeof (pgelts));
10518 10518
10519 10519 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10520 10520 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10521 10521 scfdie();
10522 10522
10523 10523 if (strcmp(exp_str, scf_property_enabled) == 0) {
10524 10524 continue;
10525 + } else if (strcmp(exp_str, SCF_PROPERTY_COMMENT) == 0) {
10526 + continue;
10525 10527 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10526 10528 xmlNodePtr rnode, sfnode;
10527 10529
10528 10530 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10529 10531 if (rnode == NULL)
10530 10532 uu_die(emsg_create_xml);
10531 10533
10532 10534 sfnode = xmlNewChild(rnode, NULL,
10533 10535 (xmlChar *)"service_fmri", NULL);
10534 10536 if (sfnode == NULL)
10535 10537 uu_die(emsg_create_xml);
10536 10538
10537 10539 if (set_attr_from_prop(exp_prop, sfnode,
10538 10540 value_attr) == 0) {
10539 10541 elts->restarter = rnode;
10540 10542 continue;
10541 10543 }
10542 10544
10543 10545 xmlFreeNode(rnode);
10544 10546 }
10545 10547
10546 10548 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10547 10549 }
10548 10550 if (ret == -1)
10549 10551 scfdie();
10550 10552
10551 10553 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10552 10554 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10553 10555 elts);
10554 10556 }
10555 10557
10556 10558 /*
10557 10559 * Put an instance element for the given instance into selts.
10558 10560 */
10559 10561 static void
10560 10562 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10561 10563 {
10562 10564 xmlNodePtr n;
10563 10565 boolean_t isdefault;
10564 10566 struct entity_elts elts;
10565 10567 struct template_elts template_elts;
10566 10568 int ret;
10567 10569
10568 10570 n = xmlNewNode(NULL, (xmlChar *)"instance");
10569 10571 if (n == NULL)
10570 10572 uu_die(emsg_create_xml);
10571 10573
10572 10574 /* name */
10573 10575 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10574 10576 scfdie();
10575 10577 safe_setprop(n, name_attr, exp_str);
10576 10578 isdefault = strcmp(exp_str, "default") == 0;
10577 10579
10578 10580 /* check existance of general pg (since general/enabled is required) */
10579 10581 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10580 10582 if (scf_error() != SCF_ERROR_NOT_FOUND)
10581 10583 scfdie();
10582 10584
10583 10585 if (g_verbose) {
10584 10586 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10585 10587 scfdie();
10586 10588
10587 10589 warn(gettext("Instance %s has no general property "
10588 10590 "group; it will be marked disabled.\n"), exp_str);
10589 10591 }
10590 10592
10591 10593 safe_setprop(n, enabled_attr, false);
10592 10594 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10593 10595 strcmp(exp_str, scf_group_framework) != 0) {
10594 10596 if (g_verbose) {
10595 10597 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10596 10598 scfdie();
10597 10599
10598 10600 warn(gettext("Property group %s is not of type "
10599 10601 "framework; the instance will be marked "
10600 10602 "disabled.\n"), exp_str);
10601 10603 }
10602 10604
10603 10605 safe_setprop(n, enabled_attr, false);
10604 10606 }
10605 10607
10606 10608 /* property groups */
10607 10609 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10608 10610 scfdie();
10609 10611
10610 10612 (void) memset(&elts, 0, sizeof (elts));
10611 10613 (void) memset(&template_elts, 0, sizeof (template_elts));
10612 10614
10613 10615 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10614 10616 uint32_t pgflags;
10615 10617
10616 10618 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10617 10619 scfdie();
10618 10620
10619 10621 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10620 10622 continue;
10621 10623
10622 10624 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10623 10625 scfdie();
10624 10626
10625 10627 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10626 10628 export_dependency(exp_pg, &elts);
10627 10629 continue;
10628 10630 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10629 10631 export_method(exp_pg, &elts);
10630 10632 continue;
10631 10633 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10632 10634 if (scf_pg_get_name(exp_pg, exp_str,
10633 10635 max_scf_name_len + 1) < 0)
10634 10636 scfdie();
10635 10637
10636 10638 if (strcmp(exp_str, scf_pg_general) == 0) {
10637 10639 export_inst_general(exp_pg, n, &elts);
10638 10640 continue;
10639 10641 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10640 10642 0) {
10641 10643 export_method_context(exp_pg, &elts);
10642 10644 continue;
10643 10645 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10644 10646 export_dependents(exp_pg, &elts);
10645 10647 continue;
10646 10648 }
10647 10649 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10648 10650 export_template(exp_pg, &elts, &template_elts);
10649 10651 continue;
10650 10652 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10651 10653 export_notify_params(exp_pg, &elts);
10652 10654 continue;
10653 10655 }
10654 10656
10655 10657 /* Ordinary pg. */
10656 10658 export_pg(exp_pg, &elts, flags);
10657 10659 }
10658 10660 if (ret == -1)
10659 10661 scfdie();
10660 10662
10661 10663 if (template_elts.common_name != NULL) {
10662 10664 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10663 10665 (void) xmlAddChild(elts.template, template_elts.common_name);
10664 10666 (void) xmlAddChild(elts.template, template_elts.description);
10665 10667 (void) xmlAddChild(elts.template, template_elts.documentation);
10666 10668 } else {
10667 10669 xmlFreeNode(template_elts.description);
10668 10670 xmlFreeNode(template_elts.documentation);
10669 10671 }
10670 10672
10671 10673 if (isdefault && elts.restarter == NULL &&
10672 10674 elts.dependencies == NULL && elts.method_context == NULL &&
10673 10675 elts.exec_methods == NULL && elts.notify_params == NULL &&
10674 10676 elts.property_groups == NULL && elts.template == NULL) {
10675 10677 xmlChar *eval;
10676 10678
10677 10679 /* This is a default instance */
10678 10680 eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10679 10681
10680 10682 xmlFreeNode(n);
10681 10683
10682 10684 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10683 10685 if (n == NULL)
10684 10686 uu_die(emsg_create_xml);
10685 10687
10686 10688 safe_setprop(n, enabled_attr, (char *)eval);
10687 10689 xmlFree(eval);
10688 10690
10689 10691 selts->create_default_instance = n;
10690 10692 } else {
10691 10693 /* Assemble the children in order. */
10692 10694 (void) xmlAddChild(n, elts.restarter);
10693 10695 (void) xmlAddChildList(n, elts.dependencies);
10694 10696 (void) xmlAddChildList(n, elts.dependents);
10695 10697 (void) xmlAddChild(n, elts.method_context);
10696 10698 (void) xmlAddChildList(n, elts.exec_methods);
10697 10699 (void) xmlAddChildList(n, elts.notify_params);
10698 10700 (void) xmlAddChildList(n, elts.property_groups);
10699 10701 (void) xmlAddChild(n, elts.template);
10700 10702
10701 10703 if (selts->instances == NULL)
10702 10704 selts->instances = n;
10703 10705 else
10704 10706 (void) xmlAddSibling(selts->instances, n);
10705 10707 }
10706 10708 }
10707 10709
10708 10710 /*
10709 10711 * Return a service element for the given service.
10710 10712 */
10711 10713 static xmlNodePtr
10712 10714 export_service(scf_service_t *svc, int flags)
10713 10715 {
10714 10716 xmlNodePtr snode;
10715 10717 struct entity_elts elts;
10716 10718 struct template_elts template_elts;
10717 10719 int ret;
10718 10720
10719 10721 snode = xmlNewNode(NULL, (xmlChar *)"service");
10720 10722 if (snode == NULL)
10721 10723 uu_die(emsg_create_xml);
10722 10724
10723 10725 /* Get & set name attribute */
10724 10726 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10725 10727 scfdie();
10726 10728 safe_setprop(snode, name_attr, exp_str);
10727 10729
10728 10730 safe_setprop(snode, type_attr, "service");
10729 10731 safe_setprop(snode, "version", "0");
10730 10732
10731 10733 /* Acquire child elements. */
10732 10734 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10733 10735 scfdie();
10734 10736
10735 10737 (void) memset(&elts, 0, sizeof (elts));
10736 10738 (void) memset(&template_elts, 0, sizeof (template_elts));
10737 10739
10738 10740 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10739 10741 uint32_t pgflags;
10740 10742
10741 10743 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10742 10744 scfdie();
10743 10745
10744 10746 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10745 10747 continue;
10746 10748
10747 10749 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10748 10750 scfdie();
10749 10751
10750 10752 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10751 10753 export_dependency(exp_pg, &elts);
10752 10754 continue;
10753 10755 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10754 10756 export_method(exp_pg, &elts);
10755 10757 continue;
10756 10758 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10757 10759 if (scf_pg_get_name(exp_pg, exp_str,
10758 10760 max_scf_name_len + 1) < 0)
10759 10761 scfdie();
10760 10762
10761 10763 if (strcmp(exp_str, scf_pg_general) == 0) {
10762 10764 export_svc_general(exp_pg, &elts);
10763 10765 continue;
10764 10766 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10765 10767 0) {
10766 10768 export_method_context(exp_pg, &elts);
10767 10769 continue;
10768 10770 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10769 10771 export_dependents(exp_pg, &elts);
10770 10772 continue;
10771 10773 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10772 10774 continue;
10773 10775 }
10774 10776 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10775 10777 export_template(exp_pg, &elts, &template_elts);
10776 10778 continue;
10777 10779 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10778 10780 export_notify_params(exp_pg, &elts);
10779 10781 continue;
10780 10782 }
10781 10783
10782 10784 export_pg(exp_pg, &elts, flags);
10783 10785 }
10784 10786 if (ret == -1)
10785 10787 scfdie();
10786 10788
10787 10789 if (template_elts.common_name != NULL) {
10788 10790 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10789 10791 (void) xmlAddChild(elts.template, template_elts.common_name);
10790 10792 (void) xmlAddChild(elts.template, template_elts.description);
10791 10793 (void) xmlAddChild(elts.template, template_elts.documentation);
10792 10794 } else {
10793 10795 xmlFreeNode(template_elts.description);
10794 10796 xmlFreeNode(template_elts.documentation);
10795 10797 }
10796 10798
10797 10799 /* Iterate instances */
10798 10800 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10799 10801 scfdie();
10800 10802
10801 10803 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10802 10804 export_instance(exp_inst, &elts, flags);
10803 10805 if (ret == -1)
10804 10806 scfdie();
10805 10807
10806 10808 /* Now add all of the accumulated elements in order. */
10807 10809 (void) xmlAddChild(snode, elts.create_default_instance);
10808 10810 (void) xmlAddChild(snode, elts.single_instance);
10809 10811 (void) xmlAddChild(snode, elts.restarter);
10810 10812 (void) xmlAddChildList(snode, elts.dependencies);
10811 10813 (void) xmlAddChildList(snode, elts.dependents);
10812 10814 (void) xmlAddChild(snode, elts.method_context);
10813 10815 (void) xmlAddChildList(snode, elts.exec_methods);
10814 10816 (void) xmlAddChildList(snode, elts.notify_params);
10815 10817 (void) xmlAddChildList(snode, elts.property_groups);
10816 10818 (void) xmlAddChildList(snode, elts.instances);
10817 10819 (void) xmlAddChild(snode, elts.stability);
10818 10820 (void) xmlAddChild(snode, elts.template);
10819 10821
10820 10822 return (snode);
10821 10823 }
10822 10824
10823 10825 static int
10824 10826 export_callback(void *data, scf_walkinfo_t *wip)
10825 10827 {
10826 10828 FILE *f;
10827 10829 xmlDocPtr doc;
10828 10830 xmlNodePtr sb;
10829 10831 int result;
10830 10832 struct export_args *argsp = (struct export_args *)data;
10831 10833
10832 10834 if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10833 10835 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10834 10836 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10835 10837 (exp_val = scf_value_create(g_hndl)) == NULL ||
10836 10838 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10837 10839 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10838 10840 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10839 10841 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10840 10842 scfdie();
10841 10843
10842 10844 exp_str_sz = max_scf_len + 1;
10843 10845 exp_str = safe_malloc(exp_str_sz);
10844 10846
10845 10847 if (argsp->filename != NULL) {
10846 10848 errno = 0;
10847 10849 f = fopen(argsp->filename, "wb");
10848 10850 if (f == NULL) {
10849 10851 if (errno == 0)
10850 10852 uu_die(gettext("Could not open \"%s\": no free "
10851 10853 "stdio streams.\n"), argsp->filename);
10852 10854 else
10853 10855 uu_die(gettext("Could not open \"%s\""),
10854 10856 argsp->filename);
10855 10857 }
10856 10858 } else
10857 10859 f = stdout;
10858 10860
10859 10861 doc = xmlNewDoc((xmlChar *)"1.0");
10860 10862 if (doc == NULL)
10861 10863 uu_die(gettext("Could not create XML document.\n"));
10862 10864
10863 10865 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10864 10866 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10865 10867 uu_die(emsg_create_xml);
10866 10868
10867 10869 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10868 10870 if (sb == NULL)
10869 10871 uu_die(emsg_create_xml);
10870 10872 safe_setprop(sb, type_attr, "manifest");
10871 10873 safe_setprop(sb, name_attr, "export");
10872 10874 (void) xmlAddSibling(doc->children, sb);
10873 10875
10874 10876 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10875 10877
10876 10878 result = write_service_bundle(doc, f);
10877 10879
10878 10880 free(exp_str);
10879 10881 scf_iter_destroy(exp_val_iter);
10880 10882 scf_iter_destroy(exp_prop_iter);
10881 10883 scf_iter_destroy(exp_pg_iter);
10882 10884 scf_iter_destroy(exp_inst_iter);
10883 10885 scf_value_destroy(exp_val);
10884 10886 scf_property_destroy(exp_prop);
10885 10887 scf_pg_destroy(exp_pg);
10886 10888 scf_instance_destroy(exp_inst);
10887 10889
10888 10890 xmlFreeDoc(doc);
10889 10891
10890 10892 if (f != stdout)
10891 10893 (void) fclose(f);
10892 10894
10893 10895 return (result);
10894 10896 }
10895 10897
10896 10898 /*
10897 10899 * Get the service named by fmri, build an XML tree which represents it, and
10898 10900 * dump it into filename (or stdout if filename is NULL).
10899 10901 */
10900 10902 int
10901 10903 lscf_service_export(char *fmri, const char *filename, int flags)
10902 10904 {
10903 10905 struct export_args args;
10904 10906 char *fmridup;
10905 10907 const char *scope, *svc, *inst;
10906 10908 size_t cblen = 3 * max_scf_name_len;
10907 10909 char *canonbuf = alloca(cblen);
10908 10910 int ret, err;
10909 10911
10910 10912 lscf_prep_hndl();
10911 10913
10912 10914 bzero(&args, sizeof (args));
10913 10915 args.filename = filename;
10914 10916 args.flags = flags;
10915 10917
10916 10918 /*
10917 10919 * If some poor user has passed an exact instance FMRI, of the sort
10918 10920 * one might cut and paste from svcs(1) or an error message, warn
10919 10921 * and chop off the instance instead of failing.
10920 10922 */
10921 10923 fmridup = alloca(strlen(fmri) + 1);
10922 10924 (void) strcpy(fmridup, fmri);
10923 10925 if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10924 10926 sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10925 10927 scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10926 10928 inst != NULL) {
10927 10929 (void) strlcpy(canonbuf, "svc:/", cblen);
10928 10930 if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10929 10931 (void) strlcat(canonbuf, "/", cblen);
10930 10932 (void) strlcat(canonbuf, scope, cblen);
10931 10933 }
10932 10934 (void) strlcat(canonbuf, svc, cblen);
10933 10935 fmri = canonbuf;
10934 10936
10935 10937 warn(gettext("Only services may be exported; ignoring "
10936 10938 "instance portion of argument.\n"));
10937 10939 }
10938 10940
10939 10941 err = 0;
10940 10942 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10941 10943 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10942 10944 &args, &err, semerr)) != 0) {
10943 10945 if (ret != -1)
10944 10946 semerr(gettext("Failed to walk instances: %s\n"),
10945 10947 scf_strerror(ret));
10946 10948 return (-1);
10947 10949 }
10948 10950
10949 10951 /*
10950 10952 * Error message has already been printed.
10951 10953 */
10952 10954 if (err != 0)
10953 10955 return (-1);
10954 10956
10955 10957 return (0);
10956 10958 }
10957 10959
10958 10960
10959 10961 /*
10960 10962 * Archive
10961 10963 */
10962 10964
10963 10965 static xmlNodePtr
10964 10966 make_archive(int flags)
10965 10967 {
10966 10968 xmlNodePtr sb;
10967 10969 scf_scope_t *scope;
10968 10970 scf_service_t *svc;
10969 10971 scf_iter_t *iter;
10970 10972 int r;
10971 10973
10972 10974 if ((scope = scf_scope_create(g_hndl)) == NULL ||
10973 10975 (svc = scf_service_create(g_hndl)) == NULL ||
10974 10976 (iter = scf_iter_create(g_hndl)) == NULL ||
10975 10977 (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10976 10978 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10977 10979 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10978 10980 (exp_val = scf_value_create(g_hndl)) == NULL ||
10979 10981 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10980 10982 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10981 10983 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10982 10984 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10983 10985 scfdie();
10984 10986
10985 10987 exp_str_sz = max_scf_len + 1;
10986 10988 exp_str = safe_malloc(exp_str_sz);
10987 10989
10988 10990 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10989 10991 if (sb == NULL)
10990 10992 uu_die(emsg_create_xml);
10991 10993 safe_setprop(sb, type_attr, "archive");
10992 10994 safe_setprop(sb, name_attr, "none");
10993 10995
10994 10996 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10995 10997 scfdie();
10996 10998 if (scf_iter_scope_services(iter, scope) != 0)
10997 10999 scfdie();
10998 11000
10999 11001 for (;;) {
11000 11002 r = scf_iter_next_service(iter, svc);
11001 11003 if (r == 0)
11002 11004 break;
11003 11005 if (r != 1)
11004 11006 scfdie();
11005 11007
11006 11008 if (scf_service_get_name(svc, exp_str,
11007 11009 max_scf_name_len + 1) < 0)
11008 11010 scfdie();
11009 11011
11010 11012 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
11011 11013 continue;
11012 11014
11013 11015 (void) xmlAddChild(sb, export_service(svc, flags));
11014 11016 }
11015 11017
11016 11018 free(exp_str);
11017 11019
11018 11020 scf_iter_destroy(exp_val_iter);
11019 11021 scf_iter_destroy(exp_prop_iter);
11020 11022 scf_iter_destroy(exp_pg_iter);
11021 11023 scf_iter_destroy(exp_inst_iter);
11022 11024 scf_value_destroy(exp_val);
11023 11025 scf_property_destroy(exp_prop);
11024 11026 scf_pg_destroy(exp_pg);
11025 11027 scf_instance_destroy(exp_inst);
11026 11028 scf_iter_destroy(iter);
11027 11029 scf_service_destroy(svc);
11028 11030 scf_scope_destroy(scope);
11029 11031
11030 11032 return (sb);
11031 11033 }
11032 11034
11033 11035 int
11034 11036 lscf_archive(const char *filename, int flags)
11035 11037 {
11036 11038 FILE *f;
11037 11039 xmlDocPtr doc;
11038 11040 int result;
11039 11041
11040 11042 lscf_prep_hndl();
11041 11043
11042 11044 if (filename != NULL) {
11043 11045 errno = 0;
11044 11046 f = fopen(filename, "wb");
11045 11047 if (f == NULL) {
11046 11048 if (errno == 0)
11047 11049 uu_die(gettext("Could not open \"%s\": no free "
11048 11050 "stdio streams.\n"), filename);
11049 11051 else
11050 11052 uu_die(gettext("Could not open \"%s\""),
11051 11053 filename);
11052 11054 }
11053 11055 } else
11054 11056 f = stdout;
11055 11057
11056 11058 doc = xmlNewDoc((xmlChar *)"1.0");
11057 11059 if (doc == NULL)
11058 11060 uu_die(gettext("Could not create XML document.\n"));
11059 11061
11060 11062 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11061 11063 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11062 11064 uu_die(emsg_create_xml);
11063 11065
11064 11066 (void) xmlAddSibling(doc->children, make_archive(flags));
11065 11067
11066 11068 result = write_service_bundle(doc, f);
11067 11069
11068 11070 xmlFreeDoc(doc);
11069 11071
11070 11072 if (f != stdout)
11071 11073 (void) fclose(f);
11072 11074
11073 11075 return (result);
11074 11076 }
11075 11077
11076 11078
11077 11079 /*
11078 11080 * "Extract" a profile.
11079 11081 */
11080 11082 int
11081 11083 lscf_profile_extract(const char *filename)
11082 11084 {
11083 11085 FILE *f;
11084 11086 xmlDocPtr doc;
11085 11087 xmlNodePtr sb, snode, inode;
11086 11088 scf_scope_t *scope;
11087 11089 scf_service_t *svc;
11088 11090 scf_instance_t *inst;
11089 11091 scf_propertygroup_t *pg;
11090 11092 scf_property_t *prop;
11091 11093 scf_value_t *val;
11092 11094 scf_iter_t *siter, *iiter;
11093 11095 int r, s;
11094 11096 char *namebuf;
11095 11097 uint8_t b;
11096 11098 int result;
11097 11099
11098 11100 lscf_prep_hndl();
11099 11101
11100 11102 if (filename != NULL) {
11101 11103 errno = 0;
11102 11104 f = fopen(filename, "wb");
11103 11105 if (f == NULL) {
11104 11106 if (errno == 0)
11105 11107 uu_die(gettext("Could not open \"%s\": no "
11106 11108 "free stdio streams.\n"), filename);
11107 11109 else
11108 11110 uu_die(gettext("Could not open \"%s\""),
11109 11111 filename);
11110 11112 }
11111 11113 } else
11112 11114 f = stdout;
11113 11115
11114 11116 doc = xmlNewDoc((xmlChar *)"1.0");
11115 11117 if (doc == NULL)
11116 11118 uu_die(gettext("Could not create XML document.\n"));
11117 11119
11118 11120 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11119 11121 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11120 11122 uu_die(emsg_create_xml);
11121 11123
11122 11124 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11123 11125 if (sb == NULL)
11124 11126 uu_die(emsg_create_xml);
11125 11127 safe_setprop(sb, type_attr, "profile");
11126 11128 safe_setprop(sb, name_attr, "extract");
11127 11129 (void) xmlAddSibling(doc->children, sb);
11128 11130
11129 11131 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11130 11132 (svc = scf_service_create(g_hndl)) == NULL ||
11131 11133 (inst = scf_instance_create(g_hndl)) == NULL ||
11132 11134 (pg = scf_pg_create(g_hndl)) == NULL ||
11133 11135 (prop = scf_property_create(g_hndl)) == NULL ||
11134 11136 (val = scf_value_create(g_hndl)) == NULL ||
11135 11137 (siter = scf_iter_create(g_hndl)) == NULL ||
11136 11138 (iiter = scf_iter_create(g_hndl)) == NULL)
11137 11139 scfdie();
11138 11140
11139 11141 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11140 11142 scfdie();
11141 11143
11142 11144 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11143 11145 scfdie();
11144 11146
11145 11147 namebuf = safe_malloc(max_scf_name_len + 1);
11146 11148
11147 11149 while ((r = scf_iter_next_service(siter, svc)) == 1) {
11148 11150 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11149 11151 scfdie();
11150 11152
11151 11153 snode = xmlNewNode(NULL, (xmlChar *)"service");
11152 11154 if (snode == NULL)
11153 11155 uu_die(emsg_create_xml);
11154 11156
11155 11157 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11156 11158 0)
11157 11159 scfdie();
11158 11160
11159 11161 safe_setprop(snode, name_attr, namebuf);
11160 11162
11161 11163 safe_setprop(snode, type_attr, "service");
11162 11164 safe_setprop(snode, "version", "0");
11163 11165
11164 11166 while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11165 11167 if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11166 11168 SCF_SUCCESS) {
11167 11169 if (scf_error() != SCF_ERROR_NOT_FOUND)
11168 11170 scfdie();
11169 11171
11170 11172 if (g_verbose) {
11171 11173 ssize_t len;
11172 11174 char *fmri;
11173 11175
11174 11176 len =
11175 11177 scf_instance_to_fmri(inst, NULL, 0);
11176 11178 if (len < 0)
11177 11179 scfdie();
11178 11180
11179 11181 fmri = safe_malloc(len + 1);
11180 11182
11181 11183 if (scf_instance_to_fmri(inst, fmri,
11182 11184 len + 1) < 0)
11183 11185 scfdie();
11184 11186
11185 11187 warn("Instance %s has no \"%s\" "
11186 11188 "property group.\n", fmri,
11187 11189 scf_pg_general);
11188 11190
11189 11191 free(fmri);
11190 11192 }
11191 11193
11192 11194 continue;
11193 11195 }
11194 11196
11195 11197 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11196 11198 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11197 11199 prop_get_val(prop, val) != 0)
11198 11200 continue;
11199 11201
11200 11202 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11201 11203 NULL);
11202 11204 if (inode == NULL)
11203 11205 uu_die(emsg_create_xml);
11204 11206
11205 11207 if (scf_instance_get_name(inst, namebuf,
11206 11208 max_scf_name_len + 1) < 0)
11207 11209 scfdie();
11208 11210
11209 11211 safe_setprop(inode, name_attr, namebuf);
11210 11212
11211 11213 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11212 11214 scfdie();
11213 11215
11214 11216 safe_setprop(inode, enabled_attr, b ? true : false);
11215 11217 }
11216 11218 if (s < 0)
11217 11219 scfdie();
11218 11220
11219 11221 if (snode->children != NULL)
11220 11222 (void) xmlAddChild(sb, snode);
11221 11223 else
11222 11224 xmlFreeNode(snode);
11223 11225 }
11224 11226 if (r < 0)
11225 11227 scfdie();
11226 11228
11227 11229 free(namebuf);
11228 11230
11229 11231 result = write_service_bundle(doc, f);
11230 11232
11231 11233 xmlFreeDoc(doc);
11232 11234
11233 11235 if (f != stdout)
11234 11236 (void) fclose(f);
11235 11237
11236 11238 return (result);
11237 11239 }
11238 11240
11239 11241
11240 11242 /*
11241 11243 * Entity manipulation commands
11242 11244 */
11243 11245
11244 11246 /*
11245 11247 * Entity selection. If no entity is selected, then the current scope is in
11246 11248 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected,
11247 11249 * only cur_inst is NULL, and when an instance is selected, none are NULL.
11248 11250 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11249 11251 * cur_inst will be non-NULL.
11250 11252 */
11251 11253
11252 11254 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11253 11255 static int
11254 11256 select_inst(const char *name)
11255 11257 {
11256 11258 scf_instance_t *inst;
11257 11259 scf_error_t err;
11258 11260
11259 11261 assert(cur_svc != NULL);
11260 11262
11261 11263 inst = scf_instance_create(g_hndl);
11262 11264 if (inst == NULL)
11263 11265 scfdie();
11264 11266
11265 11267 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11266 11268 cur_inst = inst;
11267 11269 return (0);
11268 11270 }
11269 11271
11270 11272 err = scf_error();
11271 11273 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11272 11274 scfdie();
11273 11275
11274 11276 scf_instance_destroy(inst);
11275 11277 return (1);
11276 11278 }
11277 11279
11278 11280 /* Returns as above. */
11279 11281 static int
11280 11282 select_svc(const char *name)
11281 11283 {
11282 11284 scf_service_t *svc;
11283 11285 scf_error_t err;
11284 11286
11285 11287 assert(cur_scope != NULL);
11286 11288
11287 11289 svc = scf_service_create(g_hndl);
11288 11290 if (svc == NULL)
11289 11291 scfdie();
11290 11292
11291 11293 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11292 11294 cur_svc = svc;
11293 11295 return (0);
11294 11296 }
11295 11297
11296 11298 err = scf_error();
11297 11299 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11298 11300 scfdie();
11299 11301
11300 11302 scf_service_destroy(svc);
11301 11303 return (1);
11302 11304 }
11303 11305
11304 11306 /* ARGSUSED */
11305 11307 static int
11306 11308 select_callback(void *unused, scf_walkinfo_t *wip)
11307 11309 {
11308 11310 scf_instance_t *inst;
11309 11311 scf_service_t *svc;
11310 11312 scf_scope_t *scope;
11311 11313
11312 11314 if (wip->inst != NULL) {
11313 11315 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11314 11316 (svc = scf_service_create(g_hndl)) == NULL ||
11315 11317 (inst = scf_instance_create(g_hndl)) == NULL)
11316 11318 scfdie();
11317 11319
11318 11320 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11319 11321 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11320 11322 scfdie();
11321 11323 } else {
11322 11324 assert(wip->svc != NULL);
11323 11325
11324 11326 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11325 11327 (svc = scf_service_create(g_hndl)) == NULL)
11326 11328 scfdie();
11327 11329
11328 11330 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11329 11331 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11330 11332 scfdie();
11331 11333
11332 11334 inst = NULL;
11333 11335 }
11334 11336
11335 11337 /* Clear out the current selection */
11336 11338 assert(cur_scope != NULL);
11337 11339 scf_scope_destroy(cur_scope);
11338 11340 scf_service_destroy(cur_svc);
11339 11341 scf_instance_destroy(cur_inst);
11340 11342
11341 11343 cur_scope = scope;
11342 11344 cur_svc = svc;
11343 11345 cur_inst = inst;
11344 11346
11345 11347 return (0);
11346 11348 }
11347 11349
11348 11350 static int
11349 11351 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11350 11352 {
11351 11353 char **fmri = fmri_p;
11352 11354
11353 11355 *fmri = strdup(wip->fmri);
11354 11356 if (*fmri == NULL)
11355 11357 uu_die(gettext("Out of memory.\n"));
11356 11358
11357 11359 return (0);
11358 11360 }
11359 11361
11360 11362 /*
11361 11363 * validate [fmri]
11362 11364 * Perform the validation of an FMRI instance.
11363 11365 */
11364 11366 void
11365 11367 lscf_validate_fmri(const char *fmri)
11366 11368 {
11367 11369 int ret = 0;
11368 11370 size_t inst_sz;
11369 11371 char *inst_fmri = NULL;
11370 11372 scf_tmpl_errors_t *errs = NULL;
11371 11373 char *snapbuf = NULL;
11372 11374
11373 11375 lscf_prep_hndl();
11374 11376
11375 11377 if (fmri == NULL) {
11376 11378 inst_sz = max_scf_fmri_len + 1;
11377 11379 inst_fmri = safe_malloc(inst_sz);
11378 11380
11379 11381 if (cur_snap != NULL) {
11380 11382 snapbuf = safe_malloc(max_scf_name_len + 1);
11381 11383 if (scf_snapshot_get_name(cur_snap, snapbuf,
11382 11384 max_scf_name_len + 1) < 0)
11383 11385 scfdie();
11384 11386 }
11385 11387 if (cur_inst == NULL) {
11386 11388 semerr(gettext("No instance selected\n"));
11387 11389 goto cleanup;
11388 11390 } else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11389 11391 inst_sz) >= inst_sz) {
11390 11392 /* sanity check. Should never get here */
11391 11393 uu_die(gettext("Unexpected error! file %s, line %d\n"),
11392 11394 __FILE__, __LINE__);
11393 11395 }
11394 11396 } else {
11395 11397 scf_error_t scf_err;
11396 11398 int err = 0;
11397 11399
11398 11400 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11399 11401 validate_callback, &inst_fmri, &err, semerr)) != 0) {
11400 11402 uu_warn("Failed to walk instances: %s\n",
11401 11403 scf_strerror(scf_err));
11402 11404 goto cleanup;
11403 11405 }
11404 11406 if (err != 0) {
11405 11407 /* error message displayed by scf_walk_fmri */
11406 11408 goto cleanup;
11407 11409 }
11408 11410 }
11409 11411
11410 11412 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11411 11413 SCF_TMPL_VALIDATE_FLAG_CURRENT);
11412 11414 if (ret == -1) {
11413 11415 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11414 11416 warn(gettext("Template data for %s is invalid. "
11415 11417 "Consider reverting to a previous snapshot or "
11416 11418 "restoring original configuration.\n"), inst_fmri);
11417 11419 } else {
11418 11420 uu_warn("%s: %s\n",
11419 11421 gettext("Error validating the instance"),
11420 11422 scf_strerror(scf_error()));
11421 11423 }
11422 11424 } else if (ret == 1 && errs != NULL) {
11423 11425 scf_tmpl_error_t *err = NULL;
11424 11426 char *msg;
11425 11427 size_t len = 256; /* initial error buffer size */
11426 11428 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11427 11429 SCF_TMPL_STRERROR_HUMAN : 0;
11428 11430
11429 11431 msg = safe_malloc(len);
11430 11432
11431 11433 while ((err = scf_tmpl_next_error(errs)) != NULL) {
11432 11434 int ret;
11433 11435
11434 11436 if ((ret = scf_tmpl_strerror(err, msg, len,
11435 11437 flag)) >= len) {
11436 11438 len = ret + 1;
11437 11439 msg = realloc(msg, len);
11438 11440 if (msg == NULL)
11439 11441 uu_die(gettext(
11440 11442 "Out of memory.\n"));
11441 11443 (void) scf_tmpl_strerror(err, msg, len,
11442 11444 flag);
11443 11445 }
11444 11446 (void) fprintf(stderr, "%s\n", msg);
11445 11447 }
11446 11448 if (msg != NULL)
11447 11449 free(msg);
11448 11450 }
11449 11451 if (errs != NULL)
11450 11452 scf_tmpl_errors_destroy(errs);
11451 11453
11452 11454 cleanup:
11453 11455 free(inst_fmri);
11454 11456 free(snapbuf);
11455 11457 }
11456 11458
11457 11459 static void
11458 11460 lscf_validate_file(const char *filename)
11459 11461 {
11460 11462 tmpl_errors_t *errs;
11461 11463
11462 11464 bundle_t *b = internal_bundle_new();
11463 11465 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11464 11466 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11465 11467 tmpl_errors_print(stderr, errs, "");
11466 11468 semerr(gettext("Validation failed.\n"));
11467 11469 }
11468 11470 tmpl_errors_destroy(errs);
11469 11471 }
11470 11472 (void) internal_bundle_free(b);
11471 11473 }
11472 11474
11473 11475 /*
11474 11476 * validate [fmri|file]
11475 11477 */
11476 11478 void
11477 11479 lscf_validate(const char *arg)
11478 11480 {
11479 11481 const char *str;
11480 11482
11481 11483 if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11482 11484 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11483 11485 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11484 11486 lscf_validate_file(str);
11485 11487 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11486 11488 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11487 11489 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11488 11490 lscf_validate_fmri(str);
11489 11491 } else if (access(arg, R_OK | F_OK) == 0) {
11490 11492 lscf_validate_file(arg);
11491 11493 } else {
11492 11494 lscf_validate_fmri(arg);
11493 11495 }
11494 11496 }
11495 11497
11496 11498 void
11497 11499 lscf_select(const char *fmri)
11498 11500 {
11499 11501 int ret, err;
11500 11502
11501 11503 lscf_prep_hndl();
11502 11504
11503 11505 if (cur_snap != NULL) {
11504 11506 struct snaplevel *elt;
11505 11507 char *buf;
11506 11508
11507 11509 /* Error unless name is that of the next level. */
11508 11510 elt = uu_list_next(cur_levels, cur_elt);
11509 11511 if (elt == NULL) {
11510 11512 semerr(gettext("No children.\n"));
11511 11513 return;
11512 11514 }
11513 11515
11514 11516 buf = safe_malloc(max_scf_name_len + 1);
11515 11517
11516 11518 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11517 11519 max_scf_name_len + 1) < 0)
11518 11520 scfdie();
11519 11521
11520 11522 if (strcmp(buf, fmri) != 0) {
11521 11523 semerr(gettext("No such child.\n"));
11522 11524 free(buf);
11523 11525 return;
11524 11526 }
11525 11527
11526 11528 free(buf);
11527 11529
11528 11530 cur_elt = elt;
11529 11531 cur_level = elt->sl;
11530 11532 return;
11531 11533 }
11532 11534
11533 11535 /*
11534 11536 * Special case for 'svc:', which takes the user to the scope level.
11535 11537 */
11536 11538 if (strcmp(fmri, "svc:") == 0) {
11537 11539 scf_instance_destroy(cur_inst);
11538 11540 scf_service_destroy(cur_svc);
11539 11541 cur_inst = NULL;
11540 11542 cur_svc = NULL;
11541 11543 return;
11542 11544 }
11543 11545
11544 11546 /*
11545 11547 * Special case for ':properties'. This appears as part of 'list' but
11546 11548 * can't be selected. Give a more helpful error message in this case.
11547 11549 */
11548 11550 if (strcmp(fmri, ":properties") == 0) {
11549 11551 semerr(gettext(":properties is not an entity. Try 'listprop' "
11550 11552 "to list properties.\n"));
11551 11553 return;
11552 11554 }
11553 11555
11554 11556 /*
11555 11557 * First try the argument as relative to the current selection.
11556 11558 */
11557 11559 if (cur_inst != NULL) {
11558 11560 /* EMPTY */;
11559 11561 } else if (cur_svc != NULL) {
11560 11562 if (select_inst(fmri) != 1)
11561 11563 return;
11562 11564 } else {
11563 11565 if (select_svc(fmri) != 1)
11564 11566 return;
11565 11567 }
11566 11568
11567 11569 err = 0;
11568 11570 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11569 11571 select_callback, NULL, &err, semerr)) != 0) {
11570 11572 semerr(gettext("Failed to walk instances: %s\n"),
11571 11573 scf_strerror(ret));
11572 11574 }
11573 11575 }
11574 11576
11575 11577 void
11576 11578 lscf_unselect(void)
11577 11579 {
11578 11580 lscf_prep_hndl();
11579 11581
11580 11582 if (cur_snap != NULL) {
11581 11583 struct snaplevel *elt;
11582 11584
11583 11585 elt = uu_list_prev(cur_levels, cur_elt);
11584 11586 if (elt == NULL) {
11585 11587 semerr(gettext("No parent levels.\n"));
11586 11588 } else {
11587 11589 cur_elt = elt;
11588 11590 cur_level = elt->sl;
11589 11591 }
11590 11592 } else if (cur_inst != NULL) {
11591 11593 scf_instance_destroy(cur_inst);
11592 11594 cur_inst = NULL;
11593 11595 } else if (cur_svc != NULL) {
11594 11596 scf_service_destroy(cur_svc);
11595 11597 cur_svc = NULL;
11596 11598 } else {
11597 11599 semerr(gettext("Cannot unselect at scope level.\n"));
11598 11600 }
11599 11601 }
11600 11602
11601 11603 /*
11602 11604 * Return the FMRI of the current selection, for the prompt.
11603 11605 */
11604 11606 void
11605 11607 lscf_get_selection_str(char *buf, size_t bufsz)
11606 11608 {
11607 11609 char *cp;
11608 11610 ssize_t fmrilen, szret;
11609 11611 boolean_t deleted = B_FALSE;
11610 11612
11611 11613 if (g_hndl == NULL) {
11612 11614 (void) strlcpy(buf, "svc:", bufsz);
11613 11615 return;
11614 11616 }
11615 11617
11616 11618 if (cur_level != NULL) {
11617 11619 assert(cur_snap != NULL);
11618 11620
11619 11621 /* [ snapshot ] FMRI [: instance ] */
11620 11622 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11621 11623 + 2 + max_scf_name_len + 1 + 1);
11622 11624
11623 11625 buf[0] = '[';
11624 11626
11625 11627 szret = scf_snapshot_get_name(cur_snap, buf + 1,
11626 11628 max_scf_name_len + 1);
11627 11629 if (szret < 0) {
11628 11630 if (scf_error() != SCF_ERROR_DELETED)
11629 11631 scfdie();
11630 11632
11631 11633 goto snap_deleted;
11632 11634 }
11633 11635
11634 11636 (void) strcat(buf, "]svc:/");
11635 11637
11636 11638 cp = strchr(buf, '\0');
11637 11639
11638 11640 szret = scf_snaplevel_get_service_name(cur_level, cp,
11639 11641 max_scf_name_len + 1);
11640 11642 if (szret < 0) {
11641 11643 if (scf_error() != SCF_ERROR_DELETED)
11642 11644 scfdie();
11643 11645
11644 11646 goto snap_deleted;
11645 11647 }
11646 11648
11647 11649 cp = strchr(cp, '\0');
11648 11650
11649 11651 if (snaplevel_is_instance(cur_level)) {
11650 11652 *cp++ = ':';
11651 11653
11652 11654 if (scf_snaplevel_get_instance_name(cur_level, cp,
11653 11655 max_scf_name_len + 1) < 0) {
11654 11656 if (scf_error() != SCF_ERROR_DELETED)
11655 11657 scfdie();
11656 11658
11657 11659 goto snap_deleted;
11658 11660 }
11659 11661 } else {
11660 11662 *cp++ = '[';
11661 11663 *cp++ = ':';
11662 11664
11663 11665 if (scf_instance_get_name(cur_inst, cp,
11664 11666 max_scf_name_len + 1) < 0) {
11665 11667 if (scf_error() != SCF_ERROR_DELETED)
11666 11668 scfdie();
11667 11669
11668 11670 goto snap_deleted;
11669 11671 }
11670 11672
11671 11673 (void) strcat(buf, "]");
11672 11674 }
11673 11675
11674 11676 return;
11675 11677
11676 11678 snap_deleted:
11677 11679 deleted = B_TRUE;
11678 11680 free(buf);
11679 11681 unselect_cursnap();
11680 11682 }
11681 11683
11682 11684 assert(cur_snap == NULL);
11683 11685
11684 11686 if (cur_inst != NULL) {
11685 11687 assert(cur_svc != NULL);
11686 11688 assert(cur_scope != NULL);
11687 11689
11688 11690 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11689 11691 if (fmrilen >= 0) {
11690 11692 assert(fmrilen < bufsz);
11691 11693 if (deleted)
11692 11694 warn(emsg_deleted);
11693 11695 return;
11694 11696 }
11695 11697
11696 11698 if (scf_error() != SCF_ERROR_DELETED)
11697 11699 scfdie();
11698 11700
11699 11701 deleted = B_TRUE;
11700 11702
11701 11703 scf_instance_destroy(cur_inst);
11702 11704 cur_inst = NULL;
11703 11705 }
11704 11706
11705 11707 if (cur_svc != NULL) {
11706 11708 assert(cur_scope != NULL);
11707 11709
11708 11710 szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11709 11711 if (szret >= 0) {
11710 11712 assert(szret < bufsz);
11711 11713 if (deleted)
11712 11714 warn(emsg_deleted);
11713 11715 return;
11714 11716 }
11715 11717
11716 11718 if (scf_error() != SCF_ERROR_DELETED)
11717 11719 scfdie();
11718 11720
11719 11721 deleted = B_TRUE;
11720 11722 scf_service_destroy(cur_svc);
11721 11723 cur_svc = NULL;
11722 11724 }
11723 11725
11724 11726 assert(cur_scope != NULL);
11725 11727 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11726 11728
11727 11729 if (fmrilen < 0)
11728 11730 scfdie();
11729 11731
11730 11732 assert(fmrilen < bufsz);
11731 11733 if (deleted)
11732 11734 warn(emsg_deleted);
11733 11735 }
11734 11736
11735 11737 /*
11736 11738 * Entity listing. Entities and colon namespaces (e.g., :properties and
11737 11739 * :statistics) are listed for the current selection.
11738 11740 */
11739 11741 void
11740 11742 lscf_list(const char *pattern)
11741 11743 {
11742 11744 scf_iter_t *iter;
11743 11745 char *buf;
11744 11746 int ret;
11745 11747
11746 11748 lscf_prep_hndl();
11747 11749
11748 11750 if (cur_level != NULL) {
11749 11751 struct snaplevel *elt;
11750 11752
11751 11753 (void) fputs(COLON_NAMESPACES, stdout);
11752 11754
11753 11755 elt = uu_list_next(cur_levels, cur_elt);
11754 11756 if (elt == NULL)
11755 11757 return;
11756 11758
11757 11759 /*
11758 11760 * For now, we know that the next level is an instance. But
11759 11761 * if we ever have multiple scopes, this could be complicated.
11760 11762 */
11761 11763 buf = safe_malloc(max_scf_name_len + 1);
11762 11764 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11763 11765 max_scf_name_len + 1) >= 0) {
11764 11766 (void) puts(buf);
11765 11767 } else {
11766 11768 if (scf_error() != SCF_ERROR_DELETED)
11767 11769 scfdie();
11768 11770 }
11769 11771
11770 11772 free(buf);
11771 11773
11772 11774 return;
11773 11775 }
11774 11776
11775 11777 if (cur_inst != NULL) {
11776 11778 (void) fputs(COLON_NAMESPACES, stdout);
11777 11779 return;
11778 11780 }
11779 11781
11780 11782 iter = scf_iter_create(g_hndl);
11781 11783 if (iter == NULL)
11782 11784 scfdie();
11783 11785
11784 11786 buf = safe_malloc(max_scf_name_len + 1);
11785 11787
11786 11788 if (cur_svc != NULL) {
11787 11789 /* List the instances in this service. */
11788 11790 scf_instance_t *inst;
11789 11791
11790 11792 inst = scf_instance_create(g_hndl);
11791 11793 if (inst == NULL)
11792 11794 scfdie();
11793 11795
11794 11796 if (scf_iter_service_instances(iter, cur_svc) == 0) {
11795 11797 safe_printf(COLON_NAMESPACES);
11796 11798
11797 11799 for (;;) {
11798 11800 ret = scf_iter_next_instance(iter, inst);
11799 11801 if (ret == 0)
11800 11802 break;
11801 11803 if (ret != 1) {
11802 11804 if (scf_error() != SCF_ERROR_DELETED)
11803 11805 scfdie();
11804 11806
11805 11807 break;
11806 11808 }
11807 11809
11808 11810 if (scf_instance_get_name(inst, buf,
11809 11811 max_scf_name_len + 1) >= 0) {
11810 11812 if (pattern == NULL ||
11811 11813 fnmatch(pattern, buf, 0) == 0)
11812 11814 (void) puts(buf);
11813 11815 } else {
11814 11816 if (scf_error() != SCF_ERROR_DELETED)
11815 11817 scfdie();
11816 11818 }
11817 11819 }
11818 11820 } else {
11819 11821 if (scf_error() != SCF_ERROR_DELETED)
11820 11822 scfdie();
11821 11823 }
11822 11824
11823 11825 scf_instance_destroy(inst);
11824 11826 } else {
11825 11827 /* List the services in this scope. */
11826 11828 scf_service_t *svc;
11827 11829
11828 11830 assert(cur_scope != NULL);
11829 11831
11830 11832 svc = scf_service_create(g_hndl);
11831 11833 if (svc == NULL)
11832 11834 scfdie();
11833 11835
11834 11836 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11835 11837 scfdie();
11836 11838
11837 11839 for (;;) {
11838 11840 ret = scf_iter_next_service(iter, svc);
11839 11841 if (ret == 0)
11840 11842 break;
11841 11843 if (ret != 1)
11842 11844 scfdie();
11843 11845
11844 11846 if (scf_service_get_name(svc, buf,
11845 11847 max_scf_name_len + 1) >= 0) {
11846 11848 if (pattern == NULL ||
11847 11849 fnmatch(pattern, buf, 0) == 0)
11848 11850 safe_printf("%s\n", buf);
11849 11851 } else {
11850 11852 if (scf_error() != SCF_ERROR_DELETED)
11851 11853 scfdie();
11852 11854 }
11853 11855 }
11854 11856
11855 11857 scf_service_destroy(svc);
11856 11858 }
11857 11859
11858 11860 free(buf);
11859 11861 scf_iter_destroy(iter);
11860 11862 }
11861 11863
11862 11864 /*
11863 11865 * Entity addition. Creates an empty entity in the current selection.
11864 11866 */
11865 11867 void
11866 11868 lscf_add(const char *name)
11867 11869 {
11868 11870 lscf_prep_hndl();
11869 11871
11870 11872 if (cur_snap != NULL) {
11871 11873 semerr(emsg_cant_modify_snapshots);
11872 11874 } else if (cur_inst != NULL) {
11873 11875 semerr(gettext("Cannot add entities to an instance.\n"));
11874 11876 } else if (cur_svc != NULL) {
11875 11877
11876 11878 if (scf_service_add_instance(cur_svc, name, NULL) !=
11877 11879 SCF_SUCCESS) {
11878 11880 switch (scf_error()) {
11879 11881 case SCF_ERROR_INVALID_ARGUMENT:
11880 11882 semerr(gettext("Invalid name.\n"));
11881 11883 break;
11882 11884
11883 11885 case SCF_ERROR_EXISTS:
11884 11886 semerr(gettext("Instance already exists.\n"));
11885 11887 break;
11886 11888
11887 11889 case SCF_ERROR_PERMISSION_DENIED:
11888 11890 semerr(emsg_permission_denied);
11889 11891 break;
11890 11892
11891 11893 default:
11892 11894 scfdie();
11893 11895 }
11894 11896 }
11895 11897 } else {
11896 11898 assert(cur_scope != NULL);
11897 11899
11898 11900 if (scf_scope_add_service(cur_scope, name, NULL) !=
11899 11901 SCF_SUCCESS) {
11900 11902 switch (scf_error()) {
11901 11903 case SCF_ERROR_INVALID_ARGUMENT:
11902 11904 semerr(gettext("Invalid name.\n"));
11903 11905 break;
11904 11906
11905 11907 case SCF_ERROR_EXISTS:
11906 11908 semerr(gettext("Service already exists.\n"));
11907 11909 break;
11908 11910
11909 11911 case SCF_ERROR_PERMISSION_DENIED:
11910 11912 semerr(emsg_permission_denied);
11911 11913 break;
11912 11914
11913 11915 case SCF_ERROR_BACKEND_READONLY:
11914 11916 semerr(emsg_read_only);
11915 11917 break;
11916 11918
11917 11919 default:
11918 11920 scfdie();
11919 11921 }
11920 11922 }
11921 11923 }
11922 11924 }
11923 11925
11924 11926 /* return 1 if the entity has no persistent pgs, else return 0 */
11925 11927 static int
11926 11928 entity_has_no_pgs(void *ent, int isservice)
11927 11929 {
11928 11930 scf_iter_t *iter = NULL;
11929 11931 scf_propertygroup_t *pg = NULL;
11930 11932 uint32_t flags;
11931 11933 int err;
11932 11934 int ret = 1;
11933 11935
11934 11936 if ((iter = scf_iter_create(g_hndl)) == NULL ||
11935 11937 (pg = scf_pg_create(g_hndl)) == NULL)
11936 11938 scfdie();
11937 11939
11938 11940 if (isservice) {
11939 11941 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11940 11942 scfdie();
11941 11943 } else {
11942 11944 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11943 11945 scfdie();
11944 11946 }
11945 11947
11946 11948 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11947 11949 if (scf_pg_get_flags(pg, &flags) != 0)
11948 11950 scfdie();
11949 11951
11950 11952 /* skip nonpersistent pgs */
11951 11953 if (flags & SCF_PG_FLAG_NONPERSISTENT)
11952 11954 continue;
11953 11955
11954 11956 ret = 0;
11955 11957 break;
11956 11958 }
11957 11959
11958 11960 if (err == -1)
11959 11961 scfdie();
11960 11962
11961 11963 scf_pg_destroy(pg);
11962 11964 scf_iter_destroy(iter);
11963 11965
11964 11966 return (ret);
11965 11967 }
11966 11968
11967 11969 /* return 1 if the service has no instances, else return 0 */
11968 11970 static int
11969 11971 svc_has_no_insts(scf_service_t *svc)
11970 11972 {
11971 11973 scf_instance_t *inst;
11972 11974 scf_iter_t *iter;
11973 11975 int r;
11974 11976 int ret = 1;
11975 11977
11976 11978 if ((inst = scf_instance_create(g_hndl)) == NULL ||
11977 11979 (iter = scf_iter_create(g_hndl)) == NULL)
11978 11980 scfdie();
11979 11981
11980 11982 if (scf_iter_service_instances(iter, svc) != 0)
11981 11983 scfdie();
11982 11984
11983 11985 r = scf_iter_next_instance(iter, inst);
11984 11986 if (r == 1) {
11985 11987 ret = 0;
11986 11988 } else if (r == 0) {
11987 11989 ret = 1;
11988 11990 } else if (r == -1) {
11989 11991 scfdie();
11990 11992 } else {
11991 11993 bad_error("scf_iter_next_instance", r);
11992 11994 }
11993 11995
11994 11996 scf_iter_destroy(iter);
11995 11997 scf_instance_destroy(inst);
11996 11998
11997 11999 return (ret);
11998 12000 }
11999 12001
12000 12002 /*
12001 12003 * Entity deletion.
12002 12004 */
12003 12005
12004 12006 /*
12005 12007 * Delete the property group <fmri>/:properties/<name>. Returns
12006 12008 * SCF_ERROR_NONE on success (or if the entity is not found),
12007 12009 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
12008 12010 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
12009 12011 * denied.
12010 12012 */
12011 12013 static scf_error_t
12012 12014 delete_dependency_pg(const char *fmri, const char *name)
12013 12015 {
12014 12016 void *entity = NULL;
12015 12017 int isservice;
12016 12018 scf_propertygroup_t *pg = NULL;
12017 12019 scf_error_t result;
12018 12020 char *pgty;
12019 12021 scf_service_t *svc = NULL;
12020 12022 scf_instance_t *inst = NULL;
12021 12023 scf_iter_t *iter = NULL;
12022 12024 char *name_buf = NULL;
12023 12025
12024 12026 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12025 12027 switch (result) {
12026 12028 case SCF_ERROR_NONE:
12027 12029 break;
12028 12030
12029 12031 case SCF_ERROR_NO_MEMORY:
12030 12032 uu_die(gettext("Out of memory.\n"));
12031 12033 /* NOTREACHED */
12032 12034
12033 12035 case SCF_ERROR_INVALID_ARGUMENT:
12034 12036 case SCF_ERROR_CONSTRAINT_VIOLATED:
12035 12037 return (SCF_ERROR_INVALID_ARGUMENT);
12036 12038
12037 12039 case SCF_ERROR_NOT_FOUND:
12038 12040 result = SCF_ERROR_NONE;
12039 12041 goto out;
12040 12042
12041 12043 default:
12042 12044 bad_error("fmri_to_entity", result);
12043 12045 }
12044 12046
12045 12047 pg = scf_pg_create(g_hndl);
12046 12048 if (pg == NULL)
12047 12049 scfdie();
12048 12050
12049 12051 if (entity_get_pg(entity, isservice, name, pg) != 0) {
12050 12052 if (scf_error() != SCF_ERROR_NOT_FOUND)
12051 12053 scfdie();
12052 12054
12053 12055 result = SCF_ERROR_NONE;
12054 12056 goto out;
12055 12057 }
12056 12058
12057 12059 pgty = safe_malloc(max_scf_pg_type_len + 1);
12058 12060
12059 12061 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12060 12062 scfdie();
12061 12063
12062 12064 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12063 12065 result = SCF_ERROR_TYPE_MISMATCH;
12064 12066 free(pgty);
12065 12067 goto out;
12066 12068 }
12067 12069
12068 12070 free(pgty);
12069 12071
12070 12072 if (scf_pg_delete(pg) != 0) {
12071 12073 result = scf_error();
12072 12074 if (result != SCF_ERROR_PERMISSION_DENIED)
12073 12075 scfdie();
12074 12076 goto out;
12075 12077 }
12076 12078
12077 12079 /*
12078 12080 * We have to handle the case where we've just deleted the last
12079 12081 * property group of a "dummy" entity (instance or service).
12080 12082 * A "dummy" entity is an entity only present to hold an
12081 12083 * external dependency.
12082 12084 * So, in the case we deleted the last property group then we
12083 12085 * can also delete the entity. If the entity is an instance then
12084 12086 * we must verify if this was the last instance for the service
12085 12087 * and if it is, we can also delete the service if it doesn't
12086 12088 * have any property group either.
12087 12089 */
12088 12090
12089 12091 result = SCF_ERROR_NONE;
12090 12092
12091 12093 if (isservice) {
12092 12094 svc = (scf_service_t *)entity;
12093 12095
12094 12096 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12095 12097 (iter = scf_iter_create(g_hndl)) == NULL)
12096 12098 scfdie();
12097 12099
12098 12100 name_buf = safe_malloc(max_scf_name_len + 1);
12099 12101 } else {
12100 12102 inst = (scf_instance_t *)entity;
12101 12103 }
12102 12104
12103 12105 /*
12104 12106 * If the entity is an instance and we've just deleted its last
12105 12107 * property group then we should delete it.
12106 12108 */
12107 12109 if (!isservice && entity_has_no_pgs(entity, isservice)) {
12108 12110 /* find the service before deleting the inst. - needed later */
12109 12111 if ((svc = scf_service_create(g_hndl)) == NULL)
12110 12112 scfdie();
12111 12113
12112 12114 if (scf_instance_get_parent(inst, svc) != 0)
12113 12115 scfdie();
12114 12116
12115 12117 /* delete the instance */
12116 12118 if (scf_instance_delete(inst) != 0) {
12117 12119 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12118 12120 scfdie();
12119 12121
12120 12122 result = SCF_ERROR_PERMISSION_DENIED;
12121 12123 goto out;
12122 12124 }
12123 12125 /* no need to refresh the instance */
12124 12126 inst = NULL;
12125 12127 }
12126 12128
12127 12129 /*
12128 12130 * If the service has no more instances and pgs or we just deleted the
12129 12131 * last instance and the service doesn't have anymore propery groups
12130 12132 * then the service should be deleted.
12131 12133 */
12132 12134 if (svc != NULL &&
12133 12135 svc_has_no_insts(svc) &&
12134 12136 entity_has_no_pgs((void *)svc, 1)) {
12135 12137 if (scf_service_delete(svc) == 0) {
12136 12138 if (isservice) {
12137 12139 /* no need to refresh the service */
12138 12140 svc = NULL;
12139 12141 }
12140 12142
12141 12143 goto out;
12142 12144 }
12143 12145
12144 12146 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12145 12147 scfdie();
12146 12148
12147 12149 result = SCF_ERROR_PERMISSION_DENIED;
12148 12150 }
12149 12151
12150 12152 /* if the entity has not been deleted, refresh it */
12151 12153 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12152 12154 (void) refresh_entity(isservice, entity, fmri, inst, iter,
12153 12155 name_buf);
12154 12156 }
12155 12157
12156 12158 out:
12157 12159 if (isservice && (inst != NULL && iter != NULL)) {
12158 12160 free(name_buf);
12159 12161 scf_iter_destroy(iter);
12160 12162 scf_instance_destroy(inst);
12161 12163 }
12162 12164
12163 12165 if (!isservice && svc != NULL) {
12164 12166 scf_service_destroy(svc);
12165 12167 }
12166 12168
12167 12169 scf_pg_destroy(pg);
12168 12170 if (entity != NULL)
12169 12171 entity_destroy(entity, isservice);
12170 12172
12171 12173 return (result);
12172 12174 }
12173 12175
12174 12176 static int
12175 12177 delete_dependents(scf_propertygroup_t *pg)
12176 12178 {
12177 12179 char *pgty, *name, *fmri;
12178 12180 scf_property_t *prop;
12179 12181 scf_value_t *val;
12180 12182 scf_iter_t *iter;
12181 12183 int r;
12182 12184 scf_error_t err;
12183 12185
12184 12186 /* Verify that the pg has the correct type. */
12185 12187 pgty = safe_malloc(max_scf_pg_type_len + 1);
12186 12188 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12187 12189 scfdie();
12188 12190
12189 12191 if (strcmp(pgty, scf_group_framework) != 0) {
12190 12192 if (g_verbose) {
12191 12193 fmri = safe_malloc(max_scf_fmri_len + 1);
12192 12194 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12193 12195 scfdie();
12194 12196
12195 12197 warn(gettext("Property group %s is not of expected "
12196 12198 "type %s.\n"), fmri, scf_group_framework);
12197 12199
12198 12200 free(fmri);
12199 12201 }
12200 12202
12201 12203 free(pgty);
12202 12204 return (-1);
12203 12205 }
12204 12206
12205 12207 free(pgty);
12206 12208
12207 12209 /* map delete_dependency_pg onto the properties. */
12208 12210 if ((prop = scf_property_create(g_hndl)) == NULL ||
12209 12211 (val = scf_value_create(g_hndl)) == NULL ||
12210 12212 (iter = scf_iter_create(g_hndl)) == NULL)
12211 12213 scfdie();
12212 12214
12213 12215 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12214 12216 scfdie();
12215 12217
12216 12218 name = safe_malloc(max_scf_name_len + 1);
12217 12219 fmri = safe_malloc(max_scf_fmri_len + 2);
12218 12220
12219 12221 while ((r = scf_iter_next_property(iter, prop)) == 1) {
12220 12222 scf_type_t ty;
12221 12223
12222 12224 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12223 12225 scfdie();
12224 12226
12225 12227 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12226 12228 scfdie();
12227 12229
12228 12230 if ((ty != SCF_TYPE_ASTRING &&
12229 12231 prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12230 12232 prop_get_val(prop, val) != 0)
12231 12233 continue;
12232 12234
12233 12235 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12234 12236 scfdie();
12235 12237
12236 12238 err = delete_dependency_pg(fmri, name);
12237 12239 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12238 12240 if (scf_property_to_fmri(prop, fmri,
12239 12241 max_scf_fmri_len + 2) < 0)
12240 12242 scfdie();
12241 12243
12242 12244 warn(gettext("Value of %s is not a valid FMRI.\n"),
12243 12245 fmri);
12244 12246 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12245 12247 warn(gettext("Property group \"%s\" of entity \"%s\" "
12246 12248 "does not have dependency type.\n"), name, fmri);
12247 12249 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12248 12250 warn(gettext("Could not delete property group \"%s\" "
12249 12251 "of entity \"%s\" (permission denied).\n"), name,
12250 12252 fmri);
12251 12253 }
12252 12254 }
12253 12255 if (r == -1)
12254 12256 scfdie();
12255 12257
12256 12258 scf_value_destroy(val);
12257 12259 scf_property_destroy(prop);
12258 12260
12259 12261 return (0);
12260 12262 }
12261 12263
12262 12264 /*
12263 12265 * Returns 1 if the instance may be running, and 0 otherwise.
12264 12266 */
12265 12267 static int
12266 12268 inst_is_running(scf_instance_t *inst)
12267 12269 {
12268 12270 scf_propertygroup_t *pg;
12269 12271 scf_property_t *prop;
12270 12272 scf_value_t *val;
12271 12273 char buf[MAX_SCF_STATE_STRING_SZ];
12272 12274 int ret = 0;
12273 12275 ssize_t szret;
12274 12276
12275 12277 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12276 12278 (prop = scf_property_create(g_hndl)) == NULL ||
12277 12279 (val = scf_value_create(g_hndl)) == NULL)
12278 12280 scfdie();
12279 12281
12280 12282 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12281 12283 if (scf_error() != SCF_ERROR_NOT_FOUND)
12282 12284 scfdie();
12283 12285 goto out;
12284 12286 }
12285 12287
12286 12288 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12287 12289 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12288 12290 prop_get_val(prop, val) != 0)
12289 12291 goto out;
12290 12292
12291 12293 szret = scf_value_get_astring(val, buf, sizeof (buf));
12292 12294 assert(szret >= 0);
12293 12295
12294 12296 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12295 12297 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12296 12298
12297 12299 out:
12298 12300 scf_value_destroy(val);
12299 12301 scf_property_destroy(prop);
12300 12302 scf_pg_destroy(pg);
12301 12303 return (ret);
12302 12304 }
12303 12305
12304 12306 static uint8_t
12305 12307 pg_is_external_dependency(scf_propertygroup_t *pg)
12306 12308 {
12307 12309 char *type;
12308 12310 scf_value_t *val;
12309 12311 scf_property_t *prop;
12310 12312 uint8_t b = B_FALSE;
12311 12313
12312 12314 type = safe_malloc(max_scf_pg_type_len + 1);
12313 12315
12314 12316 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12315 12317 scfdie();
12316 12318
12317 12319 if ((prop = scf_property_create(g_hndl)) == NULL ||
12318 12320 (val = scf_value_create(g_hndl)) == NULL)
12319 12321 scfdie();
12320 12322
12321 12323 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12322 12324 if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12323 12325 if (scf_property_get_value(prop, val) != 0)
12324 12326 scfdie();
12325 12327 if (scf_value_get_boolean(val, &b) != 0)
12326 12328 scfdie();
12327 12329 }
12328 12330 }
12329 12331
12330 12332 free(type);
12331 12333 (void) scf_value_destroy(val);
12332 12334 (void) scf_property_destroy(prop);
12333 12335
12334 12336 return (b);
12335 12337 }
12336 12338
12337 12339 #define DELETE_FAILURE -1
12338 12340 #define DELETE_SUCCESS_NOEXTDEPS 0
12339 12341 #define DELETE_SUCCESS_EXTDEPS 1
12340 12342
12341 12343 /*
12342 12344 * lscf_instance_delete() deletes an instance. Before calling
12343 12345 * scf_instance_delete(), though, we make sure the instance isn't
12344 12346 * running and delete dependencies in other entities which the instance
12345 12347 * declared as "dependents". If there are dependencies which were
12346 12348 * created for other entities, then instead of deleting the instance we
12347 12349 * make it "empty" by deleting all other property groups and all
12348 12350 * snapshots.
12349 12351 *
12350 12352 * lscf_instance_delete() verifies that there is no external dependency pgs
12351 12353 * before suppressing the instance. If there is, then we must not remove them
12352 12354 * now in case the instance is re-created otherwise the dependencies would be
12353 12355 * lost. The external dependency pgs will be removed if the dependencies are
12354 12356 * removed.
12355 12357 *
12356 12358 * Returns:
12357 12359 * DELETE_FAILURE on failure
12358 12360 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12359 12361 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12360 12362 */
12361 12363 static int
12362 12364 lscf_instance_delete(scf_instance_t *inst, int force)
12363 12365 {
12364 12366 scf_propertygroup_t *pg;
12365 12367 scf_snapshot_t *snap;
12366 12368 scf_iter_t *iter;
12367 12369 int err;
12368 12370 int external = 0;
12369 12371
12370 12372 /* If we're not forcing and the instance is running, refuse. */
12371 12373 if (!force && inst_is_running(inst)) {
12372 12374 char *fmri;
12373 12375
12374 12376 fmri = safe_malloc(max_scf_fmri_len + 1);
12375 12377
12376 12378 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12377 12379 scfdie();
12378 12380
12379 12381 semerr(gettext("Instance %s may be running. "
12380 12382 "Use delete -f if it is not.\n"), fmri);
12381 12383
12382 12384 free(fmri);
12383 12385 return (DELETE_FAILURE);
12384 12386 }
12385 12387
12386 12388 pg = scf_pg_create(g_hndl);
12387 12389 if (pg == NULL)
12388 12390 scfdie();
12389 12391
12390 12392 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12391 12393 (void) delete_dependents(pg);
12392 12394 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12393 12395 scfdie();
12394 12396
12395 12397 scf_pg_destroy(pg);
12396 12398
12397 12399 /*
12398 12400 * If the instance has some external dependencies then we must
12399 12401 * keep them in case the instance is reimported otherwise the
12400 12402 * dependencies would be lost on reimport.
12401 12403 */
12402 12404 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12403 12405 (pg = scf_pg_create(g_hndl)) == NULL)
12404 12406 scfdie();
12405 12407
12406 12408 if (scf_iter_instance_pgs(iter, inst) < 0)
12407 12409 scfdie();
12408 12410
12409 12411 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12410 12412 if (pg_is_external_dependency(pg)) {
12411 12413 external = 1;
12412 12414 continue;
12413 12415 }
12414 12416
12415 12417 if (scf_pg_delete(pg) != 0) {
12416 12418 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12417 12419 scfdie();
12418 12420 else {
12419 12421 semerr(emsg_permission_denied);
12420 12422
12421 12423 (void) scf_iter_destroy(iter);
12422 12424 (void) scf_pg_destroy(pg);
12423 12425 return (DELETE_FAILURE);
12424 12426 }
12425 12427 }
12426 12428 }
12427 12429
12428 12430 if (err == -1)
12429 12431 scfdie();
12430 12432
12431 12433 (void) scf_iter_destroy(iter);
12432 12434 (void) scf_pg_destroy(pg);
12433 12435
12434 12436 if (external) {
12435 12437 /*
12436 12438 * All the pgs have been deleted for the instance except
12437 12439 * the ones holding the external dependencies.
12438 12440 * For the job to be complete, we must also delete the
12439 12441 * snapshots associated with the instance.
12440 12442 */
12441 12443 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12442 12444 NULL)
12443 12445 scfdie();
12444 12446 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12445 12447 scfdie();
12446 12448
12447 12449 if (scf_iter_instance_snapshots(iter, inst) == -1)
12448 12450 scfdie();
12449 12451
12450 12452 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12451 12453 if (_scf_snapshot_delete(snap) != 0) {
12452 12454 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12453 12455 scfdie();
12454 12456
12455 12457 semerr(emsg_permission_denied);
12456 12458
12457 12459 (void) scf_iter_destroy(iter);
12458 12460 (void) scf_snapshot_destroy(snap);
12459 12461 return (DELETE_FAILURE);
12460 12462 }
12461 12463 }
12462 12464
12463 12465 if (err == -1)
12464 12466 scfdie();
12465 12467
12466 12468 (void) scf_iter_destroy(iter);
12467 12469 (void) scf_snapshot_destroy(snap);
12468 12470 return (DELETE_SUCCESS_EXTDEPS);
12469 12471 }
12470 12472
12471 12473 if (scf_instance_delete(inst) != 0) {
12472 12474 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12473 12475 scfdie();
12474 12476
12475 12477 semerr(emsg_permission_denied);
12476 12478
12477 12479 return (DELETE_FAILURE);
12478 12480 }
12479 12481
12480 12482 return (DELETE_SUCCESS_NOEXTDEPS);
12481 12483 }
12482 12484
12483 12485 /*
12484 12486 * lscf_service_delete() deletes a service. Before calling
12485 12487 * scf_service_delete(), though, we call lscf_instance_delete() for
12486 12488 * each of the instances and delete dependencies in other entities
12487 12489 * which were created as "dependents" of this service. If there are
12488 12490 * dependencies which were created for other entities, then we delete
12489 12491 * all other property groups in the service and leave it as "empty".
12490 12492 *
12491 12493 * lscf_service_delete() verifies that there is no external dependency
12492 12494 * pgs at the instance & service level before suppressing the service.
12493 12495 * If there is, then we must not remove them now in case the service
12494 12496 * is re-imported otherwise the dependencies would be lost. The external
12495 12497 * dependency pgs will be removed if the dependencies are removed.
12496 12498 *
12497 12499 * Returns:
12498 12500 * DELETE_FAILURE on failure
12499 12501 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12500 12502 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12501 12503 */
12502 12504 static int
12503 12505 lscf_service_delete(scf_service_t *svc, int force)
12504 12506 {
12505 12507 int r;
12506 12508 scf_instance_t *inst;
12507 12509 scf_propertygroup_t *pg;
12508 12510 scf_iter_t *iter;
12509 12511 int ret;
12510 12512 int external = 0;
12511 12513
12512 12514 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12513 12515 (pg = scf_pg_create(g_hndl)) == NULL ||
12514 12516 (iter = scf_iter_create(g_hndl)) == NULL)
12515 12517 scfdie();
12516 12518
12517 12519 if (scf_iter_service_instances(iter, svc) != 0)
12518 12520 scfdie();
12519 12521
12520 12522 for (r = scf_iter_next_instance(iter, inst);
12521 12523 r == 1;
12522 12524 r = scf_iter_next_instance(iter, inst)) {
12523 12525
12524 12526 ret = lscf_instance_delete(inst, force);
12525 12527 if (ret == DELETE_FAILURE) {
12526 12528 scf_iter_destroy(iter);
12527 12529 scf_pg_destroy(pg);
12528 12530 scf_instance_destroy(inst);
12529 12531 return (DELETE_FAILURE);
12530 12532 }
12531 12533
12532 12534 /*
12533 12535 * Record the fact that there is some external dependencies
12534 12536 * at the instance level.
12535 12537 */
12536 12538 if (ret == DELETE_SUCCESS_EXTDEPS)
12537 12539 external |= 1;
12538 12540 }
12539 12541
12540 12542 if (r != 0)
12541 12543 scfdie();
12542 12544
12543 12545 /* Delete dependency property groups in dependent services. */
12544 12546 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12545 12547 (void) delete_dependents(pg);
12546 12548 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12547 12549 scfdie();
12548 12550
12549 12551 scf_iter_destroy(iter);
12550 12552 scf_pg_destroy(pg);
12551 12553 scf_instance_destroy(inst);
12552 12554
12553 12555 /*
12554 12556 * If the service has some external dependencies then we don't
12555 12557 * want to remove them in case the service is re-imported.
12556 12558 */
12557 12559 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12558 12560 (iter = scf_iter_create(g_hndl)) == NULL)
12559 12561 scfdie();
12560 12562
12561 12563 if (scf_iter_service_pgs(iter, svc) < 0)
12562 12564 scfdie();
12563 12565
12564 12566 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12565 12567 if (pg_is_external_dependency(pg)) {
12566 12568 external |= 2;
12567 12569 continue;
12568 12570 }
12569 12571
12570 12572 if (scf_pg_delete(pg) != 0) {
12571 12573 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12572 12574 scfdie();
12573 12575 else {
12574 12576 semerr(emsg_permission_denied);
12575 12577
12576 12578 (void) scf_iter_destroy(iter);
12577 12579 (void) scf_pg_destroy(pg);
12578 12580 return (DELETE_FAILURE);
12579 12581 }
12580 12582 }
12581 12583 }
12582 12584
12583 12585 if (r == -1)
12584 12586 scfdie();
12585 12587
12586 12588 (void) scf_iter_destroy(iter);
12587 12589 (void) scf_pg_destroy(pg);
12588 12590
12589 12591 if (external != 0)
12590 12592 return (DELETE_SUCCESS_EXTDEPS);
12591 12593
12592 12594 if (scf_service_delete(svc) == 0)
12593 12595 return (DELETE_SUCCESS_NOEXTDEPS);
12594 12596
12595 12597 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12596 12598 scfdie();
12597 12599
12598 12600 semerr(emsg_permission_denied);
12599 12601 return (DELETE_FAILURE);
12600 12602 }
12601 12603
12602 12604 static int
12603 12605 delete_callback(void *data, scf_walkinfo_t *wip)
12604 12606 {
12605 12607 int force = (int)data;
12606 12608
12607 12609 if (wip->inst != NULL)
12608 12610 (void) lscf_instance_delete(wip->inst, force);
12609 12611 else
12610 12612 (void) lscf_service_delete(wip->svc, force);
12611 12613
12612 12614 return (0);
12613 12615 }
12614 12616
12615 12617 void
12616 12618 lscf_delete(const char *fmri, int force)
12617 12619 {
12618 12620 scf_service_t *svc;
12619 12621 scf_instance_t *inst;
12620 12622 int ret;
12621 12623
12622 12624 lscf_prep_hndl();
12623 12625
12624 12626 if (cur_snap != NULL) {
12625 12627 if (!snaplevel_is_instance(cur_level)) {
12626 12628 char *buf;
12627 12629
12628 12630 buf = safe_malloc(max_scf_name_len + 1);
12629 12631 if (scf_instance_get_name(cur_inst, buf,
12630 12632 max_scf_name_len + 1) >= 0) {
12631 12633 if (strcmp(buf, fmri) == 0) {
12632 12634 semerr(emsg_cant_modify_snapshots);
12633 12635 free(buf);
12634 12636 return;
12635 12637 }
12636 12638 } else if (scf_error() != SCF_ERROR_DELETED) {
12637 12639 scfdie();
12638 12640 }
12639 12641 free(buf);
12640 12642 }
12641 12643 } else if (cur_inst != NULL) {
12642 12644 /* EMPTY */;
12643 12645 } else if (cur_svc != NULL) {
12644 12646 inst = scf_instance_create(g_hndl);
12645 12647 if (inst == NULL)
12646 12648 scfdie();
12647 12649
12648 12650 if (scf_service_get_instance(cur_svc, fmri, inst) ==
12649 12651 SCF_SUCCESS) {
12650 12652 (void) lscf_instance_delete(inst, force);
12651 12653 scf_instance_destroy(inst);
12652 12654 return;
12653 12655 }
12654 12656
12655 12657 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12656 12658 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12657 12659 scfdie();
12658 12660
12659 12661 scf_instance_destroy(inst);
12660 12662 } else {
12661 12663 assert(cur_scope != NULL);
12662 12664
12663 12665 svc = scf_service_create(g_hndl);
12664 12666 if (svc == NULL)
12665 12667 scfdie();
12666 12668
12667 12669 if (scf_scope_get_service(cur_scope, fmri, svc) ==
12668 12670 SCF_SUCCESS) {
12669 12671 (void) lscf_service_delete(svc, force);
12670 12672 scf_service_destroy(svc);
12671 12673 return;
12672 12674 }
12673 12675
12674 12676 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12675 12677 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12676 12678 scfdie();
12677 12679
12678 12680 scf_service_destroy(svc);
12679 12681 }
12680 12682
12681 12683 /*
12682 12684 * Match FMRI to entity.
12683 12685 */
12684 12686 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12685 12687 delete_callback, (void *)force, NULL, semerr)) != 0) {
12686 12688 semerr(gettext("Failed to walk instances: %s\n"),
12687 12689 scf_strerror(ret));
12688 12690 }
12689 12691 }
12690 12692
12691 12693
12692 12694
12693 12695 /*
12694 12696 * :properties commands. These all end with "pg" or "prop" and generally
12695 12697 * operate on the currently selected entity.
12696 12698 */
12697 12699
12698 12700 /*
12699 12701 * Property listing. List the property groups, properties, their types and
12700 12702 * their values for the currently selected entity.
12701 12703 */
12702 12704 static void
12703 12705 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12704 12706 {
12705 12707 char *buf;
12706 12708 uint32_t flags;
12707 12709
12708 12710 buf = safe_malloc(max_scf_pg_type_len + 1);
12709 12711
12710 12712 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12711 12713 scfdie();
12712 12714
12713 12715 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12714 12716 scfdie();
12715 12717
12716 12718 safe_printf("%-*s %s", namewidth, name, buf);
12717 12719
12718 12720 if (flags & SCF_PG_FLAG_NONPERSISTENT)
12719 12721 safe_printf("\tNONPERSISTENT");
12720 12722
12721 12723 safe_printf("\n");
12722 12724
12723 12725 free(buf);
12724 12726 }
12725 12727
12726 12728 static boolean_t
12727 12729 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12728 12730 {
12729 12731 if (scf_property_get_value(prop, val) == 0) {
12730 12732 return (B_FALSE);
12731 12733 } else {
12732 12734 switch (scf_error()) {
12733 12735 case SCF_ERROR_NOT_FOUND:
12734 12736 return (B_FALSE);
12735 12737 case SCF_ERROR_PERMISSION_DENIED:
12736 12738 case SCF_ERROR_CONSTRAINT_VIOLATED:
12737 12739 return (B_TRUE);
12738 12740 default:
12739 12741 scfdie();
12740 12742 /*NOTREACHED*/
12741 12743 }
12742 12744 }
12743 12745 }
12744 12746
12745 12747 static void
12746 12748 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12747 12749 {
12748 12750 scf_iter_t *iter;
12749 12751 scf_value_t *val;
12750 12752 const char *type;
12751 12753 int multiple_strings = 0;
12752 12754 int ret;
12753 12755
12754 12756 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12755 12757 (val = scf_value_create(g_hndl)) == NULL)
12756 12758 scfdie();
12757 12759
12758 12760 type = prop_to_typestr(prop);
12759 12761 assert(type != NULL);
12760 12762
12761 12763 safe_printf("%-*s %-7s ", len, name, type);
12762 12764
12763 12765 if (prop_has_multiple_values(prop, val) &&
12764 12766 (scf_value_type(val) == SCF_TYPE_ASTRING ||
12765 12767 scf_value_type(val) == SCF_TYPE_USTRING))
12766 12768 multiple_strings = 1;
12767 12769
12768 12770 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12769 12771 scfdie();
12770 12772
12771 12773 while ((ret = scf_iter_next_value(iter, val)) == 1) {
12772 12774 char *buf;
12773 12775 ssize_t vlen, szret;
12774 12776
12775 12777 vlen = scf_value_get_as_string(val, NULL, 0);
12776 12778 if (vlen < 0)
12777 12779 scfdie();
12778 12780
12779 12781 buf = safe_malloc(vlen + 1);
12780 12782
12781 12783 szret = scf_value_get_as_string(val, buf, vlen + 1);
12782 12784 if (szret < 0)
12783 12785 scfdie();
12784 12786 assert(szret <= vlen);
12785 12787
12786 12788 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12787 12789 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12788 12790 safe_printf(" \"");
12789 12791 (void) quote_and_print(buf, stdout, 0);
12790 12792 (void) putchar('"');
12791 12793 if (ferror(stdout)) {
12792 12794 (void) putchar('\n');
12793 12795 uu_die(gettext("Error writing to stdout.\n"));
12794 12796 }
12795 12797 } else {
12796 12798 safe_printf(" %s", buf);
12797 12799 }
12798 12800
12799 12801 free(buf);
12800 12802 }
12801 12803 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12802 12804 scfdie();
12803 12805
12804 12806 if (putchar('\n') != '\n')
12805 12807 uu_die(gettext("Could not output newline"));
12806 12808 }
12807 12809
12808 12810 /*
12809 12811 * Outputs template property group info for the describe subcommand.
12810 12812 * If 'templates' == 2, verbose output is printed in the format expected
12811 12813 * for describe -v, which includes all templates fields. If pg is
12812 12814 * not NULL, we're describing the template data, not an existing property
12813 12815 * group, and formatting should be appropriate for describe -t.
12814 12816 */
12815 12817 static void
12816 12818 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12817 12819 {
12818 12820 char *buf;
12819 12821 uint8_t required;
12820 12822 scf_property_t *stability_prop;
12821 12823 scf_value_t *stability_val;
12822 12824
12823 12825 if (templates == 0)
12824 12826 return;
12825 12827
12826 12828 if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12827 12829 (stability_val = scf_value_create(g_hndl)) == NULL)
12828 12830 scfdie();
12829 12831
12830 12832 if (templates == 2 && pg != NULL) {
12831 12833 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12832 12834 stability_prop) == 0) {
12833 12835 if (prop_check_type(stability_prop,
12834 12836 SCF_TYPE_ASTRING) == 0 &&
12835 12837 prop_get_val(stability_prop, stability_val) == 0) {
12836 12838 char *stability;
12837 12839
12838 12840 stability = safe_malloc(max_scf_value_len + 1);
12839 12841
12840 12842 if (scf_value_get_astring(stability_val,
12841 12843 stability, max_scf_value_len + 1) == -1 &&
12842 12844 scf_error() != SCF_ERROR_NOT_FOUND)
12843 12845 scfdie();
12844 12846
12845 12847 safe_printf("%s%s: %s\n", TMPL_INDENT,
12846 12848 gettext("stability"), stability);
12847 12849
12848 12850 free(stability);
12849 12851 }
12850 12852 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12851 12853 scfdie();
12852 12854 }
12853 12855
12854 12856 scf_property_destroy(stability_prop);
12855 12857 scf_value_destroy(stability_val);
12856 12858
12857 12859 if (pgt == NULL)
12858 12860 return;
12859 12861
12860 12862 if (pg == NULL || templates == 2) {
12861 12863 /* print type info only if scf_tmpl_pg_name succeeds */
12862 12864 if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12863 12865 if (pg != NULL)
12864 12866 safe_printf("%s", TMPL_INDENT);
12865 12867 safe_printf("%s: ", gettext("name"));
12866 12868 safe_printf("%s\n", buf);
12867 12869 free(buf);
12868 12870 }
12869 12871
12870 12872 /* print type info only if scf_tmpl_pg_type succeeds */
12871 12873 if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12872 12874 if (pg != NULL)
12873 12875 safe_printf("%s", TMPL_INDENT);
12874 12876 safe_printf("%s: ", gettext("type"));
12875 12877 safe_printf("%s\n", buf);
12876 12878 free(buf);
12877 12879 }
12878 12880 }
12879 12881
12880 12882 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12881 12883 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12882 12884 required ? "true" : "false");
12883 12885
12884 12886 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12885 12887 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12886 12888 buf);
12887 12889 free(buf);
12888 12890 }
12889 12891
12890 12892 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12891 12893 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12892 12894 buf);
12893 12895 free(buf);
12894 12896 }
12895 12897
12896 12898 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12897 12899 if (templates == 2)
12898 12900 safe_printf("%s%s: %s\n", TMPL_INDENT,
12899 12901 gettext("description"), buf);
12900 12902 else
12901 12903 safe_printf("%s%s\n", TMPL_INDENT, buf);
12902 12904 free(buf);
12903 12905 }
12904 12906
12905 12907 }
12906 12908
12907 12909 /*
12908 12910 * With as_value set to true, indent as appropriate for the value level.
12909 12911 * If false, indent to appropriate level for inclusion in constraint
12910 12912 * or choice printout.
12911 12913 */
12912 12914 static void
12913 12915 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12914 12916 int as_value)
12915 12917 {
12916 12918 char *buf;
12917 12919
12918 12920 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12919 12921 if (as_value == 0)
12920 12922 safe_printf("%s", TMPL_CHOICE_INDENT);
12921 12923 else
12922 12924 safe_printf("%s", TMPL_INDENT);
12923 12925 safe_printf("%s: %s\n", gettext("value common name"), buf);
12924 12926 free(buf);
12925 12927 }
12926 12928
12927 12929 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12928 12930 if (as_value == 0)
12929 12931 safe_printf("%s", TMPL_CHOICE_INDENT);
12930 12932 else
12931 12933 safe_printf("%s", TMPL_INDENT);
12932 12934 safe_printf("%s: %s\n", gettext("value description"), buf);
12933 12935 free(buf);
12934 12936 }
12935 12937 }
12936 12938
12937 12939 static void
12938 12940 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12939 12941 {
12940 12942 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12941 12943 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12942 12944 safe_printf("%s\n", val_buf);
12943 12945
12944 12946 print_template_value_details(prt, val_buf, 1);
12945 12947 }
12946 12948
12947 12949 static void
12948 12950 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12949 12951 {
12950 12952 int i, printed = 0;
12951 12953 scf_values_t values;
12952 12954 scf_count_ranges_t c_ranges;
12953 12955 scf_int_ranges_t i_ranges;
12954 12956
12955 12957 printed = 0;
12956 12958 i = 0;
12957 12959 if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12958 12960 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12959 12961 gettext("value constraints"));
12960 12962 printed++;
12961 12963 for (i = 0; i < values.value_count; ++i) {
12962 12964 safe_printf("%s%s: %s\n", TMPL_INDENT,
12963 12965 gettext("value name"), values.values_as_strings[i]);
12964 12966 if (verbose == 1)
12965 12967 print_template_value_details(prt,
12966 12968 values.values_as_strings[i], 0);
12967 12969 }
12968 12970
12969 12971 scf_values_destroy(&values);
12970 12972 }
12971 12973
12972 12974 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12973 12975 if (printed++ == 0)
12974 12976 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12975 12977 gettext("value constraints"));
12976 12978 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12977 12979 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12978 12980 gettext("range"), c_ranges.scr_min[i],
12979 12981 c_ranges.scr_max[i]);
12980 12982 }
12981 12983 scf_count_ranges_destroy(&c_ranges);
12982 12984 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12983 12985 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12984 12986 if (printed++ == 0)
12985 12987 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12986 12988 gettext("value constraints"));
12987 12989 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12988 12990 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12989 12991 gettext("range"), i_ranges.sir_min[i],
12990 12992 i_ranges.sir_max[i]);
12991 12993 }
12992 12994 scf_int_ranges_destroy(&i_ranges);
12993 12995 }
12994 12996 }
12995 12997
12996 12998 static void
12997 12999 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12998 13000 {
12999 13001 int i = 0, printed = 0;
13000 13002 scf_values_t values;
13001 13003 scf_count_ranges_t c_ranges;
13002 13004 scf_int_ranges_t i_ranges;
13003 13005
13004 13006 printed = 0;
13005 13007 if (scf_tmpl_value_name_choices(prt, &values) == 0) {
13006 13008 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13007 13009 gettext("value constraints"));
13008 13010 printed++;
13009 13011 for (i = 0; i < values.value_count; i++) {
13010 13012 safe_printf("%s%s: %s\n", TMPL_INDENT,
13011 13013 gettext("value name"), values.values_as_strings[i]);
13012 13014 if (verbose == 1)
13013 13015 print_template_value_details(prt,
13014 13016 values.values_as_strings[i], 0);
13015 13017 }
13016 13018
13017 13019 scf_values_destroy(&values);
13018 13020 }
13019 13021
13020 13022 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13021 13023 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13022 13024 if (printed++ == 0)
13023 13025 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13024 13026 gettext("value choices"));
13025 13027 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13026 13028 gettext("range"), c_ranges.scr_min[i],
13027 13029 c_ranges.scr_max[i]);
13028 13030 }
13029 13031 scf_count_ranges_destroy(&c_ranges);
13030 13032 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13031 13033 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13032 13034 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13033 13035 if (printed++ == 0)
13034 13036 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13035 13037 gettext("value choices"));
13036 13038 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13037 13039 gettext("range"), i_ranges.sir_min[i],
13038 13040 i_ranges.sir_max[i]);
13039 13041 }
13040 13042 scf_int_ranges_destroy(&i_ranges);
13041 13043 }
13042 13044 }
13043 13045
13044 13046 static void
13045 13047 list_values_by_template(scf_prop_tmpl_t *prt)
13046 13048 {
13047 13049 print_template_constraints(prt, 1);
13048 13050 print_template_choices(prt, 1);
13049 13051 }
13050 13052
13051 13053 static void
13052 13054 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13053 13055 {
13054 13056 char *val_buf;
13055 13057 scf_iter_t *iter;
13056 13058 scf_value_t *val;
13057 13059 int ret;
13058 13060
13059 13061 if ((iter = scf_iter_create(g_hndl)) == NULL ||
13060 13062 (val = scf_value_create(g_hndl)) == NULL)
13061 13063 scfdie();
13062 13064
13063 13065 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13064 13066 scfdie();
13065 13067
13066 13068 val_buf = safe_malloc(max_scf_value_len + 1);
13067 13069
13068 13070 while ((ret = scf_iter_next_value(iter, val)) == 1) {
13069 13071 if (scf_value_get_as_string(val, val_buf,
13070 13072 max_scf_value_len + 1) < 0)
13071 13073 scfdie();
13072 13074
13073 13075 print_template_value(prt, val_buf);
13074 13076 }
13075 13077 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13076 13078 scfdie();
13077 13079 free(val_buf);
13078 13080
13079 13081 print_template_constraints(prt, 0);
13080 13082 print_template_choices(prt, 0);
13081 13083
13082 13084 }
13083 13085
13084 13086 /*
13085 13087 * Outputs property info for the describe subcommand
13086 13088 * Verbose output if templates == 2, -v option of svccfg describe
13087 13089 * Displays template data if prop is not NULL, -t option of svccfg describe
13088 13090 */
13089 13091 static void
13090 13092 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13091 13093 {
13092 13094 char *buf;
13093 13095 uint8_t u_buf;
13094 13096 int i;
13095 13097 uint64_t min, max;
13096 13098 scf_values_t values;
13097 13099
13098 13100 if (prt == NULL || templates == 0)
13099 13101 return;
13100 13102
13101 13103 if (prop == NULL) {
13102 13104 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13103 13105 if (scf_tmpl_prop_name(prt, &buf) > 0) {
13104 13106 safe_printf("%s\n", buf);
13105 13107 free(buf);
13106 13108 } else
13107 13109 safe_printf("(%s)\n", gettext("any"));
13108 13110 }
13109 13111
13110 13112 if (prop == NULL || templates == 2) {
13111 13113 if (prop != NULL)
13112 13114 safe_printf("%s", TMPL_INDENT);
13113 13115 else
13114 13116 safe_printf("%s", TMPL_VALUE_INDENT);
13115 13117 safe_printf("%s: ", gettext("type"));
13116 13118 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13117 13119 safe_printf("%s\n", buf);
13118 13120 free(buf);
13119 13121 } else
13120 13122 safe_printf("(%s)\n", gettext("any"));
13121 13123 }
13122 13124
13123 13125 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13124 13126 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13125 13127 u_buf ? "true" : "false");
13126 13128
13127 13129 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13128 13130 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13129 13131 buf);
13130 13132 free(buf);
13131 13133 }
13132 13134
13133 13135 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13134 13136 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13135 13137 buf);
13136 13138 free(buf);
13137 13139 }
13138 13140
13139 13141 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13140 13142 safe_printf("%s%s\n", TMPL_INDENT, buf);
13141 13143 free(buf);
13142 13144 }
13143 13145
13144 13146 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13145 13147 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13146 13148 scf_tmpl_visibility_to_string(u_buf));
13147 13149
13148 13150 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13149 13151 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13150 13152 gettext("minimum number of values"), min);
13151 13153 if (max == ULLONG_MAX) {
13152 13154 safe_printf("%s%s: %s\n", TMPL_INDENT,
13153 13155 gettext("maximum number of values"),
13154 13156 gettext("unlimited"));
13155 13157 } else {
13156 13158 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13157 13159 gettext("maximum number of values"), max);
13158 13160 }
13159 13161 }
13160 13162
13161 13163 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13162 13164 for (i = 0; i < values.value_count; i++) {
13163 13165 if (i == 0) {
13164 13166 safe_printf("%s%s:", TMPL_INDENT,
13165 13167 gettext("internal separators"));
13166 13168 }
13167 13169 safe_printf(" \"%s\"", values.values_as_strings[i]);
13168 13170 }
13169 13171 safe_printf("\n");
13170 13172 }
13171 13173
13172 13174 if (templates != 2)
13173 13175 return;
13174 13176
13175 13177 if (prop != NULL)
13176 13178 list_values_tmpl(prt, prop);
13177 13179 else
13178 13180 list_values_by_template(prt);
13179 13181 }
13180 13182
13181 13183 static char *
13182 13184 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13183 13185 {
13184 13186 char *rv;
13185 13187
13186 13188 rv = _scf_read_single_astring_from_pg(pg, prop_name);
13187 13189 if (rv == NULL) {
13188 13190 switch (scf_error()) {
13189 13191 case SCF_ERROR_NOT_FOUND:
13190 13192 break;
13191 13193 default:
13192 13194 scfdie();
13193 13195 }
13194 13196 }
13195 13197 return (rv);
13196 13198 }
13197 13199
13198 13200 static void
13199 13201 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13200 13202 {
13201 13203 size_t doc_len;
13202 13204 size_t man_len;
13203 13205 char *pg_name;
13204 13206 char *text = NULL;
13205 13207 int rv;
13206 13208
13207 13209 doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13208 13210 man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13209 13211 pg_name = safe_malloc(max_scf_name_len + 1);
13210 13212 while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13211 13213 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13212 13214 scfdie();
13213 13215 }
13214 13216 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13215 13217 /* Display doc_link and and uri */
13216 13218 safe_printf("%s%s:\n", TMPL_INDENT,
13217 13219 gettext("doc_link"));
13218 13220 text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13219 13221 if (text != NULL) {
13220 13222 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13221 13223 TMPL_INDENT, gettext("name"), text);
13222 13224 uu_free(text);
13223 13225 }
13224 13226 text = read_astring(pg, SCF_PROPERTY_TM_URI);
13225 13227 if (text != NULL) {
13226 13228 safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13227 13229 gettext("uri"), text);
13228 13230 uu_free(text);
13229 13231 }
13230 13232 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13231 13233 man_len) == 0) {
13232 13234 /* Display manpage title, section and path */
13233 13235 safe_printf("%s%s:\n", TMPL_INDENT,
13234 13236 gettext("manpage"));
13235 13237 text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13236 13238 if (text != NULL) {
13237 13239 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13238 13240 TMPL_INDENT, gettext("title"), text);
13239 13241 uu_free(text);
13240 13242 }
13241 13243 text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13242 13244 if (text != NULL) {
13243 13245 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13244 13246 TMPL_INDENT, gettext("section"), text);
13245 13247 uu_free(text);
13246 13248 }
13247 13249 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13248 13250 if (text != NULL) {
13249 13251 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13250 13252 TMPL_INDENT, gettext("manpath"), text);
13251 13253 uu_free(text);
13252 13254 }
13253 13255 }
13254 13256 }
13255 13257 if (rv == -1)
13256 13258 scfdie();
13257 13259
13258 13260 done:
13259 13261 free(pg_name);
13260 13262 }
13261 13263
13262 13264 static void
13263 13265 list_entity_tmpl(int templates)
13264 13266 {
13265 13267 char *common_name = NULL;
13266 13268 char *description = NULL;
13267 13269 char *locale = NULL;
13268 13270 scf_iter_t *iter;
13269 13271 scf_propertygroup_t *pg;
13270 13272 scf_property_t *prop;
13271 13273 int r;
13272 13274 scf_value_t *val;
13273 13275
13274 13276 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13275 13277 (prop = scf_property_create(g_hndl)) == NULL ||
13276 13278 (val = scf_value_create(g_hndl)) == NULL ||
13277 13279 (iter = scf_iter_create(g_hndl)) == NULL)
13278 13280 scfdie();
13279 13281
13280 13282 locale = setlocale(LC_MESSAGES, NULL);
13281 13283
13282 13284 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13283 13285 common_name = safe_malloc(max_scf_value_len + 1);
13284 13286
13285 13287 /* Try both the current locale and the "C" locale. */
13286 13288 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13287 13289 (scf_error() == SCF_ERROR_NOT_FOUND &&
13288 13290 scf_pg_get_property(pg, "C", prop) == 0)) {
13289 13291 if (prop_get_val(prop, val) == 0 &&
13290 13292 scf_value_get_ustring(val, common_name,
13291 13293 max_scf_value_len + 1) != -1) {
13292 13294 safe_printf("%s%s: %s\n", TMPL_INDENT,
13293 13295 gettext("common name"), common_name);
13294 13296 }
13295 13297 }
13296 13298 }
13297 13299
13298 13300 /*
13299 13301 * Do description, manpages, and doc links if templates == 2.
13300 13302 */
13301 13303 if (templates == 2) {
13302 13304 /* Get the description. */
13303 13305 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13304 13306 description = safe_malloc(max_scf_value_len + 1);
13305 13307
13306 13308 /* Try both the current locale and the "C" locale. */
13307 13309 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13308 13310 (scf_error() == SCF_ERROR_NOT_FOUND &&
13309 13311 scf_pg_get_property(pg, "C", prop) == 0)) {
13310 13312 if (prop_get_val(prop, val) == 0 &&
13311 13313 scf_value_get_ustring(val, description,
13312 13314 max_scf_value_len + 1) != -1) {
13313 13315 safe_printf("%s%s: %s\n", TMPL_INDENT,
13314 13316 gettext("description"),
13315 13317 description);
13316 13318 }
13317 13319 }
13318 13320 }
13319 13321
13320 13322 /* Process doc_link & manpage elements. */
13321 13323 if (cur_level != NULL) {
13322 13324 r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13323 13325 SCF_GROUP_TEMPLATE);
13324 13326 } else if (cur_inst != NULL) {
13325 13327 r = scf_iter_instance_pgs_typed(iter, cur_inst,
13326 13328 SCF_GROUP_TEMPLATE);
13327 13329 } else {
13328 13330 r = scf_iter_service_pgs_typed(iter, cur_svc,
13329 13331 SCF_GROUP_TEMPLATE);
13330 13332 }
13331 13333 if (r == 0) {
13332 13334 display_documentation(iter, pg);
13333 13335 }
13334 13336 }
13335 13337
13336 13338 free(common_name);
13337 13339 free(description);
13338 13340 scf_pg_destroy(pg);
13339 13341 scf_property_destroy(prop);
13340 13342 scf_value_destroy(val);
13341 13343 scf_iter_destroy(iter);
13342 13344 }
13343 13345
13344 13346 static void
13345 13347 listtmpl(const char *pattern, int templates)
13346 13348 {
13347 13349 scf_pg_tmpl_t *pgt;
13348 13350 scf_prop_tmpl_t *prt;
13349 13351 char *snapbuf = NULL;
13350 13352 char *fmribuf;
13351 13353 char *pg_name = NULL, *prop_name = NULL;
13352 13354 ssize_t prop_name_size;
13353 13355 char *qual_prop_name;
13354 13356 char *search_name;
13355 13357 int listed = 0;
13356 13358
13357 13359 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13358 13360 (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13359 13361 scfdie();
13360 13362
13361 13363 fmribuf = safe_malloc(max_scf_name_len + 1);
13362 13364 qual_prop_name = safe_malloc(max_scf_name_len + 1);
13363 13365
13364 13366 if (cur_snap != NULL) {
13365 13367 snapbuf = safe_malloc(max_scf_name_len + 1);
13366 13368 if (scf_snapshot_get_name(cur_snap, snapbuf,
13367 13369 max_scf_name_len + 1) < 0)
13368 13370 scfdie();
13369 13371 }
13370 13372
13371 13373 if (cur_inst != NULL) {
13372 13374 if (scf_instance_to_fmri(cur_inst, fmribuf,
13373 13375 max_scf_name_len + 1) < 0)
13374 13376 scfdie();
13375 13377 } else if (cur_svc != NULL) {
13376 13378 if (scf_service_to_fmri(cur_svc, fmribuf,
13377 13379 max_scf_name_len + 1) < 0)
13378 13380 scfdie();
13379 13381 } else
13380 13382 abort();
13381 13383
13382 13384 /* If pattern is specified, we want to list only those items. */
13383 13385 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13384 13386 listed = 0;
13385 13387 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13386 13388 fnmatch(pattern, pg_name, 0) == 0)) {
13387 13389 list_pg_tmpl(pgt, NULL, templates);
13388 13390 listed++;
13389 13391 }
13390 13392
13391 13393 scf_tmpl_prop_reset(prt);
13392 13394
13393 13395 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13394 13396 search_name = NULL;
13395 13397 prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13396 13398 if ((prop_name_size > 0) && (pg_name != NULL)) {
13397 13399 if (snprintf(qual_prop_name,
13398 13400 max_scf_name_len + 1, "%s/%s",
13399 13401 pg_name, prop_name) >=
13400 13402 max_scf_name_len + 1) {
13401 13403 prop_name_size = -1;
13402 13404 } else {
13403 13405 search_name = qual_prop_name;
13404 13406 }
13405 13407 }
13406 13408 if (listed > 0 || pattern == NULL ||
13407 13409 (prop_name_size > 0 &&
13408 13410 fnmatch(pattern, search_name,
13409 13411 FNM_PATHNAME) == 0))
13410 13412 list_prop_tmpl(prt, NULL, templates);
13411 13413 if (prop_name != NULL) {
13412 13414 free(prop_name);
13413 13415 prop_name = NULL;
13414 13416 }
13415 13417 }
13416 13418 if (pg_name != NULL) {
13417 13419 free(pg_name);
13418 13420 pg_name = NULL;
13419 13421 }
13420 13422 }
13421 13423
13422 13424 scf_tmpl_prop_destroy(prt);
13423 13425 scf_tmpl_pg_destroy(pgt);
13424 13426 free(snapbuf);
13425 13427 free(fmribuf);
13426 13428 free(qual_prop_name);
13427 13429 }
13428 13430
13429 13431 static void
13430 13432 listprop(const char *pattern, int only_pgs, int templates)
13431 13433 {
13432 13434 scf_propertygroup_t *pg;
13433 13435 scf_property_t *prop;
13434 13436 scf_iter_t *iter, *piter;
13435 13437 char *pgnbuf, *prnbuf, *ppnbuf;
13436 13438 scf_pg_tmpl_t *pgt, *pgtp;
13437 13439 scf_prop_tmpl_t *prt;
13438 13440
13439 13441 void **objects;
13440 13442 char **names;
13441 13443 void **tmpls;
13442 13444 int allocd, i;
13443 13445
13444 13446 int ret;
13445 13447 ssize_t pgnlen, prnlen, szret;
13446 13448 size_t max_len = 0;
13447 13449
13448 13450 if (cur_svc == NULL && cur_inst == NULL) {
13449 13451 semerr(emsg_entity_not_selected);
13450 13452 return;
13451 13453 }
13452 13454
13453 13455 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13454 13456 (prop = scf_property_create(g_hndl)) == NULL ||
13455 13457 (iter = scf_iter_create(g_hndl)) == NULL ||
13456 13458 (piter = scf_iter_create(g_hndl)) == NULL ||
13457 13459 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13458 13460 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13459 13461 scfdie();
13460 13462
13461 13463 prnbuf = safe_malloc(max_scf_name_len + 1);
13462 13464
13463 13465 if (cur_level != NULL)
13464 13466 ret = scf_iter_snaplevel_pgs(iter, cur_level);
13465 13467 else if (cur_inst != NULL)
13466 13468 ret = scf_iter_instance_pgs(iter, cur_inst);
13467 13469 else
13468 13470 ret = scf_iter_service_pgs(iter, cur_svc);
13469 13471 if (ret != 0) {
13470 13472 return;
13471 13473 }
13472 13474
13473 13475 /*
13474 13476 * We want to only list items which match pattern, and we want the
13475 13477 * second column to line up, so during the first pass we'll save
13476 13478 * matching items, their names, and their templates in objects,
13477 13479 * names, and tmpls, computing the maximum name length as we go,
13478 13480 * and then we'll print them out.
13479 13481 *
13480 13482 * Note: We always keep an extra slot available so the array can be
13481 13483 * NULL-terminated.
13482 13484 */
13483 13485 i = 0;
13484 13486 allocd = 1;
13485 13487 objects = safe_malloc(sizeof (*objects));
13486 13488 names = safe_malloc(sizeof (*names));
13487 13489 tmpls = safe_malloc(sizeof (*tmpls));
13488 13490
13489 13491 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13490 13492 int new_pg = 0;
13491 13493 int print_props = 0;
13492 13494 pgtp = NULL;
13493 13495
13494 13496 pgnlen = scf_pg_get_name(pg, NULL, 0);
13495 13497 if (pgnlen < 0)
13496 13498 scfdie();
13497 13499
13498 13500 pgnbuf = safe_malloc(pgnlen + 1);
13499 13501
13500 13502 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13501 13503 if (szret < 0)
13502 13504 scfdie();
13503 13505 assert(szret <= pgnlen);
13504 13506
13505 13507 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13506 13508 if (scf_error() != SCF_ERROR_NOT_FOUND)
13507 13509 scfdie();
13508 13510 pgtp = NULL;
13509 13511 } else {
13510 13512 pgtp = pgt;
13511 13513 }
13512 13514
13513 13515 if (pattern == NULL ||
13514 13516 fnmatch(pattern, pgnbuf, 0) == 0) {
13515 13517 if (i+1 >= allocd) {
13516 13518 allocd *= 2;
13517 13519 objects = realloc(objects,
13518 13520 sizeof (*objects) * allocd);
13519 13521 names =
13520 13522 realloc(names, sizeof (*names) * allocd);
13521 13523 tmpls = realloc(tmpls,
13522 13524 sizeof (*tmpls) * allocd);
13523 13525 if (objects == NULL || names == NULL ||
13524 13526 tmpls == NULL)
13525 13527 uu_die(gettext("Out of memory"));
13526 13528 }
13527 13529 objects[i] = pg;
13528 13530 names[i] = pgnbuf;
13529 13531
13530 13532 if (pgtp == NULL)
13531 13533 tmpls[i] = NULL;
13532 13534 else
13533 13535 tmpls[i] = pgt;
13534 13536
13535 13537 ++i;
13536 13538
13537 13539 if (pgnlen > max_len)
13538 13540 max_len = pgnlen;
13539 13541
13540 13542 new_pg = 1;
13541 13543 print_props = 1;
13542 13544 }
13543 13545
13544 13546 if (only_pgs) {
13545 13547 if (new_pg) {
13546 13548 pg = scf_pg_create(g_hndl);
13547 13549 if (pg == NULL)
13548 13550 scfdie();
13549 13551 pgt = scf_tmpl_pg_create(g_hndl);
13550 13552 if (pgt == NULL)
13551 13553 scfdie();
13552 13554 } else
13553 13555 free(pgnbuf);
13554 13556
13555 13557 continue;
13556 13558 }
13557 13559
13558 13560 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13559 13561 scfdie();
13560 13562
13561 13563 while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13562 13564 prnlen = scf_property_get_name(prop, prnbuf,
13563 13565 max_scf_name_len + 1);
13564 13566 if (prnlen < 0)
13565 13567 scfdie();
13566 13568
13567 13569 /* Will prepend the property group name and a slash. */
13568 13570 prnlen += pgnlen + 1;
13569 13571
13570 13572 ppnbuf = safe_malloc(prnlen + 1);
13571 13573
13572 13574 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13573 13575 prnbuf) < 0)
13574 13576 uu_die("snprintf");
13575 13577
13576 13578 if (pattern == NULL || print_props == 1 ||
13577 13579 fnmatch(pattern, ppnbuf, 0) == 0) {
13578 13580 if (i+1 >= allocd) {
13579 13581 allocd *= 2;
13580 13582 objects = realloc(objects,
13581 13583 sizeof (*objects) * allocd);
13582 13584 names = realloc(names,
13583 13585 sizeof (*names) * allocd);
13584 13586 tmpls = realloc(tmpls,
13585 13587 sizeof (*tmpls) * allocd);
13586 13588 if (objects == NULL || names == NULL ||
13587 13589 tmpls == NULL)
13588 13590 uu_die(gettext(
13589 13591 "Out of memory"));
13590 13592 }
13591 13593
13592 13594 objects[i] = prop;
13593 13595 names[i] = ppnbuf;
13594 13596
13595 13597 if (pgtp != NULL) {
13596 13598 if (scf_tmpl_get_by_prop(pgt, prnbuf,
13597 13599 prt, 0) < 0) {
13598 13600 if (scf_error() !=
13599 13601 SCF_ERROR_NOT_FOUND)
13600 13602 scfdie();
13601 13603 tmpls[i] = NULL;
13602 13604 } else {
13603 13605 tmpls[i] = prt;
13604 13606 }
13605 13607 } else {
13606 13608 tmpls[i] = NULL;
13607 13609 }
13608 13610
13609 13611 ++i;
13610 13612
13611 13613 if (prnlen > max_len)
13612 13614 max_len = prnlen;
13613 13615
13614 13616 prop = scf_property_create(g_hndl);
13615 13617 prt = scf_tmpl_prop_create(g_hndl);
13616 13618 } else {
13617 13619 free(ppnbuf);
13618 13620 }
13619 13621 }
13620 13622
13621 13623 if (new_pg) {
13622 13624 pg = scf_pg_create(g_hndl);
13623 13625 if (pg == NULL)
13624 13626 scfdie();
13625 13627 pgt = scf_tmpl_pg_create(g_hndl);
13626 13628 if (pgt == NULL)
13627 13629 scfdie();
13628 13630 } else
13629 13631 free(pgnbuf);
13630 13632 }
13631 13633 if (ret != 0)
13632 13634 scfdie();
13633 13635
13634 13636 objects[i] = NULL;
13635 13637
13636 13638 scf_pg_destroy(pg);
13637 13639 scf_tmpl_pg_destroy(pgt);
13638 13640 scf_property_destroy(prop);
13639 13641 scf_tmpl_prop_destroy(prt);
13640 13642
13641 13643 for (i = 0; objects[i] != NULL; ++i) {
13642 13644 if (strchr(names[i], '/') == NULL) {
13643 13645 /* property group */
13644 13646 pg = (scf_propertygroup_t *)objects[i];
13645 13647 pgt = (scf_pg_tmpl_t *)tmpls[i];
13646 13648 list_pg_info(pg, names[i], max_len);
13647 13649 list_pg_tmpl(pgt, pg, templates);
13648 13650 free(names[i]);
13649 13651 scf_pg_destroy(pg);
13650 13652 if (pgt != NULL)
13651 13653 scf_tmpl_pg_destroy(pgt);
13652 13654 } else {
13653 13655 /* property */
13654 13656 prop = (scf_property_t *)objects[i];
13655 13657 prt = (scf_prop_tmpl_t *)tmpls[i];
13656 13658 list_prop_info(prop, names[i], max_len);
13657 13659 list_prop_tmpl(prt, prop, templates);
13658 13660 free(names[i]);
13659 13661 scf_property_destroy(prop);
13660 13662 if (prt != NULL)
13661 13663 scf_tmpl_prop_destroy(prt);
13662 13664 }
13663 13665 }
13664 13666
13665 13667 free(names);
13666 13668 free(objects);
13667 13669 free(tmpls);
13668 13670 }
13669 13671
13670 13672 void
13671 13673 lscf_listpg(const char *pattern)
13672 13674 {
13673 13675 lscf_prep_hndl();
13674 13676
13675 13677 listprop(pattern, 1, 0);
13676 13678 }
13677 13679
13678 13680 /*
13679 13681 * Property group and property creation, setting, and deletion. setprop (and
13680 13682 * its alias, addprop) can either create a property group of a given type, or
13681 13683 * it can create or set a property to a given type and list of values.
13682 13684 */
13683 13685 void
13684 13686 lscf_addpg(const char *name, const char *type, const char *flags)
13685 13687 {
13686 13688 scf_propertygroup_t *pg;
13687 13689 int ret;
13688 13690 uint32_t flgs = 0;
13689 13691 const char *cp;
13690 13692
13691 13693
13692 13694 lscf_prep_hndl();
13693 13695
13694 13696 if (cur_snap != NULL) {
13695 13697 semerr(emsg_cant_modify_snapshots);
13696 13698 return;
13697 13699 }
13698 13700
13699 13701 if (cur_inst == NULL && cur_svc == NULL) {
13700 13702 semerr(emsg_entity_not_selected);
13701 13703 return;
13702 13704 }
13703 13705
13704 13706 if (flags != NULL) {
13705 13707 for (cp = flags; *cp != '\0'; ++cp) {
13706 13708 switch (*cp) {
13707 13709 case 'P':
13708 13710 flgs |= SCF_PG_FLAG_NONPERSISTENT;
13709 13711 break;
13710 13712
13711 13713 case 'p':
13712 13714 flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13713 13715 break;
13714 13716
13715 13717 default:
13716 13718 semerr(gettext("Invalid property group flag "
13717 13719 "%c."), *cp);
13718 13720 return;
13719 13721 }
13720 13722 }
13721 13723 }
13722 13724
13723 13725 pg = scf_pg_create(g_hndl);
13724 13726 if (pg == NULL)
13725 13727 scfdie();
13726 13728
13727 13729 if (cur_inst != NULL)
13728 13730 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13729 13731 else
13730 13732 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13731 13733
13732 13734 if (ret != SCF_SUCCESS) {
13733 13735 switch (scf_error()) {
13734 13736 case SCF_ERROR_INVALID_ARGUMENT:
13735 13737 semerr(gettext("Name, type, or flags are invalid.\n"));
13736 13738 break;
13737 13739
13738 13740 case SCF_ERROR_EXISTS:
13739 13741 semerr(gettext("Property group already exists.\n"));
13740 13742 break;
13741 13743
13742 13744 case SCF_ERROR_PERMISSION_DENIED:
13743 13745 semerr(emsg_permission_denied);
13744 13746 break;
13745 13747
13746 13748 case SCF_ERROR_BACKEND_ACCESS:
13747 13749 semerr(gettext("Backend refused access.\n"));
13748 13750 break;
13749 13751
13750 13752 default:
13751 13753 scfdie();
13752 13754 }
13753 13755 }
13754 13756
13755 13757 scf_pg_destroy(pg);
13756 13758
13757 13759 private_refresh();
13758 13760 }
13759 13761
13760 13762 void
13761 13763 lscf_delpg(char *name)
13762 13764 {
13763 13765 lscf_prep_hndl();
13764 13766
13765 13767 if (cur_snap != NULL) {
13766 13768 semerr(emsg_cant_modify_snapshots);
13767 13769 return;
13768 13770 }
13769 13771
13770 13772 if (cur_inst == NULL && cur_svc == NULL) {
13771 13773 semerr(emsg_entity_not_selected);
13772 13774 return;
13773 13775 }
13774 13776
13775 13777 if (strchr(name, '/') != NULL) {
13776 13778 semerr(emsg_invalid_pg_name, name);
13777 13779 return;
13778 13780 }
13779 13781
13780 13782 lscf_delprop(name);
13781 13783 }
13782 13784
13783 13785 /*
13784 13786 * scf_delhash() is used to remove the property group related to the
13785 13787 * hash entry for a specific manifest in the repository. pgname will be
13786 13788 * constructed from the location of the manifest file. If deathrow isn't 0,
13787 13789 * manifest file doesn't need to exist (manifest string will be used as
13788 13790 * an absolute path).
13789 13791 */
13790 13792 void
13791 13793 lscf_delhash(char *manifest, int deathrow)
13792 13794 {
13793 13795 char *pgname;
13794 13796
13795 13797 if (cur_snap != NULL ||
13796 13798 cur_inst != NULL || cur_svc != NULL) {
13797 13799 warn(gettext("error, an entity is selected\n"));
13798 13800 return;
13799 13801 }
13800 13802
13801 13803 /* select smf/manifest */
13802 13804 lscf_select(HASH_SVC);
13803 13805 /*
13804 13806 * Translate the manifest file name to property name. In the deathrow
13805 13807 * case, the manifest file does not need to exist.
13806 13808 */
13807 13809 pgname = mhash_filename_to_propname(manifest,
13808 13810 deathrow ? B_TRUE : B_FALSE);
13809 13811 if (pgname == NULL) {
13810 13812 warn(gettext("cannot resolve pathname for %s\n"), manifest);
13811 13813 return;
13812 13814 }
13813 13815 /* delete the hash property name */
13814 13816 lscf_delpg(pgname);
13815 13817 }
13816 13818
13817 13819 void
13818 13820 lscf_listprop(const char *pattern)
13819 13821 {
13820 13822 lscf_prep_hndl();
13821 13823
13822 13824 listprop(pattern, 0, 0);
13823 13825 }
13824 13826
13825 13827 int
13826 13828 lscf_setprop(const char *pgname, const char *type, const char *value,
13827 13829 const uu_list_t *values)
13828 13830 {
13829 13831 scf_type_t ty, current_ty;
13830 13832 scf_service_t *svc;
13831 13833 scf_propertygroup_t *pg, *parent_pg;
13832 13834 scf_property_t *prop, *parent_prop;
13833 13835 scf_pg_tmpl_t *pgt;
13834 13836 scf_prop_tmpl_t *prt;
13835 13837 int ret, result = 0;
13836 13838 scf_transaction_t *tx;
13837 13839 scf_transaction_entry_t *e;
13838 13840 scf_value_t *v;
13839 13841 uu_list_walk_t *walk;
13840 13842 string_list_t *sp;
13841 13843 char *propname;
13842 13844 int req_quotes = 0;
13843 13845
13844 13846 lscf_prep_hndl();
13845 13847
13846 13848 if ((e = scf_entry_create(g_hndl)) == NULL ||
13847 13849 (svc = scf_service_create(g_hndl)) == NULL ||
13848 13850 (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13849 13851 (pg = scf_pg_create(g_hndl)) == NULL ||
13850 13852 (parent_prop = scf_property_create(g_hndl)) == NULL ||
13851 13853 (prop = scf_property_create(g_hndl)) == NULL ||
13852 13854 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13853 13855 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13854 13856 (tx = scf_transaction_create(g_hndl)) == NULL)
13855 13857 scfdie();
13856 13858
13857 13859 if (cur_snap != NULL) {
13858 13860 semerr(emsg_cant_modify_snapshots);
13859 13861 goto fail;
13860 13862 }
13861 13863
13862 13864 if (cur_inst == NULL && cur_svc == NULL) {
13863 13865 semerr(emsg_entity_not_selected);
13864 13866 goto fail;
13865 13867 }
13866 13868
13867 13869 propname = strchr(pgname, '/');
13868 13870 if (propname == NULL) {
13869 13871 semerr(gettext("Property names must contain a `/'.\n"));
13870 13872 goto fail;
13871 13873 }
13872 13874
13873 13875 *propname = '\0';
13874 13876 ++propname;
13875 13877
13876 13878 if (type != NULL) {
13877 13879 ty = string_to_type(type);
13878 13880 if (ty == SCF_TYPE_INVALID) {
13879 13881 semerr(gettext("Unknown type \"%s\".\n"), type);
13880 13882 goto fail;
13881 13883 }
13882 13884 }
13883 13885
13884 13886 if (cur_inst != NULL)
13885 13887 ret = scf_instance_get_pg(cur_inst, pgname, pg);
13886 13888 else
13887 13889 ret = scf_service_get_pg(cur_svc, pgname, pg);
13888 13890 if (ret != SCF_SUCCESS) {
13889 13891 switch (scf_error()) {
13890 13892 case SCF_ERROR_NOT_FOUND:
13891 13893 semerr(emsg_no_such_pg, pgname);
13892 13894 goto fail;
13893 13895
13894 13896 case SCF_ERROR_INVALID_ARGUMENT:
13895 13897 semerr(emsg_invalid_pg_name, pgname);
13896 13898 goto fail;
13897 13899
13898 13900 default:
13899 13901 scfdie();
13900 13902 break;
13901 13903 }
13902 13904 }
13903 13905
13904 13906 do {
13905 13907 if (scf_pg_update(pg) == -1)
13906 13908 scfdie();
13907 13909 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13908 13910 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13909 13911 scfdie();
13910 13912
13911 13913 semerr(emsg_permission_denied);
13912 13914 goto fail;
13913 13915 }
13914 13916
13915 13917 ret = scf_pg_get_property(pg, propname, prop);
13916 13918 if (ret == SCF_SUCCESS) {
13917 13919 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS)
13918 13920 scfdie();
13919 13921
13920 13922 if (type == NULL)
13921 13923 ty = current_ty;
13922 13924 if (scf_transaction_property_change_type(tx, e,
13923 13925 propname, ty) == -1)
13924 13926 scfdie();
13925 13927
13926 13928 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13927 13929 /* Infer the type, if possible. */
13928 13930 if (type == NULL) {
13929 13931 /*
13930 13932 * First check if we're an instance and the
13931 13933 * property is set on the service.
13932 13934 */
13933 13935 if (cur_inst != NULL &&
13934 13936 scf_instance_get_parent(cur_inst,
13935 13937 svc) == 0 &&
13936 13938 scf_service_get_pg(cur_svc, pgname,
13937 13939 parent_pg) == 0 &&
13938 13940 scf_pg_get_property(parent_pg, propname,
13939 13941 parent_prop) == 0 &&
13940 13942 scf_property_type(parent_prop,
13941 13943 ¤t_ty) == 0) {
13942 13944 ty = current_ty;
13943 13945
13944 13946 /* Then check for a type set in a template. */
13945 13947 } else if (scf_tmpl_get_by_pg(pg, pgt,
13946 13948 0) == 0 &&
13947 13949 scf_tmpl_get_by_prop(pgt, propname, prt,
13948 13950 0) == 0 &&
13949 13951 scf_tmpl_prop_type(prt, ¤t_ty) == 0) {
13950 13952 ty = current_ty;
13951 13953
13952 13954 /* If type can't be inferred, fail. */
13953 13955 } else {
13954 13956 semerr(gettext("Type required for new "
13955 13957 "properties.\n"));
13956 13958 goto fail;
13957 13959 }
13958 13960 }
13959 13961 if (scf_transaction_property_new(tx, e, propname,
13960 13962 ty) == -1)
13961 13963 scfdie();
13962 13964 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13963 13965 semerr(emsg_invalid_prop_name, propname);
13964 13966 goto fail;
13965 13967 } else {
13966 13968 scfdie();
13967 13969 }
13968 13970
13969 13971 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13970 13972 req_quotes = 1;
13971 13973
13972 13974 if (value != NULL) {
13973 13975 v = string_to_value(value, ty, 0);
13974 13976
13975 13977 if (v == NULL)
13976 13978 goto fail;
13977 13979
13978 13980 ret = scf_entry_add_value(e, v);
13979 13981 assert(ret == SCF_SUCCESS);
13980 13982 } else {
13981 13983 assert(values != NULL);
13982 13984
13983 13985 walk = uu_list_walk_start((uu_list_t *)values,
13984 13986 UU_DEFAULT);
13985 13987 if (walk == NULL)
13986 13988 uu_die(gettext("Could not walk list"));
13987 13989
13988 13990 for (sp = uu_list_walk_next(walk); sp != NULL;
13989 13991 sp = uu_list_walk_next(walk)) {
13990 13992 v = string_to_value(sp->str, ty, req_quotes);
13991 13993
13992 13994 if (v == NULL) {
13993 13995 scf_entry_destroy_children(e);
13994 13996 goto fail;
13995 13997 }
13996 13998
13997 13999 ret = scf_entry_add_value(e, v);
13998 14000 assert(ret == SCF_SUCCESS);
13999 14001 }
14000 14002 uu_list_walk_end(walk);
14001 14003 }
14002 14004 result = scf_transaction_commit(tx);
14003 14005
14004 14006 scf_transaction_reset(tx);
14005 14007 scf_entry_destroy_children(e);
14006 14008 } while (result == 0);
14007 14009
14008 14010 if (result < 0) {
14009 14011 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14010 14012 scfdie();
14011 14013
14012 14014 semerr(emsg_permission_denied);
14013 14015 goto fail;
14014 14016 }
14015 14017
14016 14018 ret = 0;
14017 14019
14018 14020 private_refresh();
14019 14021
14020 14022 goto cleanup;
14021 14023
14022 14024 fail:
14023 14025 ret = -1;
14024 14026
14025 14027 cleanup:
14026 14028 scf_transaction_destroy(tx);
14027 14029 scf_entry_destroy(e);
14028 14030 scf_service_destroy(svc);
14029 14031 scf_pg_destroy(parent_pg);
14030 14032 scf_pg_destroy(pg);
14031 14033 scf_property_destroy(parent_prop);
14032 14034 scf_property_destroy(prop);
14033 14035 scf_tmpl_pg_destroy(pgt);
14034 14036 scf_tmpl_prop_destroy(prt);
14035 14037
14036 14038 return (ret);
14037 14039 }
14038 14040
14039 14041 void
14040 14042 lscf_delprop(char *pgn)
14041 14043 {
14042 14044 char *slash, *pn;
14043 14045 scf_propertygroup_t *pg;
14044 14046 scf_transaction_t *tx;
14045 14047 scf_transaction_entry_t *e;
14046 14048 int ret;
14047 14049
14048 14050
14049 14051 lscf_prep_hndl();
14050 14052
14051 14053 if (cur_snap != NULL) {
14052 14054 semerr(emsg_cant_modify_snapshots);
14053 14055 return;
14054 14056 }
14055 14057
14056 14058 if (cur_inst == NULL && cur_svc == NULL) {
14057 14059 semerr(emsg_entity_not_selected);
14058 14060 return;
14059 14061 }
14060 14062
14061 14063 pg = scf_pg_create(g_hndl);
14062 14064 if (pg == NULL)
14063 14065 scfdie();
14064 14066
14065 14067 slash = strchr(pgn, '/');
14066 14068 if (slash == NULL) {
14067 14069 pn = NULL;
14068 14070 } else {
14069 14071 *slash = '\0';
14070 14072 pn = slash + 1;
14071 14073 }
14072 14074
14073 14075 if (cur_inst != NULL)
14074 14076 ret = scf_instance_get_pg(cur_inst, pgn, pg);
14075 14077 else
14076 14078 ret = scf_service_get_pg(cur_svc, pgn, pg);
14077 14079 if (ret != SCF_SUCCESS) {
14078 14080 switch (scf_error()) {
14079 14081 case SCF_ERROR_NOT_FOUND:
14080 14082 semerr(emsg_no_such_pg, pgn);
14081 14083 break;
14082 14084
14083 14085 case SCF_ERROR_INVALID_ARGUMENT:
14084 14086 semerr(emsg_invalid_pg_name, pgn);
14085 14087 break;
14086 14088
14087 14089 default:
14088 14090 scfdie();
14089 14091 }
14090 14092
14091 14093 scf_pg_destroy(pg);
14092 14094
14093 14095 return;
14094 14096 }
14095 14097
14096 14098 if (pn == NULL) {
14097 14099 /* Try to delete the property group. */
14098 14100 if (scf_pg_delete(pg) != SCF_SUCCESS) {
14099 14101 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14100 14102 scfdie();
14101 14103
14102 14104 semerr(emsg_permission_denied);
14103 14105 } else {
14104 14106 private_refresh();
14105 14107 }
14106 14108
14107 14109 scf_pg_destroy(pg);
14108 14110 return;
14109 14111 }
14110 14112
14111 14113 e = scf_entry_create(g_hndl);
14112 14114 tx = scf_transaction_create(g_hndl);
14113 14115
14114 14116 do {
14115 14117 if (scf_pg_update(pg) == -1)
14116 14118 scfdie();
14117 14119 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14118 14120 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14119 14121 scfdie();
14120 14122
14121 14123 semerr(emsg_permission_denied);
14122 14124 break;
14123 14125 }
14124 14126
14125 14127 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14126 14128 if (scf_error() == SCF_ERROR_NOT_FOUND) {
14127 14129 semerr(gettext("No such property %s/%s.\n"),
14128 14130 pgn, pn);
14129 14131 break;
14130 14132 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14131 14133 semerr(emsg_invalid_prop_name, pn);
14132 14134 break;
14133 14135 } else {
14134 14136 scfdie();
14135 14137 }
14136 14138 }
14137 14139
14138 14140 ret = scf_transaction_commit(tx);
14139 14141
14140 14142 if (ret == 0)
14141 14143 scf_transaction_reset(tx);
14142 14144 } while (ret == 0);
14143 14145
14144 14146 if (ret < 0) {
14145 14147 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14146 14148 scfdie();
14147 14149
14148 14150 semerr(emsg_permission_denied);
14149 14151 } else {
14150 14152 private_refresh();
14151 14153 }
14152 14154
14153 14155 scf_transaction_destroy(tx);
14154 14156 scf_entry_destroy(e);
14155 14157 scf_pg_destroy(pg);
14156 14158 }
14157 14159
14158 14160 /*
14159 14161 * Property editing.
14160 14162 */
14161 14163
14162 14164 static int
14163 14165 write_edit_script(FILE *strm)
14164 14166 {
14165 14167 char *fmribuf;
14166 14168 ssize_t fmrilen;
14167 14169
14168 14170 scf_propertygroup_t *pg;
14169 14171 scf_property_t *prop;
14170 14172 scf_value_t *val;
14171 14173 scf_type_t ty;
14172 14174 int ret, result = 0;
14173 14175 scf_iter_t *iter, *piter, *viter;
14174 14176 char *buf, *tybuf, *pname;
14175 14177 const char *emsg_write_error;
14176 14178
14177 14179
14178 14180 emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14179 14181
14180 14182
14181 14183 /* select fmri */
14182 14184 if (cur_inst != NULL) {
14183 14185 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14184 14186 if (fmrilen < 0)
14185 14187 scfdie();
14186 14188 fmribuf = safe_malloc(fmrilen + 1);
14187 14189 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14188 14190 scfdie();
14189 14191 } else {
14190 14192 assert(cur_svc != NULL);
14191 14193 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14192 14194 if (fmrilen < 0)
14193 14195 scfdie();
14194 14196 fmribuf = safe_malloc(fmrilen + 1);
14195 14197 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14196 14198 scfdie();
14197 14199 }
14198 14200
14199 14201 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14200 14202 warn(emsg_write_error, strerror(errno));
14201 14203 free(fmribuf);
14202 14204 return (-1);
14203 14205 }
14204 14206
14205 14207 free(fmribuf);
14206 14208
14207 14209
14208 14210 if ((pg = scf_pg_create(g_hndl)) == NULL ||
14209 14211 (prop = scf_property_create(g_hndl)) == NULL ||
14210 14212 (val = scf_value_create(g_hndl)) == NULL ||
14211 14213 (iter = scf_iter_create(g_hndl)) == NULL ||
14212 14214 (piter = scf_iter_create(g_hndl)) == NULL ||
14213 14215 (viter = scf_iter_create(g_hndl)) == NULL)
14214 14216 scfdie();
14215 14217
14216 14218 buf = safe_malloc(max_scf_name_len + 1);
14217 14219 tybuf = safe_malloc(max_scf_pg_type_len + 1);
14218 14220 pname = safe_malloc(max_scf_name_len + 1);
14219 14221
14220 14222 if (cur_inst != NULL)
14221 14223 ret = scf_iter_instance_pgs(iter, cur_inst);
14222 14224 else
14223 14225 ret = scf_iter_service_pgs(iter, cur_svc);
14224 14226 if (ret != SCF_SUCCESS)
14225 14227 scfdie();
14226 14228
14227 14229 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14228 14230 int ret2;
14229 14231
14230 14232 /*
14231 14233 * # delprop pg
14232 14234 * # addpg pg type
14233 14235 */
14234 14236 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14235 14237 scfdie();
14236 14238
14237 14239 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14238 14240 scfdie();
14239 14241
14240 14242 if (fprintf(strm, "# Property group \"%s\"\n"
14241 14243 "# delprop %s\n"
14242 14244 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14243 14245 warn(emsg_write_error, strerror(errno));
14244 14246 result = -1;
14245 14247 goto out;
14246 14248 }
14247 14249
14248 14250 /* # setprop pg/prop = (values) */
14249 14251
14250 14252 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14251 14253 scfdie();
14252 14254
14253 14255 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14254 14256 int first = 1;
14255 14257 int ret3;
14256 14258 int multiple;
14257 14259 int is_str;
14258 14260 scf_type_t bty;
14259 14261
14260 14262 if (scf_property_get_name(prop, pname,
14261 14263 max_scf_name_len + 1) < 0)
14262 14264 scfdie();
14263 14265
14264 14266 if (scf_property_type(prop, &ty) != 0)
14265 14267 scfdie();
14266 14268
14267 14269 multiple = prop_has_multiple_values(prop, val);
14268 14270
14269 14271 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14270 14272 pname, scf_type_to_string(ty), multiple ? "(" : "")
14271 14273 < 0) {
14272 14274 warn(emsg_write_error, strerror(errno));
14273 14275 result = -1;
14274 14276 goto out;
14275 14277 }
14276 14278
14277 14279 (void) scf_type_base_type(ty, &bty);
14278 14280 is_str = (bty == SCF_TYPE_ASTRING);
14279 14281
14280 14282 if (scf_iter_property_values(viter, prop) !=
14281 14283 SCF_SUCCESS)
14282 14284 scfdie();
14283 14285
14284 14286 while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14285 14287 char *buf;
14286 14288 ssize_t buflen;
14287 14289
14288 14290 buflen = scf_value_get_as_string(val, NULL, 0);
14289 14291 if (buflen < 0)
14290 14292 scfdie();
14291 14293
14292 14294 buf = safe_malloc(buflen + 1);
14293 14295
14294 14296 if (scf_value_get_as_string(val, buf,
14295 14297 buflen + 1) < 0)
14296 14298 scfdie();
14297 14299
14298 14300 if (first)
14299 14301 first = 0;
14300 14302 else {
14301 14303 if (putc(' ', strm) != ' ') {
14302 14304 warn(emsg_write_error,
14303 14305 strerror(errno));
14304 14306 result = -1;
14305 14307 goto out;
14306 14308 }
14307 14309 }
14308 14310
14309 14311 if ((is_str && multiple) ||
14310 14312 strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14311 14313 (void) putc('"', strm);
14312 14314 (void) quote_and_print(buf, strm, 1);
14313 14315 (void) putc('"', strm);
14314 14316
14315 14317 if (ferror(strm)) {
14316 14318 warn(emsg_write_error,
14317 14319 strerror(errno));
14318 14320 result = -1;
14319 14321 goto out;
14320 14322 }
14321 14323 } else {
14322 14324 if (fprintf(strm, "%s", buf) < 0) {
14323 14325 warn(emsg_write_error,
14324 14326 strerror(errno));
14325 14327 result = -1;
14326 14328 goto out;
14327 14329 }
14328 14330 }
14329 14331
14330 14332 free(buf);
14331 14333 }
14332 14334 if (ret3 < 0 &&
14333 14335 scf_error() != SCF_ERROR_PERMISSION_DENIED)
14334 14336 scfdie();
14335 14337
14336 14338 /* Write closing paren if mult-value property */
14337 14339 if ((multiple && putc(')', strm) == EOF) ||
14338 14340
14339 14341 /* Write final newline */
14340 14342 fputc('\n', strm) == EOF) {
14341 14343 warn(emsg_write_error, strerror(errno));
14342 14344 result = -1;
14343 14345 goto out;
14344 14346 }
14345 14347 }
14346 14348 if (ret2 < 0)
14347 14349 scfdie();
14348 14350
14349 14351 if (fputc('\n', strm) == EOF) {
14350 14352 warn(emsg_write_error, strerror(errno));
14351 14353 result = -1;
14352 14354 goto out;
14353 14355 }
14354 14356 }
14355 14357 if (ret < 0)
14356 14358 scfdie();
14357 14359
14358 14360 out:
14359 14361 free(pname);
14360 14362 free(tybuf);
14361 14363 free(buf);
14362 14364 scf_iter_destroy(viter);
14363 14365 scf_iter_destroy(piter);
14364 14366 scf_iter_destroy(iter);
14365 14367 scf_value_destroy(val);
14366 14368 scf_property_destroy(prop);
14367 14369 scf_pg_destroy(pg);
14368 14370
14369 14371 if (result == 0) {
14370 14372 if (fflush(strm) != 0) {
14371 14373 warn(emsg_write_error, strerror(errno));
14372 14374 return (-1);
14373 14375 }
14374 14376 }
14375 14377
14376 14378 return (result);
14377 14379 }
14378 14380
14379 14381 int
14380 14382 lscf_editprop()
14381 14383 {
14382 14384 char *buf, *editor;
14383 14385 size_t bufsz;
14384 14386 int tmpfd;
14385 14387 char tempname[] = TEMP_FILE_PATTERN;
14386 14388
14387 14389 lscf_prep_hndl();
14388 14390
14389 14391 if (cur_snap != NULL) {
14390 14392 semerr(emsg_cant_modify_snapshots);
14391 14393 return (-1);
14392 14394 }
14393 14395
14394 14396 if (cur_svc == NULL && cur_inst == NULL) {
14395 14397 semerr(emsg_entity_not_selected);
14396 14398 return (-1);
14397 14399 }
14398 14400
14399 14401 tmpfd = mkstemp(tempname);
14400 14402 if (tmpfd == -1) {
14401 14403 semerr(gettext("Could not create temporary file.\n"));
14402 14404 return (-1);
14403 14405 }
14404 14406
14405 14407 (void) strcpy(tempfilename, tempname);
14406 14408
14407 14409 tempfile = fdopen(tmpfd, "r+");
14408 14410 if (tempfile == NULL) {
14409 14411 warn(gettext("Could not create temporary file.\n"));
14410 14412 if (close(tmpfd) == -1)
14411 14413 warn(gettext("Could not close temporary file: %s.\n"),
14412 14414 strerror(errno));
14413 14415
14414 14416 remove_tempfile();
14415 14417
14416 14418 return (-1);
14417 14419 }
14418 14420
14419 14421 if (write_edit_script(tempfile) == -1) {
14420 14422 remove_tempfile();
14421 14423 return (-1);
14422 14424 }
14423 14425
14424 14426 editor = getenv("EDITOR");
14425 14427 if (editor == NULL)
14426 14428 editor = "vi";
14427 14429
14428 14430 bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14429 14431 buf = safe_malloc(bufsz);
14430 14432
14431 14433 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14432 14434 uu_die(gettext("Error creating editor command"));
14433 14435
14434 14436 if (system(buf) == -1) {
14435 14437 semerr(gettext("Could not launch editor %s: %s\n"), editor,
14436 14438 strerror(errno));
14437 14439 free(buf);
14438 14440 remove_tempfile();
14439 14441 return (-1);
14440 14442 }
14441 14443
14442 14444 free(buf);
14443 14445
14444 14446 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14445 14447
14446 14448 remove_tempfile();
14447 14449
14448 14450 return (0);
14449 14451 }
14450 14452
14451 14453 static void
14452 14454 add_string(uu_list_t *strlist, const char *str)
14453 14455 {
14454 14456 string_list_t *elem;
14455 14457 elem = safe_malloc(sizeof (*elem));
14456 14458 uu_list_node_init(elem, &elem->node, string_pool);
14457 14459 elem->str = safe_strdup(str);
14458 14460 if (uu_list_append(strlist, elem) != 0)
14459 14461 uu_die(gettext("libuutil error: %s\n"),
14460 14462 uu_strerror(uu_error()));
14461 14463 }
14462 14464
14463 14465 static int
14464 14466 remove_string(uu_list_t *strlist, const char *str)
14465 14467 {
14466 14468 uu_list_walk_t *elems;
14467 14469 string_list_t *sp;
14468 14470
14469 14471 /*
14470 14472 * Find the element that needs to be removed.
14471 14473 */
14472 14474 elems = uu_list_walk_start(strlist, UU_DEFAULT);
14473 14475 while ((sp = uu_list_walk_next(elems)) != NULL) {
14474 14476 if (strcmp(sp->str, str) == 0)
14475 14477 break;
14476 14478 }
14477 14479 uu_list_walk_end(elems);
14478 14480
14479 14481 /*
14480 14482 * Returning 1 here as the value was not found, this
14481 14483 * might not be an error. Leave it to the caller to
14482 14484 * decide.
14483 14485 */
14484 14486 if (sp == NULL) {
14485 14487 return (1);
14486 14488 }
14487 14489
14488 14490 uu_list_remove(strlist, sp);
14489 14491
14490 14492 free(sp->str);
14491 14493 free(sp);
14492 14494
14493 14495 return (0);
14494 14496 }
14495 14497
14496 14498 /*
14497 14499 * Get all property values that don't match the given glob pattern,
14498 14500 * if a pattern is specified.
14499 14501 */
14500 14502 static void
14501 14503 get_prop_values(scf_property_t *prop, uu_list_t *values,
14502 14504 const char *pattern)
14503 14505 {
14504 14506 scf_iter_t *iter;
14505 14507 scf_value_t *val;
14506 14508 int ret;
14507 14509
14508 14510 if ((iter = scf_iter_create(g_hndl)) == NULL ||
14509 14511 (val = scf_value_create(g_hndl)) == NULL)
14510 14512 scfdie();
14511 14513
14512 14514 if (scf_iter_property_values(iter, prop) != 0)
14513 14515 scfdie();
14514 14516
14515 14517 while ((ret = scf_iter_next_value(iter, val)) == 1) {
14516 14518 char *buf;
14517 14519 ssize_t vlen, szret;
14518 14520
14519 14521 vlen = scf_value_get_as_string(val, NULL, 0);
14520 14522 if (vlen < 0)
14521 14523 scfdie();
14522 14524
14523 14525 buf = safe_malloc(vlen + 1);
14524 14526
14525 14527 szret = scf_value_get_as_string(val, buf, vlen + 1);
14526 14528 if (szret < 0)
14527 14529 scfdie();
14528 14530 assert(szret <= vlen);
14529 14531
14530 14532 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14531 14533 add_string(values, buf);
14532 14534
14533 14535 free(buf);
14534 14536 }
14535 14537
14536 14538 if (ret == -1)
14537 14539 scfdie();
14538 14540
14539 14541 scf_value_destroy(val);
14540 14542 scf_iter_destroy(iter);
14541 14543 }
14542 14544
14543 14545 static int
14544 14546 lscf_setpropvalue(const char *pgname, const char *type,
14545 14547 const char *arg, int isadd, int isnotfoundok)
14546 14548 {
14547 14549 scf_type_t ty;
14548 14550 scf_propertygroup_t *pg;
14549 14551 scf_property_t *prop;
14550 14552 int ret, result = 0;
14551 14553 scf_transaction_t *tx;
14552 14554 scf_transaction_entry_t *e;
14553 14555 scf_value_t *v;
14554 14556 string_list_t *sp;
14555 14557 char *propname;
14556 14558 uu_list_t *values;
14557 14559 uu_list_walk_t *walk;
14558 14560 void *cookie = NULL;
14559 14561 char *pattern = NULL;
14560 14562
14561 14563 lscf_prep_hndl();
14562 14564
14563 14565 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14564 14566 uu_die(gettext("Could not create property list: %s\n"),
14565 14567 uu_strerror(uu_error()));
14566 14568
14567 14569 if (!isadd)
14568 14570 pattern = safe_strdup(arg);
14569 14571
14570 14572 if ((e = scf_entry_create(g_hndl)) == NULL ||
14571 14573 (pg = scf_pg_create(g_hndl)) == NULL ||
14572 14574 (prop = scf_property_create(g_hndl)) == NULL ||
14573 14575 (tx = scf_transaction_create(g_hndl)) == NULL)
14574 14576 scfdie();
14575 14577
14576 14578 if (cur_snap != NULL) {
14577 14579 semerr(emsg_cant_modify_snapshots);
14578 14580 goto fail;
14579 14581 }
14580 14582
14581 14583 if (cur_inst == NULL && cur_svc == NULL) {
14582 14584 semerr(emsg_entity_not_selected);
14583 14585 goto fail;
14584 14586 }
14585 14587
14586 14588 propname = strchr(pgname, '/');
14587 14589 if (propname == NULL) {
14588 14590 semerr(gettext("Property names must contain a `/'.\n"));
14589 14591 goto fail;
14590 14592 }
14591 14593
14592 14594 *propname = '\0';
14593 14595 ++propname;
14594 14596
14595 14597 if (type != NULL) {
14596 14598 ty = string_to_type(type);
14597 14599 if (ty == SCF_TYPE_INVALID) {
14598 14600 semerr(gettext("Unknown type \"%s\".\n"), type);
14599 14601 goto fail;
14600 14602 }
14601 14603 }
14602 14604
14603 14605 if (cur_inst != NULL)
14604 14606 ret = scf_instance_get_pg(cur_inst, pgname, pg);
14605 14607 else
14606 14608 ret = scf_service_get_pg(cur_svc, pgname, pg);
14607 14609 if (ret != 0) {
14608 14610 switch (scf_error()) {
14609 14611 case SCF_ERROR_NOT_FOUND:
14610 14612 if (isnotfoundok) {
14611 14613 result = 0;
14612 14614 } else {
14613 14615 semerr(emsg_no_such_pg, pgname);
14614 14616 result = -1;
14615 14617 }
14616 14618 goto out;
14617 14619
14618 14620 case SCF_ERROR_INVALID_ARGUMENT:
14619 14621 semerr(emsg_invalid_pg_name, pgname);
14620 14622 goto fail;
14621 14623
14622 14624 default:
14623 14625 scfdie();
14624 14626 }
14625 14627 }
14626 14628
14627 14629 do {
14628 14630 if (scf_pg_update(pg) == -1)
14629 14631 scfdie();
14630 14632 if (scf_transaction_start(tx, pg) != 0) {
14631 14633 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14632 14634 scfdie();
14633 14635
14634 14636 semerr(emsg_permission_denied);
14635 14637 goto fail;
14636 14638 }
14637 14639
14638 14640 ret = scf_pg_get_property(pg, propname, prop);
14639 14641 if (ret == 0) {
14640 14642 scf_type_t ptype;
14641 14643 char *pat = pattern;
14642 14644
14643 14645 if (scf_property_type(prop, &ptype) != 0)
14644 14646 scfdie();
14645 14647
14646 14648 if (isadd) {
14647 14649 if (type != NULL && ptype != ty) {
14648 14650 semerr(gettext("Property \"%s\" is not "
14649 14651 "of type \"%s\".\n"), propname,
14650 14652 type);
14651 14653 goto fail;
14652 14654 }
14653 14655
14654 14656 pat = NULL;
14655 14657 } else {
14656 14658 size_t len = strlen(pat);
14657 14659 if (len > 0 && pat[len - 1] == '\"')
14658 14660 pat[len - 1] = '\0';
14659 14661 if (len > 0 && pat[0] == '\"')
14660 14662 pat++;
14661 14663 }
14662 14664
14663 14665 ty = ptype;
14664 14666
14665 14667 get_prop_values(prop, values, pat);
14666 14668
14667 14669 if (isadd)
14668 14670 add_string(values, arg);
14669 14671
14670 14672 if (scf_transaction_property_change(tx, e,
14671 14673 propname, ty) == -1)
14672 14674 scfdie();
14673 14675 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14674 14676 if (isadd) {
14675 14677 if (type == NULL) {
14676 14678 semerr(gettext("Type required "
14677 14679 "for new properties.\n"));
14678 14680 goto fail;
14679 14681 }
14680 14682
14681 14683 add_string(values, arg);
14682 14684
14683 14685 if (scf_transaction_property_new(tx, e,
14684 14686 propname, ty) == -1)
14685 14687 scfdie();
14686 14688 } else if (isnotfoundok) {
14687 14689 result = 0;
14688 14690 goto out;
14689 14691 } else {
14690 14692 semerr(gettext("No such property %s/%s.\n"),
14691 14693 pgname, propname);
14692 14694 result = -1;
14693 14695 goto out;
14694 14696 }
14695 14697 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14696 14698 semerr(emsg_invalid_prop_name, propname);
14697 14699 goto fail;
14698 14700 } else {
14699 14701 scfdie();
14700 14702 }
14701 14703
14702 14704 walk = uu_list_walk_start(values, UU_DEFAULT);
14703 14705 if (walk == NULL)
14704 14706 uu_die(gettext("Could not walk property list.\n"));
14705 14707
14706 14708 for (sp = uu_list_walk_next(walk); sp != NULL;
14707 14709 sp = uu_list_walk_next(walk)) {
14708 14710 v = string_to_value(sp->str, ty, 0);
14709 14711
14710 14712 if (v == NULL) {
14711 14713 scf_entry_destroy_children(e);
14712 14714 goto fail;
14713 14715 }
14714 14716 ret = scf_entry_add_value(e, v);
14715 14717 assert(ret == 0);
14716 14718 }
14717 14719 uu_list_walk_end(walk);
14718 14720
14719 14721 result = scf_transaction_commit(tx);
14720 14722
14721 14723 scf_transaction_reset(tx);
14722 14724 scf_entry_destroy_children(e);
14723 14725 } while (result == 0);
14724 14726
14725 14727 if (result < 0) {
14726 14728 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14727 14729 scfdie();
14728 14730
14729 14731 semerr(emsg_permission_denied);
14730 14732 goto fail;
14731 14733 }
14732 14734
14733 14735 result = 0;
14734 14736
14735 14737 private_refresh();
14736 14738
14737 14739 out:
14738 14740 scf_transaction_destroy(tx);
14739 14741 scf_entry_destroy(e);
14740 14742 scf_pg_destroy(pg);
14741 14743 scf_property_destroy(prop);
14742 14744 free(pattern);
14743 14745
14744 14746 while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14745 14747 free(sp->str);
14746 14748 free(sp);
14747 14749 }
14748 14750
14749 14751 uu_list_destroy(values);
14750 14752
14751 14753 return (result);
14752 14754
14753 14755 fail:
14754 14756 result = -1;
14755 14757 goto out;
14756 14758 }
14757 14759
14758 14760 int
14759 14761 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14760 14762 {
14761 14763 return (lscf_setpropvalue(pgname, type, value, 1, 0));
14762 14764 }
14763 14765
14764 14766 int
14765 14767 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14766 14768 {
14767 14769 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14768 14770 }
14769 14771
14770 14772 /*
14771 14773 * Look for a standard start method, first in the instance (if any),
14772 14774 * then the service.
14773 14775 */
14774 14776 static const char *
14775 14777 start_method_name(int *in_instance)
14776 14778 {
14777 14779 scf_propertygroup_t *pg;
14778 14780 char **p;
14779 14781 int ret;
14780 14782 scf_instance_t *inst = cur_inst;
14781 14783
14782 14784 if ((pg = scf_pg_create(g_hndl)) == NULL)
14783 14785 scfdie();
14784 14786
14785 14787 again:
14786 14788 for (p = start_method_names; *p != NULL; p++) {
14787 14789 if (inst != NULL)
14788 14790 ret = scf_instance_get_pg(inst, *p, pg);
14789 14791 else
14790 14792 ret = scf_service_get_pg(cur_svc, *p, pg);
14791 14793
14792 14794 if (ret == 0) {
14793 14795 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14794 14796 char *buf = safe_malloc(bufsz);
14795 14797
14796 14798 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14797 14799 free(buf);
14798 14800 continue;
14799 14801 }
14800 14802 if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14801 14803 free(buf);
14802 14804 continue;
14803 14805 }
14804 14806
14805 14807 free(buf);
14806 14808 *in_instance = (inst != NULL);
14807 14809 scf_pg_destroy(pg);
14808 14810 return (*p);
14809 14811 }
14810 14812
14811 14813 if (scf_error() == SCF_ERROR_NOT_FOUND)
14812 14814 continue;
14813 14815
14814 14816 scfdie();
14815 14817 }
14816 14818
14817 14819 if (inst != NULL) {
14818 14820 inst = NULL;
14819 14821 goto again;
14820 14822 }
14821 14823
14822 14824 scf_pg_destroy(pg);
14823 14825 return (NULL);
14824 14826 }
14825 14827
14826 14828 static int
14827 14829 addpg(const char *name, const char *type)
14828 14830 {
14829 14831 scf_propertygroup_t *pg;
14830 14832 int ret;
14831 14833
14832 14834 pg = scf_pg_create(g_hndl);
14833 14835 if (pg == NULL)
14834 14836 scfdie();
14835 14837
14836 14838 if (cur_inst != NULL)
14837 14839 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14838 14840 else
14839 14841 ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14840 14842
14841 14843 if (ret != 0) {
14842 14844 switch (scf_error()) {
14843 14845 case SCF_ERROR_EXISTS:
14844 14846 ret = 0;
14845 14847 break;
14846 14848
14847 14849 case SCF_ERROR_PERMISSION_DENIED:
14848 14850 semerr(emsg_permission_denied);
14849 14851 break;
14850 14852
14851 14853 default:
14852 14854 scfdie();
14853 14855 }
14854 14856 }
14855 14857
14856 14858 scf_pg_destroy(pg);
14857 14859 return (ret);
14858 14860 }
14859 14861
14860 14862 int
14861 14863 lscf_setenv(uu_list_t *args, int isunset)
14862 14864 {
14863 14865 int ret = 0;
14864 14866 size_t i;
14865 14867 int argc;
14866 14868 char **argv = NULL;
14867 14869 string_list_t *slp;
14868 14870 char *pattern;
14869 14871 char *prop;
14870 14872 int do_service = 0;
14871 14873 int do_instance = 0;
14872 14874 const char *method = NULL;
14873 14875 const char *name = NULL;
14874 14876 const char *value = NULL;
14875 14877 scf_instance_t *saved_cur_inst = cur_inst;
14876 14878
14877 14879 lscf_prep_hndl();
14878 14880
14879 14881 argc = uu_list_numnodes(args);
14880 14882 if (argc < 1)
14881 14883 goto usage;
14882 14884
14883 14885 argv = calloc(argc + 1, sizeof (char *));
14884 14886 if (argv == NULL)
14885 14887 uu_die(gettext("Out of memory.\n"));
14886 14888
14887 14889 for (slp = uu_list_first(args), i = 0;
14888 14890 slp != NULL;
14889 14891 slp = uu_list_next(args, slp), ++i)
14890 14892 argv[i] = slp->str;
14891 14893
14892 14894 argv[i] = NULL;
14893 14895
14894 14896 opterr = 0;
14895 14897 optind = 0;
14896 14898 for (;;) {
14897 14899 ret = getopt(argc, argv, "sim:");
14898 14900 if (ret == -1)
14899 14901 break;
14900 14902
14901 14903 switch (ret) {
14902 14904 case 's':
14903 14905 do_service = 1;
14904 14906 cur_inst = NULL;
14905 14907 break;
14906 14908
14907 14909 case 'i':
14908 14910 do_instance = 1;
14909 14911 break;
14910 14912
14911 14913 case 'm':
14912 14914 method = optarg;
14913 14915 break;
14914 14916
14915 14917 case '?':
14916 14918 goto usage;
14917 14919
14918 14920 default:
14919 14921 bad_error("getopt", ret);
14920 14922 }
14921 14923 }
14922 14924
14923 14925 argc -= optind;
14924 14926 if ((do_service && do_instance) ||
14925 14927 (isunset && argc != 1) ||
14926 14928 (!isunset && argc != 2))
14927 14929 goto usage;
14928 14930
14929 14931 name = argv[optind];
14930 14932 if (!isunset)
14931 14933 value = argv[optind + 1];
14932 14934
14933 14935 if (cur_snap != NULL) {
14934 14936 semerr(emsg_cant_modify_snapshots);
14935 14937 ret = -1;
14936 14938 goto out;
14937 14939 }
14938 14940
14939 14941 if (cur_inst == NULL && cur_svc == NULL) {
14940 14942 semerr(emsg_entity_not_selected);
14941 14943 ret = -1;
14942 14944 goto out;
14943 14945 }
14944 14946
14945 14947 if (do_instance && cur_inst == NULL) {
14946 14948 semerr(gettext("No instance is selected.\n"));
14947 14949 ret = -1;
14948 14950 goto out;
14949 14951 }
14950 14952
14951 14953 if (do_service && cur_svc == NULL) {
14952 14954 semerr(gettext("No service is selected.\n"));
14953 14955 ret = -1;
14954 14956 goto out;
14955 14957 }
14956 14958
14957 14959 if (method == NULL) {
14958 14960 if (do_instance || do_service) {
14959 14961 method = "method_context";
14960 14962 if (!isunset) {
14961 14963 ret = addpg("method_context",
14962 14964 SCF_GROUP_FRAMEWORK);
14963 14965 if (ret != 0)
14964 14966 goto out;
14965 14967 }
14966 14968 } else {
14967 14969 int in_instance;
14968 14970 method = start_method_name(&in_instance);
14969 14971 if (method == NULL) {
14970 14972 semerr(gettext(
14971 14973 "Couldn't find start method; please "
14972 14974 "specify a method with '-m'.\n"));
14973 14975 ret = -1;
14974 14976 goto out;
14975 14977 }
14976 14978 if (!in_instance)
14977 14979 cur_inst = NULL;
14978 14980 }
14979 14981 } else {
14980 14982 scf_propertygroup_t *pg;
14981 14983 size_t bufsz;
14982 14984 char *buf;
14983 14985 int ret;
14984 14986
14985 14987 if ((pg = scf_pg_create(g_hndl)) == NULL)
14986 14988 scfdie();
14987 14989
14988 14990 if (cur_inst != NULL)
14989 14991 ret = scf_instance_get_pg(cur_inst, method, pg);
14990 14992 else
14991 14993 ret = scf_service_get_pg(cur_svc, method, pg);
14992 14994
14993 14995 if (ret != 0) {
14994 14996 scf_pg_destroy(pg);
14995 14997 switch (scf_error()) {
14996 14998 case SCF_ERROR_NOT_FOUND:
14997 14999 semerr(gettext("Couldn't find the method "
14998 15000 "\"%s\".\n"), method);
14999 15001 goto out;
15000 15002
15001 15003 case SCF_ERROR_INVALID_ARGUMENT:
15002 15004 semerr(gettext("Invalid method name \"%s\".\n"),
15003 15005 method);
15004 15006 goto out;
15005 15007
15006 15008 default:
15007 15009 scfdie();
15008 15010 }
15009 15011 }
15010 15012
15011 15013 bufsz = strlen(SCF_GROUP_METHOD) + 1;
15012 15014 buf = safe_malloc(bufsz);
15013 15015
15014 15016 if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
15015 15017 strcmp(buf, SCF_GROUP_METHOD) != 0) {
15016 15018 semerr(gettext("Property group \"%s\" is not of type "
15017 15019 "\"method\".\n"), method);
15018 15020 ret = -1;
15019 15021 free(buf);
15020 15022 scf_pg_destroy(pg);
15021 15023 goto out;
15022 15024 }
15023 15025
15024 15026 free(buf);
15025 15027 scf_pg_destroy(pg);
15026 15028 }
15027 15029
15028 15030 prop = uu_msprintf("%s/environment", method);
15029 15031 pattern = uu_msprintf("%s=*", name);
15030 15032
15031 15033 if (prop == NULL || pattern == NULL)
15032 15034 uu_die(gettext("Out of memory.\n"));
15033 15035
15034 15036 ret = lscf_delpropvalue(prop, pattern, !isunset);
15035 15037
15036 15038 if (ret == 0 && !isunset) {
15037 15039 uu_free(pattern);
15038 15040 uu_free(prop);
15039 15041 prop = uu_msprintf("%s/environment", method);
15040 15042 pattern = uu_msprintf("%s=%s", name, value);
15041 15043 if (prop == NULL || pattern == NULL)
15042 15044 uu_die(gettext("Out of memory.\n"));
15043 15045 ret = lscf_addpropvalue(prop, "astring:", pattern);
15044 15046 }
15045 15047 uu_free(pattern);
15046 15048 uu_free(prop);
15047 15049
15048 15050 out:
15049 15051 cur_inst = saved_cur_inst;
15050 15052
15051 15053 free(argv);
15052 15054 return (ret);
15053 15055 usage:
15054 15056 ret = -2;
15055 15057 goto out;
15056 15058 }
15057 15059
15058 15060 /*
15059 15061 * Snapshot commands
15060 15062 */
15061 15063
15062 15064 void
15063 15065 lscf_listsnap()
15064 15066 {
15065 15067 scf_snapshot_t *snap;
15066 15068 scf_iter_t *iter;
15067 15069 char *nb;
15068 15070 int r;
15069 15071
15070 15072 lscf_prep_hndl();
15071 15073
15072 15074 if (cur_inst == NULL) {
15073 15075 semerr(gettext("Instance not selected.\n"));
15074 15076 return;
15075 15077 }
15076 15078
15077 15079 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15078 15080 (iter = scf_iter_create(g_hndl)) == NULL)
15079 15081 scfdie();
15080 15082
15081 15083 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15082 15084 scfdie();
15083 15085
15084 15086 nb = safe_malloc(max_scf_name_len + 1);
15085 15087
15086 15088 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15087 15089 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15088 15090 scfdie();
15089 15091
15090 15092 (void) puts(nb);
15091 15093 }
15092 15094 if (r < 0)
15093 15095 scfdie();
15094 15096
15095 15097 free(nb);
15096 15098 scf_iter_destroy(iter);
15097 15099 scf_snapshot_destroy(snap);
15098 15100 }
15099 15101
15100 15102 void
15101 15103 lscf_selectsnap(const char *name)
15102 15104 {
15103 15105 scf_snapshot_t *snap;
15104 15106 scf_snaplevel_t *level;
15105 15107
15106 15108 lscf_prep_hndl();
15107 15109
15108 15110 if (cur_inst == NULL) {
15109 15111 semerr(gettext("Instance not selected.\n"));
15110 15112 return;
15111 15113 }
15112 15114
15113 15115 if (cur_snap != NULL) {
15114 15116 if (name != NULL) {
15115 15117 char *cur_snap_name;
15116 15118 boolean_t nochange;
15117 15119
15118 15120 cur_snap_name = safe_malloc(max_scf_name_len + 1);
15119 15121
15120 15122 if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15121 15123 max_scf_name_len + 1) < 0)
15122 15124 scfdie();
15123 15125
15124 15126 nochange = strcmp(name, cur_snap_name) == 0;
15125 15127
15126 15128 free(cur_snap_name);
15127 15129
15128 15130 if (nochange)
15129 15131 return;
15130 15132 }
15131 15133
15132 15134 unselect_cursnap();
15133 15135 }
15134 15136
15135 15137 if (name == NULL)
15136 15138 return;
15137 15139
15138 15140 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15139 15141 (level = scf_snaplevel_create(g_hndl)) == NULL)
15140 15142 scfdie();
15141 15143
15142 15144 if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15143 15145 SCF_SUCCESS) {
15144 15146 switch (scf_error()) {
15145 15147 case SCF_ERROR_INVALID_ARGUMENT:
15146 15148 semerr(gettext("Invalid name \"%s\".\n"), name);
15147 15149 break;
15148 15150
15149 15151 case SCF_ERROR_NOT_FOUND:
15150 15152 semerr(gettext("No such snapshot \"%s\".\n"), name);
15151 15153 break;
15152 15154
15153 15155 default:
15154 15156 scfdie();
15155 15157 }
15156 15158
15157 15159 scf_snaplevel_destroy(level);
15158 15160 scf_snapshot_destroy(snap);
15159 15161 return;
15160 15162 }
15161 15163
15162 15164 /* Load the snaplevels into our list. */
15163 15165 cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15164 15166 if (cur_levels == NULL)
15165 15167 uu_die(gettext("Could not create list: %s\n"),
15166 15168 uu_strerror(uu_error()));
15167 15169
15168 15170 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15169 15171 if (scf_error() != SCF_ERROR_NOT_FOUND)
15170 15172 scfdie();
15171 15173
15172 15174 semerr(gettext("Snapshot has no snaplevels.\n"));
15173 15175
15174 15176 scf_snaplevel_destroy(level);
15175 15177 scf_snapshot_destroy(snap);
15176 15178 return;
15177 15179 }
15178 15180
15179 15181 cur_snap = snap;
15180 15182
15181 15183 for (;;) {
15182 15184 cur_elt = safe_malloc(sizeof (*cur_elt));
15183 15185 uu_list_node_init(cur_elt, &cur_elt->list_node,
15184 15186 snaplevel_pool);
15185 15187 cur_elt->sl = level;
15186 15188 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15187 15189 uu_die(gettext("libuutil error: %s\n"),
15188 15190 uu_strerror(uu_error()));
15189 15191
15190 15192 level = scf_snaplevel_create(g_hndl);
15191 15193 if (level == NULL)
15192 15194 scfdie();
15193 15195
15194 15196 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15195 15197 level) != SCF_SUCCESS) {
15196 15198 if (scf_error() != SCF_ERROR_NOT_FOUND)
15197 15199 scfdie();
15198 15200
15199 15201 scf_snaplevel_destroy(level);
15200 15202 break;
15201 15203 }
15202 15204 }
15203 15205
15204 15206 cur_elt = uu_list_last(cur_levels);
15205 15207 cur_level = cur_elt->sl;
15206 15208 }
15207 15209
15208 15210 /*
15209 15211 * Copies the properties & values in src to dst. Assumes src won't change.
15210 15212 * Returns -1 if permission is denied, -2 if another transaction interrupts,
15211 15213 * and 0 on success.
15212 15214 *
15213 15215 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15214 15216 * property, if it is copied and has type boolean. (See comment in
15215 15217 * lscf_revert()).
15216 15218 */
15217 15219 static int
15218 15220 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15219 15221 uint8_t enabled)
15220 15222 {
15221 15223 scf_transaction_t *tx;
15222 15224 scf_iter_t *iter, *viter;
15223 15225 scf_property_t *prop;
15224 15226 scf_value_t *v;
15225 15227 char *nbuf;
15226 15228 int r;
15227 15229
15228 15230 tx = scf_transaction_create(g_hndl);
15229 15231 if (tx == NULL)
15230 15232 scfdie();
15231 15233
15232 15234 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15233 15235 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15234 15236 scfdie();
15235 15237
15236 15238 scf_transaction_destroy(tx);
15237 15239
15238 15240 return (-1);
15239 15241 }
15240 15242
15241 15243 if ((iter = scf_iter_create(g_hndl)) == NULL ||
15242 15244 (prop = scf_property_create(g_hndl)) == NULL ||
15243 15245 (viter = scf_iter_create(g_hndl)) == NULL)
15244 15246 scfdie();
15245 15247
15246 15248 nbuf = safe_malloc(max_scf_name_len + 1);
15247 15249
15248 15250 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15249 15251 scfdie();
15250 15252
15251 15253 for (;;) {
15252 15254 scf_transaction_entry_t *e;
15253 15255 scf_type_t ty;
15254 15256
15255 15257 r = scf_iter_next_property(iter, prop);
15256 15258 if (r == -1)
15257 15259 scfdie();
15258 15260 if (r == 0)
15259 15261 break;
15260 15262
15261 15263 e = scf_entry_create(g_hndl);
15262 15264 if (e == NULL)
15263 15265 scfdie();
15264 15266
15265 15267 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15266 15268 scfdie();
15267 15269
15268 15270 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15269 15271 scfdie();
15270 15272
15271 15273 if (scf_transaction_property_new(tx, e, nbuf,
15272 15274 ty) != SCF_SUCCESS)
15273 15275 scfdie();
15274 15276
15275 15277 if ((enabled == 0 || enabled == 1) &&
15276 15278 strcmp(nbuf, scf_property_enabled) == 0 &&
15277 15279 ty == SCF_TYPE_BOOLEAN) {
15278 15280 v = scf_value_create(g_hndl);
15279 15281 if (v == NULL)
15280 15282 scfdie();
15281 15283
15282 15284 scf_value_set_boolean(v, enabled);
15283 15285
15284 15286 if (scf_entry_add_value(e, v) != 0)
15285 15287 scfdie();
15286 15288 } else {
15287 15289 if (scf_iter_property_values(viter, prop) != 0)
15288 15290 scfdie();
15289 15291
15290 15292 for (;;) {
15291 15293 v = scf_value_create(g_hndl);
15292 15294 if (v == NULL)
15293 15295 scfdie();
15294 15296
15295 15297 r = scf_iter_next_value(viter, v);
15296 15298 if (r == -1)
15297 15299 scfdie();
15298 15300 if (r == 0) {
15299 15301 scf_value_destroy(v);
15300 15302 break;
15301 15303 }
15302 15304
15303 15305 if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15304 15306 scfdie();
15305 15307 }
15306 15308 }
15307 15309 }
15308 15310
15309 15311 free(nbuf);
15310 15312 scf_iter_destroy(viter);
15311 15313 scf_property_destroy(prop);
15312 15314 scf_iter_destroy(iter);
15313 15315
15314 15316 r = scf_transaction_commit(tx);
15315 15317 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15316 15318 scfdie();
15317 15319
15318 15320 scf_transaction_destroy_children(tx);
15319 15321 scf_transaction_destroy(tx);
15320 15322
15321 15323 switch (r) {
15322 15324 case 1: return (0);
15323 15325 case 0: return (-2);
15324 15326 case -1: return (-1);
15325 15327
15326 15328 default:
15327 15329 abort();
15328 15330 }
15329 15331
15330 15332 /* NOTREACHED */
15331 15333 }
15332 15334
15333 15335 void
15334 15336 lscf_revert(const char *snapname)
15335 15337 {
15336 15338 scf_snapshot_t *snap, *prev;
15337 15339 scf_snaplevel_t *level, *nlevel;
15338 15340 scf_iter_t *iter;
15339 15341 scf_propertygroup_t *pg, *npg;
15340 15342 scf_property_t *prop;
15341 15343 scf_value_t *val;
15342 15344 char *nbuf, *tbuf;
15343 15345 uint8_t enabled;
15344 15346
15345 15347 lscf_prep_hndl();
15346 15348
15347 15349 if (cur_inst == NULL) {
15348 15350 semerr(gettext("Instance not selected.\n"));
15349 15351 return;
15350 15352 }
15351 15353
15352 15354 if (snapname != NULL) {
15353 15355 snap = scf_snapshot_create(g_hndl);
15354 15356 if (snap == NULL)
15355 15357 scfdie();
15356 15358
15357 15359 if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15358 15360 SCF_SUCCESS) {
15359 15361 switch (scf_error()) {
15360 15362 case SCF_ERROR_INVALID_ARGUMENT:
15361 15363 semerr(gettext("Invalid snapshot name "
15362 15364 "\"%s\".\n"), snapname);
15363 15365 break;
15364 15366
15365 15367 case SCF_ERROR_NOT_FOUND:
15366 15368 semerr(gettext("No such snapshot.\n"));
15367 15369 break;
15368 15370
15369 15371 default:
15370 15372 scfdie();
15371 15373 }
15372 15374
15373 15375 scf_snapshot_destroy(snap);
15374 15376 return;
15375 15377 }
15376 15378 } else {
15377 15379 if (cur_snap != NULL) {
15378 15380 snap = cur_snap;
15379 15381 } else {
15380 15382 semerr(gettext("No snapshot selected.\n"));
15381 15383 return;
15382 15384 }
15383 15385 }
15384 15386
15385 15387 if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15386 15388 (level = scf_snaplevel_create(g_hndl)) == NULL ||
15387 15389 (iter = scf_iter_create(g_hndl)) == NULL ||
15388 15390 (pg = scf_pg_create(g_hndl)) == NULL ||
15389 15391 (npg = scf_pg_create(g_hndl)) == NULL ||
15390 15392 (prop = scf_property_create(g_hndl)) == NULL ||
15391 15393 (val = scf_value_create(g_hndl)) == NULL)
15392 15394 scfdie();
15393 15395
15394 15396 nbuf = safe_malloc(max_scf_name_len + 1);
15395 15397 tbuf = safe_malloc(max_scf_pg_type_len + 1);
15396 15398
15397 15399 /* Take the "previous" snapshot before we blow away the properties. */
15398 15400 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15399 15401 if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15400 15402 scfdie();
15401 15403 } else {
15402 15404 if (scf_error() != SCF_ERROR_NOT_FOUND)
15403 15405 scfdie();
15404 15406
15405 15407 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15406 15408 scfdie();
15407 15409 }
15408 15410
15409 15411 /* Save general/enabled, since we're probably going to replace it. */
15410 15412 enabled = 2;
15411 15413 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15412 15414 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15413 15415 scf_property_get_value(prop, val) == 0)
15414 15416 (void) scf_value_get_boolean(val, &enabled);
15415 15417
15416 15418 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15417 15419 if (scf_error() != SCF_ERROR_NOT_FOUND)
15418 15420 scfdie();
15419 15421
15420 15422 goto out;
15421 15423 }
15422 15424
15423 15425 for (;;) {
15424 15426 boolean_t isinst;
15425 15427 uint32_t flags;
15426 15428 int r;
15427 15429
15428 15430 /* Clear the properties from the corresponding entity. */
15429 15431 isinst = snaplevel_is_instance(level);
15430 15432
15431 15433 if (!isinst)
15432 15434 r = scf_iter_service_pgs(iter, cur_svc);
15433 15435 else
15434 15436 r = scf_iter_instance_pgs(iter, cur_inst);
15435 15437 if (r != SCF_SUCCESS)
15436 15438 scfdie();
15437 15439
15438 15440 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15439 15441 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15440 15442 scfdie();
15441 15443
15442 15444 /* Skip nonpersistent pgs. */
15443 15445 if (flags & SCF_PG_FLAG_NONPERSISTENT)
15444 15446 continue;
15445 15447
15446 15448 if (scf_pg_delete(pg) != SCF_SUCCESS) {
15447 15449 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15448 15450 scfdie();
15449 15451
15450 15452 semerr(emsg_permission_denied);
15451 15453 goto out;
15452 15454 }
15453 15455 }
15454 15456 if (r == -1)
15455 15457 scfdie();
15456 15458
15457 15459 /* Copy the properties to the corresponding entity. */
15458 15460 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15459 15461 scfdie();
15460 15462
15461 15463 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15462 15464 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15463 15465 scfdie();
15464 15466
15465 15467 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15466 15468 0)
15467 15469 scfdie();
15468 15470
15469 15471 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15470 15472 scfdie();
15471 15473
15472 15474 if (!isinst)
15473 15475 r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15474 15476 flags, npg);
15475 15477 else
15476 15478 r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15477 15479 flags, npg);
15478 15480 if (r != SCF_SUCCESS) {
15479 15481 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15480 15482 scfdie();
15481 15483
15482 15484 semerr(emsg_permission_denied);
15483 15485 goto out;
15484 15486 }
15485 15487
15486 15488 if ((enabled == 0 || enabled == 1) &&
15487 15489 strcmp(nbuf, scf_pg_general) == 0)
15488 15490 r = pg_copy(pg, npg, enabled);
15489 15491 else
15490 15492 r = pg_copy(pg, npg, 2);
15491 15493
15492 15494 switch (r) {
15493 15495 case 0:
15494 15496 break;
15495 15497
15496 15498 case -1:
15497 15499 semerr(emsg_permission_denied);
15498 15500 goto out;
15499 15501
15500 15502 case -2:
15501 15503 semerr(gettext(
15502 15504 "Interrupted by another change.\n"));
15503 15505 goto out;
15504 15506
15505 15507 default:
15506 15508 abort();
15507 15509 }
15508 15510 }
15509 15511 if (r == -1)
15510 15512 scfdie();
15511 15513
15512 15514 /* Get next level. */
15513 15515 nlevel = scf_snaplevel_create(g_hndl);
15514 15516 if (nlevel == NULL)
15515 15517 scfdie();
15516 15518
15517 15519 if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15518 15520 SCF_SUCCESS) {
15519 15521 if (scf_error() != SCF_ERROR_NOT_FOUND)
15520 15522 scfdie();
15521 15523
15522 15524 scf_snaplevel_destroy(nlevel);
15523 15525 break;
15524 15526 }
15525 15527
15526 15528 scf_snaplevel_destroy(level);
15527 15529 level = nlevel;
15528 15530 }
15529 15531
15530 15532 if (snapname == NULL) {
15531 15533 lscf_selectsnap(NULL);
15532 15534 snap = NULL; /* cur_snap has been destroyed */
15533 15535 }
15534 15536
15535 15537 out:
15536 15538 free(tbuf);
15537 15539 free(nbuf);
15538 15540 scf_value_destroy(val);
15539 15541 scf_property_destroy(prop);
15540 15542 scf_pg_destroy(npg);
15541 15543 scf_pg_destroy(pg);
15542 15544 scf_iter_destroy(iter);
15543 15545 scf_snaplevel_destroy(level);
15544 15546 scf_snapshot_destroy(prev);
15545 15547 if (snap != cur_snap)
15546 15548 scf_snapshot_destroy(snap);
15547 15549 }
15548 15550
15549 15551 void
15550 15552 lscf_refresh(void)
15551 15553 {
15552 15554 ssize_t fmrilen;
15553 15555 size_t bufsz;
15554 15556 char *fmribuf;
15555 15557 int r;
15556 15558
15557 15559 lscf_prep_hndl();
15558 15560
15559 15561 if (cur_inst == NULL) {
15560 15562 semerr(gettext("Instance not selected.\n"));
15561 15563 return;
15562 15564 }
15563 15565
15564 15566 bufsz = max_scf_fmri_len + 1;
15565 15567 fmribuf = safe_malloc(bufsz);
15566 15568 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15567 15569 if (fmrilen < 0) {
15568 15570 free(fmribuf);
15569 15571 if (scf_error() != SCF_ERROR_DELETED)
15570 15572 scfdie();
15571 15573 scf_instance_destroy(cur_inst);
15572 15574 cur_inst = NULL;
15573 15575 warn(emsg_deleted);
15574 15576 return;
15575 15577 }
15576 15578 assert(fmrilen < bufsz);
15577 15579
15578 15580 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15579 15581 switch (r) {
15580 15582 case 0:
15581 15583 break;
15582 15584
15583 15585 case ECONNABORTED:
15584 15586 warn(gettext("Could not refresh %s "
15585 15587 "(repository connection broken).\n"), fmribuf);
15586 15588 break;
15587 15589
15588 15590 case ECANCELED:
15589 15591 warn(emsg_deleted);
15590 15592 break;
15591 15593
15592 15594 case EPERM:
15593 15595 warn(gettext("Could not refresh %s "
15594 15596 "(permission denied).\n"), fmribuf);
15595 15597 break;
15596 15598
15597 15599 case ENOSPC:
15598 15600 warn(gettext("Could not refresh %s "
15599 15601 "(repository server out of resources).\n"),
15600 15602 fmribuf);
15601 15603 break;
15602 15604
15603 15605 case EACCES:
15604 15606 default:
15605 15607 bad_error("refresh_entity", scf_error());
15606 15608 }
15607 15609
15608 15610 free(fmribuf);
15609 15611 }
15610 15612
15611 15613 /*
15612 15614 * describe [-v] [-t] [pg/prop]
15613 15615 */
15614 15616 int
15615 15617 lscf_describe(uu_list_t *args, int hasargs)
15616 15618 {
15617 15619 int ret = 0;
15618 15620 size_t i;
15619 15621 int argc;
15620 15622 char **argv = NULL;
15621 15623 string_list_t *slp;
15622 15624 int do_verbose = 0;
15623 15625 int do_templates = 0;
15624 15626 char *pattern = NULL;
15625 15627
15626 15628 lscf_prep_hndl();
15627 15629
15628 15630 if (hasargs != 0) {
15629 15631 argc = uu_list_numnodes(args);
15630 15632 if (argc < 1)
15631 15633 goto usage;
15632 15634
15633 15635 argv = calloc(argc + 1, sizeof (char *));
15634 15636 if (argv == NULL)
15635 15637 uu_die(gettext("Out of memory.\n"));
15636 15638
15637 15639 for (slp = uu_list_first(args), i = 0;
15638 15640 slp != NULL;
15639 15641 slp = uu_list_next(args, slp), ++i)
15640 15642 argv[i] = slp->str;
15641 15643
15642 15644 argv[i] = NULL;
15643 15645
15644 15646 /*
15645 15647 * We start optind = 0 because our list of arguments
15646 15648 * starts at argv[0]
15647 15649 */
15648 15650 optind = 0;
15649 15651 opterr = 0;
15650 15652 for (;;) {
15651 15653 ret = getopt(argc, argv, "vt");
15652 15654 if (ret == -1)
15653 15655 break;
15654 15656
15655 15657 switch (ret) {
15656 15658 case 'v':
15657 15659 do_verbose = 1;
15658 15660 break;
15659 15661
15660 15662 case 't':
15661 15663 do_templates = 1;
15662 15664 break;
15663 15665
15664 15666 case '?':
15665 15667 goto usage;
15666 15668
15667 15669 default:
15668 15670 bad_error("getopt", ret);
15669 15671 }
15670 15672 }
15671 15673
15672 15674 pattern = argv[optind];
15673 15675 }
15674 15676
15675 15677 if (cur_inst == NULL && cur_svc == NULL) {
15676 15678 semerr(emsg_entity_not_selected);
15677 15679 ret = -1;
15678 15680 goto out;
15679 15681 }
15680 15682
15681 15683 /*
15682 15684 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15683 15685 * output if their last parameter is set to 2. Less information is
15684 15686 * produced if the parameter is set to 1.
15685 15687 */
15686 15688 if (pattern == NULL) {
15687 15689 if (do_verbose == 1)
15688 15690 list_entity_tmpl(2);
15689 15691 else
15690 15692 list_entity_tmpl(1);
15691 15693 }
15692 15694
15693 15695 if (do_templates == 0) {
15694 15696 if (do_verbose == 1)
15695 15697 listprop(pattern, 0, 2);
15696 15698 else
15697 15699 listprop(pattern, 0, 1);
15698 15700 } else {
15699 15701 if (do_verbose == 1)
15700 15702 listtmpl(pattern, 2);
15701 15703 else
15702 15704 listtmpl(pattern, 1);
15703 15705 }
15704 15706
15705 15707 ret = 0;
15706 15708 out:
15707 15709 if (argv != NULL)
15708 15710 free(argv);
15709 15711 return (ret);
15710 15712 usage:
15711 15713 ret = -2;
15712 15714 goto out;
15713 15715 }
15714 15716
15715 15717 #define PARAM_ACTIVE ((const char *) "active")
15716 15718 #define PARAM_INACTIVE ((const char *) "inactive")
15717 15719 #define PARAM_SMTP_TO ((const char *) "to")
15718 15720
15719 15721 /*
15720 15722 * tokenize()
15721 15723 * Breaks down the string according to the tokens passed.
15722 15724 * Caller is responsible for freeing array of pointers returned.
15723 15725 * Returns NULL on failure
15724 15726 */
15725 15727 char **
15726 15728 tokenize(char *str, const char *sep)
15727 15729 {
15728 15730 char *token, *lasts;
15729 15731 char **buf;
15730 15732 int n = 0; /* number of elements */
15731 15733 int size = 8; /* size of the array (initial) */
15732 15734
15733 15735 buf = safe_malloc(size * sizeof (char *));
15734 15736
15735 15737 for (token = strtok_r(str, sep, &lasts); token != NULL;
15736 15738 token = strtok_r(NULL, sep, &lasts), ++n) {
15737 15739 if (n + 1 >= size) {
15738 15740 size *= 2;
15739 15741 if ((buf = realloc(buf, size * sizeof (char *))) ==
15740 15742 NULL) {
15741 15743 uu_die(gettext("Out of memory"));
15742 15744 }
15743 15745 }
15744 15746 buf[n] = token;
15745 15747 }
15746 15748 /* NULL terminate the pointer array */
15747 15749 buf[n] = NULL;
15748 15750
15749 15751 return (buf);
15750 15752 }
15751 15753
15752 15754 int32_t
15753 15755 check_tokens(char **p)
15754 15756 {
15755 15757 int32_t smf = 0;
15756 15758 int32_t fma = 0;
15757 15759
15758 15760 while (*p) {
15759 15761 int32_t t = string_to_tset(*p);
15760 15762
15761 15763 if (t == 0) {
15762 15764 if (is_fma_token(*p) == 0)
15763 15765 return (INVALID_TOKENS);
15764 15766 fma = 1; /* this token is an fma event */
15765 15767 } else {
15766 15768 smf |= t;
15767 15769 }
15768 15770
15769 15771 if (smf != 0 && fma == 1)
15770 15772 return (MIXED_TOKENS);
15771 15773 ++p;
15772 15774 }
15773 15775
15774 15776 if (smf > 0)
15775 15777 return (smf);
15776 15778 else if (fma == 1)
15777 15779 return (FMA_TOKENS);
15778 15780
15779 15781 return (INVALID_TOKENS);
15780 15782 }
15781 15783
15782 15784 static int
15783 15785 get_selection_str(char *fmri, size_t sz)
15784 15786 {
15785 15787 if (g_hndl == NULL) {
15786 15788 semerr(emsg_entity_not_selected);
15787 15789 return (-1);
15788 15790 } else if (cur_level != NULL) {
15789 15791 semerr(emsg_invalid_for_snapshot);
15790 15792 return (-1);
15791 15793 } else {
15792 15794 lscf_get_selection_str(fmri, sz);
15793 15795 }
15794 15796
15795 15797 return (0);
15796 15798 }
15797 15799
15798 15800 void
15799 15801 lscf_delnotify(const char *set, int global)
15800 15802 {
15801 15803 char *str = strdup(set);
15802 15804 char **pgs;
15803 15805 char **p;
15804 15806 int32_t tset;
15805 15807 char *fmri = NULL;
15806 15808
15807 15809 if (str == NULL)
15808 15810 uu_die(gettext("Out of memory.\n"));
15809 15811
15810 15812 pgs = tokenize(str, ",");
15811 15813
15812 15814 if ((tset = check_tokens(pgs)) > 0) {
15813 15815 size_t sz = max_scf_fmri_len + 1;
15814 15816
15815 15817 fmri = safe_malloc(sz);
15816 15818 if (global) {
15817 15819 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15818 15820 } else if (get_selection_str(fmri, sz) != 0) {
15819 15821 goto out;
15820 15822 }
15821 15823
15822 15824 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15823 15825 tset) != SCF_SUCCESS) {
15824 15826 uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15825 15827 scf_strerror(scf_error()));
15826 15828 }
15827 15829 } else if (tset == FMA_TOKENS) {
15828 15830 if (global) {
15829 15831 semerr(gettext("Can't use option '-g' with FMA event "
15830 15832 "definitions\n"));
15831 15833 goto out;
15832 15834 }
15833 15835
15834 15836 for (p = pgs; *p; ++p) {
15835 15837 if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15836 15838 SCF_SUCCESS) {
15837 15839 uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15838 15840 scf_strerror(scf_error()));
15839 15841 goto out;
15840 15842 }
15841 15843 }
15842 15844 } else if (tset == MIXED_TOKENS) {
15843 15845 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15844 15846 goto out;
15845 15847 } else {
15846 15848 uu_die(gettext("Invalid input.\n"));
15847 15849 }
15848 15850
15849 15851 out:
15850 15852 free(fmri);
15851 15853 free(pgs);
15852 15854 free(str);
15853 15855 }
15854 15856
15855 15857 void
15856 15858 lscf_listnotify(const char *set, int global)
15857 15859 {
15858 15860 char *str = safe_strdup(set);
15859 15861 char **pgs;
15860 15862 char **p;
15861 15863 int32_t tset;
15862 15864 nvlist_t *nvl;
15863 15865 char *fmri = NULL;
15864 15866
15865 15867 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15866 15868 uu_die(gettext("Out of memory.\n"));
15867 15869
15868 15870 pgs = tokenize(str, ",");
15869 15871
15870 15872 if ((tset = check_tokens(pgs)) > 0) {
15871 15873 size_t sz = max_scf_fmri_len + 1;
15872 15874
15873 15875 fmri = safe_malloc(sz);
15874 15876 if (global) {
15875 15877 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15876 15878 } else if (get_selection_str(fmri, sz) != 0) {
15877 15879 goto out;
15878 15880 }
15879 15881
15880 15882 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15881 15883 SCF_SUCCESS) {
15882 15884 if (scf_error() != SCF_ERROR_NOT_FOUND &&
15883 15885 scf_error() != SCF_ERROR_DELETED)
15884 15886 uu_warn(gettext(
15885 15887 "Failed listnotify: %s\n"),
15886 15888 scf_strerror(scf_error()));
15887 15889 goto out;
15888 15890 }
15889 15891
15890 15892 listnotify_print(nvl, NULL);
15891 15893 } else if (tset == FMA_TOKENS) {
15892 15894 if (global) {
15893 15895 semerr(gettext("Can't use option '-g' with FMA event "
15894 15896 "definitions\n"));
15895 15897 goto out;
15896 15898 }
15897 15899
15898 15900 for (p = pgs; *p; ++p) {
15899 15901 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15900 15902 SCF_SUCCESS) {
15901 15903 /*
15902 15904 * if the preferences have just been deleted
15903 15905 * or does not exist, just skip.
15904 15906 */
15905 15907 if (scf_error() == SCF_ERROR_NOT_FOUND ||
15906 15908 scf_error() == SCF_ERROR_DELETED)
15907 15909 continue;
15908 15910 uu_warn(gettext(
15909 15911 "Failed listnotify: %s\n"),
15910 15912 scf_strerror(scf_error()));
15911 15913 goto out;
15912 15914 }
15913 15915 listnotify_print(nvl, re_tag(*p));
15914 15916 }
15915 15917 } else if (tset == MIXED_TOKENS) {
15916 15918 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15917 15919 goto out;
15918 15920 } else {
15919 15921 semerr(gettext("Invalid input.\n"));
15920 15922 }
15921 15923
15922 15924 out:
15923 15925 nvlist_free(nvl);
15924 15926 free(fmri);
15925 15927 free(pgs);
15926 15928 free(str);
15927 15929 }
15928 15930
15929 15931 static char *
15930 15932 strip_quotes_and_blanks(char *s)
15931 15933 {
15932 15934 char *start = s;
15933 15935 char *end = strrchr(s, '\"');
15934 15936
15935 15937 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15936 15938 start = s + 1;
15937 15939 while (isblank(*start))
15938 15940 start++;
15939 15941 while (isblank(*(end - 1)) && end > start) {
15940 15942 end--;
15941 15943 }
15942 15944 *end = '\0';
15943 15945 }
15944 15946
15945 15947 return (start);
15946 15948 }
15947 15949
15948 15950 static int
15949 15951 set_active(nvlist_t *mech, const char *hier_part)
15950 15952 {
15951 15953 boolean_t b;
15952 15954
15953 15955 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15954 15956 b = B_TRUE;
15955 15957 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15956 15958 b = B_FALSE;
15957 15959 } else {
15958 15960 return (-1);
15959 15961 }
15960 15962
15961 15963 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15962 15964 uu_die(gettext("Out of memory.\n"));
15963 15965
15964 15966 return (0);
15965 15967 }
15966 15968
15967 15969 static int
15968 15970 add_snmp_params(nvlist_t *mech, char *hier_part)
15969 15971 {
15970 15972 return (set_active(mech, hier_part));
15971 15973 }
15972 15974
15973 15975 static int
15974 15976 add_syslog_params(nvlist_t *mech, char *hier_part)
15975 15977 {
15976 15978 return (set_active(mech, hier_part));
15977 15979 }
15978 15980
15979 15981 /*
15980 15982 * add_mailto_paramas()
15981 15983 * parse the hier_part of mailto URI
15982 15984 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15983 15985 * or mailto:{[active]|inactive}
15984 15986 */
15985 15987 static int
15986 15988 add_mailto_params(nvlist_t *mech, char *hier_part)
15987 15989 {
15988 15990 const char *tok = "?&";
15989 15991 char *p;
15990 15992 char *lasts;
15991 15993 char *param;
15992 15994 char *val;
15993 15995
15994 15996 /*
15995 15997 * If the notification parametes are in the form of
15996 15998 *
15997 15999 * malito:{[active]|inactive}
15998 16000 *
15999 16001 * we set the property accordingly and return.
16000 16002 * Otherwise, we make the notification type active and
16001 16003 * process the hier_part.
16002 16004 */
16003 16005 if (set_active(mech, hier_part) == 0)
16004 16006 return (0);
16005 16007 else if (set_active(mech, PARAM_ACTIVE) != 0)
16006 16008 return (-1);
16007 16009
16008 16010 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
16009 16011 /*
16010 16012 * sanity check: we only get here if hier_part = "", but
16011 16013 * that's handled by set_active
16012 16014 */
16013 16015 uu_die("strtok_r");
16014 16016 }
16015 16017
16016 16018 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
16017 16019 uu_die(gettext("Out of memory.\n"));
16018 16020
16019 16021 while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16020 16022 if ((param = strtok_r(p, "=", &val)) != NULL)
16021 16023 if (nvlist_add_string(mech, param, val) != 0)
16022 16024 uu_die(gettext("Out of memory.\n"));
16023 16025
16024 16026 return (0);
16025 16027 }
16026 16028
16027 16029 static int
16028 16030 uri_split(char *uri, char **scheme, char **hier_part)
16029 16031 {
16030 16032 int r = -1;
16031 16033
16032 16034 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16033 16035 *hier_part == NULL) {
16034 16036 semerr(gettext("'%s' is not an URI\n"), uri);
16035 16037 return (r);
16036 16038 }
16037 16039
16038 16040 if ((r = check_uri_scheme(*scheme)) < 0) {
16039 16041 semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16040 16042 return (r);
16041 16043 }
16042 16044
16043 16045 return (r);
16044 16046 }
16045 16047
16046 16048 static int
16047 16049 process_uri(nvlist_t *params, char *uri)
16048 16050 {
16049 16051 char *scheme;
16050 16052 char *hier_part;
16051 16053 nvlist_t *mech;
16052 16054 int index;
16053 16055 int r;
16054 16056
16055 16057 if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16056 16058 return (-1);
16057 16059
16058 16060 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16059 16061 uu_die(gettext("Out of memory.\n"));
16060 16062
16061 16063 switch (index) {
16062 16064 case 0:
16063 16065 /* error messages displayed by called function */
16064 16066 r = add_mailto_params(mech, hier_part);
16065 16067 break;
16066 16068
16067 16069 case 1:
16068 16070 if ((r = add_snmp_params(mech, hier_part)) != 0)
16069 16071 semerr(gettext("Not valid parameters: '%s'\n"),
16070 16072 hier_part);
16071 16073 break;
16072 16074
16073 16075 case 2:
16074 16076 if ((r = add_syslog_params(mech, hier_part)) != 0)
16075 16077 semerr(gettext("Not valid parameters: '%s'\n"),
16076 16078 hier_part);
16077 16079 break;
16078 16080
16079 16081 default:
16080 16082 r = -1;
16081 16083 }
16082 16084
16083 16085 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16084 16086 mech) != 0)
16085 16087 uu_die(gettext("Out of memory.\n"));
16086 16088
16087 16089 nvlist_free(mech);
16088 16090 return (r);
16089 16091 }
16090 16092
16091 16093 static int
16092 16094 set_params(nvlist_t *params, char **p)
16093 16095 {
16094 16096 char *uri;
16095 16097
16096 16098 if (p == NULL)
16097 16099 /* sanity check */
16098 16100 uu_die("set_params");
16099 16101
16100 16102 while (*p) {
16101 16103 uri = strip_quotes_and_blanks(*p);
16102 16104 if (process_uri(params, uri) != 0)
16103 16105 return (-1);
16104 16106
16105 16107 ++p;
16106 16108 }
16107 16109
16108 16110 return (0);
16109 16111 }
16110 16112
16111 16113 static int
16112 16114 setnotify(const char *e, char **p, int global)
16113 16115 {
16114 16116 char *str = safe_strdup(e);
16115 16117 char **events;
16116 16118 int32_t tset;
16117 16119 int r = -1;
16118 16120 nvlist_t *nvl, *params;
16119 16121 char *fmri = NULL;
16120 16122
16121 16123 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16122 16124 nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 ||
16123 16125 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16124 16126 SCF_NOTIFY_PARAMS_VERSION) != 0)
16125 16127 uu_die(gettext("Out of memory.\n"));
16126 16128
16127 16129 events = tokenize(str, ",");
16128 16130
16129 16131 if ((tset = check_tokens(events)) > 0) {
16130 16132 /* SMF state transitions parameters */
16131 16133 size_t sz = max_scf_fmri_len + 1;
16132 16134
16133 16135 fmri = safe_malloc(sz);
16134 16136 if (global) {
16135 16137 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16136 16138 } else if (get_selection_str(fmri, sz) != 0) {
16137 16139 goto out;
16138 16140 }
16139 16141
16140 16142 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16141 16143 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16142 16144 uu_die(gettext("Out of memory.\n"));
16143 16145
16144 16146 if ((r = set_params(params, p)) == 0) {
16145 16147 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16146 16148 params) != 0)
16147 16149 uu_die(gettext("Out of memory.\n"));
16148 16150
16149 16151 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16150 16152 nvl) != SCF_SUCCESS) {
16151 16153 r = -1;
16152 16154 uu_warn(gettext(
16153 16155 "Failed smf_notify_set_params(3SCF): %s\n"),
16154 16156 scf_strerror(scf_error()));
16155 16157 }
16156 16158 }
16157 16159 } else if (tset == FMA_TOKENS) {
16158 16160 /* FMA event parameters */
16159 16161 if (global) {
16160 16162 semerr(gettext("Can't use option '-g' with FMA event "
16161 16163 "definitions\n"));
16162 16164 goto out;
16163 16165 }
16164 16166
16165 16167 if ((r = set_params(params, p)) != 0)
16166 16168 goto out;
16167 16169
16168 16170 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16169 16171 uu_die(gettext("Out of memory.\n"));
16170 16172
16171 16173 while (*events) {
16172 16174 if (smf_notify_set_params(de_tag(*events), nvl) !=
16173 16175 SCF_SUCCESS)
16174 16176 uu_warn(gettext(
16175 16177 "Failed smf_notify_set_params(3SCF) for "
16176 16178 "event %s: %s\n"), *events,
16177 16179 scf_strerror(scf_error()));
16178 16180 events++;
16179 16181 }
16180 16182 } else if (tset == MIXED_TOKENS) {
16181 16183 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16182 16184 } else {
16183 16185 /* Sanity check */
16184 16186 uu_die(gettext("Invalid input.\n"));
16185 16187 }
16186 16188
16187 16189 out:
16188 16190 nvlist_free(nvl);
16189 16191 nvlist_free(params);
16190 16192 free(fmri);
16191 16193 free(str);
16192 16194
16193 16195 return (r);
16194 16196 }
16195 16197
16196 16198 int
16197 16199 lscf_setnotify(uu_list_t *args)
16198 16200 {
16199 16201 int argc;
16200 16202 char **argv = NULL;
16201 16203 string_list_t *slp;
16202 16204 int global;
16203 16205 char *events;
16204 16206 char **p;
16205 16207 int i;
16206 16208 int ret;
16207 16209
16208 16210 if ((argc = uu_list_numnodes(args)) < 2)
16209 16211 goto usage;
16210 16212
16211 16213 argv = calloc(argc + 1, sizeof (char *));
16212 16214 if (argv == NULL)
16213 16215 uu_die(gettext("Out of memory.\n"));
16214 16216
16215 16217 for (slp = uu_list_first(args), i = 0;
16216 16218 slp != NULL;
16217 16219 slp = uu_list_next(args, slp), ++i)
16218 16220 argv[i] = slp->str;
16219 16221
16220 16222 argv[i] = NULL;
16221 16223
16222 16224 if (strcmp(argv[0], "-g") == 0) {
16223 16225 global = 1;
16224 16226 events = argv[1];
16225 16227 p = argv + 2;
16226 16228 } else {
16227 16229 global = 0;
16228 16230 events = argv[0];
16229 16231 p = argv + 1;
16230 16232 }
16231 16233
16232 16234 ret = setnotify(events, p, global);
16233 16235
16234 16236 out:
16235 16237 free(argv);
16236 16238 return (ret);
16237 16239
16238 16240 usage:
16239 16241 ret = -2;
16240 16242 goto out;
16241 16243 }
16242 16244
16243 16245 /*
16244 16246 * Creates a list of instance name strings associated with a service. If
16245 16247 * wohandcrafted flag is set, get only instances that have a last-import
16246 16248 * snapshot, instances that were imported via svccfg.
16247 16249 */
16248 16250 static uu_list_t *
16249 16251 create_instance_list(scf_service_t *svc, int wohandcrafted)
16250 16252 {
16251 16253 scf_snapshot_t *snap = NULL;
16252 16254 scf_instance_t *inst;
16253 16255 scf_iter_t *inst_iter;
16254 16256 uu_list_t *instances;
16255 16257 char *instname;
16256 16258 int r;
16257 16259
16258 16260 inst_iter = scf_iter_create(g_hndl);
16259 16261 inst = scf_instance_create(g_hndl);
16260 16262 if (inst_iter == NULL || inst == NULL) {
16261 16263 uu_warn(gettext("Could not create instance or iterator\n"));
16262 16264 scfdie();
16263 16265 }
16264 16266
16265 16267 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16266 16268 return (instances);
16267 16269
16268 16270 if (scf_iter_service_instances(inst_iter, svc) != 0) {
16269 16271 switch (scf_error()) {
16270 16272 case SCF_ERROR_CONNECTION_BROKEN:
16271 16273 case SCF_ERROR_DELETED:
16272 16274 uu_list_destroy(instances);
16273 16275 instances = NULL;
16274 16276 goto out;
16275 16277
16276 16278 case SCF_ERROR_HANDLE_MISMATCH:
16277 16279 case SCF_ERROR_NOT_BOUND:
16278 16280 case SCF_ERROR_NOT_SET:
16279 16281 default:
16280 16282 bad_error("scf_iter_service_instances", scf_error());
16281 16283 }
16282 16284 }
16283 16285
16284 16286 instname = safe_malloc(max_scf_name_len + 1);
16285 16287 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16286 16288 if (r == -1) {
16287 16289 (void) uu_warn(gettext("Unable to iterate through "
16288 16290 "instances to create instance list : %s\n"),
16289 16291 scf_strerror(scf_error()));
16290 16292
16291 16293 uu_list_destroy(instances);
16292 16294 instances = NULL;
16293 16295 goto out;
16294 16296 }
16295 16297
16296 16298 /*
16297 16299 * If the instance does not have a last-import snapshot
16298 16300 * then do not add it to the list as it is a hand-crafted
16299 16301 * instance that should not be managed.
16300 16302 */
16301 16303 if (wohandcrafted) {
16302 16304 if (snap == NULL &&
16303 16305 (snap = scf_snapshot_create(g_hndl)) == NULL) {
16304 16306 uu_warn(gettext("Unable to create snapshot "
16305 16307 "entity\n"));
16306 16308 scfdie();
16307 16309 }
16308 16310
16309 16311 if (scf_instance_get_snapshot(inst,
16310 16312 snap_lastimport, snap) != 0) {
16311 16313 switch (scf_error()) {
16312 16314 case SCF_ERROR_NOT_FOUND :
16313 16315 case SCF_ERROR_DELETED:
16314 16316 continue;
16315 16317
16316 16318 case SCF_ERROR_CONNECTION_BROKEN:
16317 16319 uu_list_destroy(instances);
16318 16320 instances = NULL;
16319 16321 goto out;
16320 16322
16321 16323 case SCF_ERROR_HANDLE_MISMATCH:
16322 16324 case SCF_ERROR_NOT_BOUND:
16323 16325 case SCF_ERROR_NOT_SET:
16324 16326 default:
16325 16327 bad_error("scf_iter_service_instances",
16326 16328 scf_error());
16327 16329 }
16328 16330 }
16329 16331 }
16330 16332
16331 16333 if (scf_instance_get_name(inst, instname,
16332 16334 max_scf_name_len + 1) < 0) {
16333 16335 switch (scf_error()) {
16334 16336 case SCF_ERROR_NOT_FOUND :
16335 16337 continue;
16336 16338
16337 16339 case SCF_ERROR_CONNECTION_BROKEN:
16338 16340 case SCF_ERROR_DELETED:
16339 16341 uu_list_destroy(instances);
16340 16342 instances = NULL;
16341 16343 goto out;
16342 16344
16343 16345 case SCF_ERROR_HANDLE_MISMATCH:
16344 16346 case SCF_ERROR_NOT_BOUND:
16345 16347 case SCF_ERROR_NOT_SET:
16346 16348 default:
16347 16349 bad_error("scf_iter_service_instances",
16348 16350 scf_error());
16349 16351 }
16350 16352 }
16351 16353
16352 16354 add_string(instances, instname);
16353 16355 }
16354 16356
16355 16357 out:
16356 16358 if (snap)
16357 16359 scf_snapshot_destroy(snap);
16358 16360
16359 16361 scf_instance_destroy(inst);
16360 16362 scf_iter_destroy(inst_iter);
16361 16363 free(instname);
16362 16364 return (instances);
16363 16365 }
16364 16366
16365 16367 /*
16366 16368 * disable an instance but wait for the instance to
16367 16369 * move out of the running state.
16368 16370 *
16369 16371 * Returns 0 : if the instance did not disable
16370 16372 * Returns non-zero : if the instance disabled.
16371 16373 *
16372 16374 */
16373 16375 static int
16374 16376 disable_instance(scf_instance_t *instance)
16375 16377 {
16376 16378 char *fmribuf;
16377 16379 int enabled = 10000;
16378 16380
16379 16381 if (inst_is_running(instance)) {
16380 16382 fmribuf = safe_malloc(max_scf_name_len + 1);
16381 16383 if (scf_instance_to_fmri(instance, fmribuf,
16382 16384 max_scf_name_len + 1) < 0) {
16383 16385 free(fmribuf);
16384 16386 return (0);
16385 16387 }
16386 16388
16387 16389 /*
16388 16390 * If the instance cannot be disabled then return
16389 16391 * failure to disable and let the caller decide
16390 16392 * if that is of importance.
16391 16393 */
16392 16394 if (smf_disable_instance(fmribuf, 0) != 0) {
16393 16395 free(fmribuf);
16394 16396 return (0);
16395 16397 }
16396 16398
16397 16399 while (enabled) {
16398 16400 if (!inst_is_running(instance))
16399 16401 break;
16400 16402
16401 16403 (void) poll(NULL, 0, 5);
16402 16404 enabled = enabled - 5;
16403 16405 }
16404 16406
16405 16407 free(fmribuf);
16406 16408 }
16407 16409
16408 16410 return (enabled);
16409 16411 }
16410 16412
16411 16413 /*
16412 16414 * Function to compare two service_manifest structures.
16413 16415 */
16414 16416 /* ARGSUSED2 */
16415 16417 static int
16416 16418 service_manifest_compare(const void *left, const void *right, void *unused)
16417 16419 {
16418 16420 service_manifest_t *l = (service_manifest_t *)left;
16419 16421 service_manifest_t *r = (service_manifest_t *)right;
16420 16422 int rc;
16421 16423
16422 16424 rc = strcmp(l->servicename, r->servicename);
16423 16425
16424 16426 return (rc);
16425 16427 }
16426 16428
16427 16429 /*
16428 16430 * Look for the provided service in the service to manifest
16429 16431 * tree. If the service exists, and a manifest was provided
16430 16432 * then add the manifest to that service. If the service
16431 16433 * does not exist, then add the service and manifest to the
16432 16434 * list.
16433 16435 *
16434 16436 * If the manifest is NULL, return the element if found. If
16435 16437 * the service is not found return NULL.
16436 16438 */
16437 16439 service_manifest_t *
16438 16440 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16439 16441 {
16440 16442 service_manifest_t elem;
16441 16443 service_manifest_t *fnelem;
16442 16444 uu_avl_index_t marker;
16443 16445
16444 16446 elem.servicename = svnbuf;
16445 16447 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16446 16448
16447 16449 if (mfst) {
16448 16450 if (fnelem) {
16449 16451 add_string(fnelem->mfstlist, strdup(mfst));
16450 16452 } else {
16451 16453 fnelem = safe_malloc(sizeof (*fnelem));
16452 16454 fnelem->servicename = safe_strdup(svnbuf);
16453 16455 if ((fnelem->mfstlist =
16454 16456 uu_list_create(string_pool, NULL, 0)) == NULL)
16455 16457 uu_die(gettext("Could not create property "
16456 16458 "list: %s\n"), uu_strerror(uu_error()));
16457 16459
16458 16460 add_string(fnelem->mfstlist, safe_strdup(mfst));
16459 16461
16460 16462 uu_avl_insert(service_manifest_tree, fnelem, marker);
16461 16463 }
16462 16464 }
16463 16465
16464 16466 return (fnelem);
16465 16467 }
16466 16468
16467 16469 /*
16468 16470 * Create the service to manifest avl tree.
16469 16471 *
16470 16472 * Walk each of the manifests currently installed in the supported
16471 16473 * directories, /lib/svc/manifests and /var/svc/manifests. For
16472 16474 * each of the manifests, inventory the services and add them to
16473 16475 * the tree.
16474 16476 *
16475 16477 * Code that calls this function should make sure fileystem/minimal is online,
16476 16478 * /var is available, since this function walks the /var/svc/manifest directory.
16477 16479 */
16478 16480 static void
16479 16481 create_manifest_tree(void)
16480 16482 {
16481 16483 manifest_info_t **entry;
16482 16484 manifest_info_t **manifests;
16483 16485 uu_list_walk_t *svcs;
16484 16486 bundle_t *b;
16485 16487 entity_t *mfsvc;
16486 16488 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16487 16489 int c, status;
16488 16490
16489 16491 if (service_manifest_pool)
16490 16492 return;
16491 16493
16492 16494 /*
16493 16495 * Create the list pool for the service manifest list
16494 16496 */
16495 16497 service_manifest_pool = uu_avl_pool_create("service_manifest",
16496 16498 sizeof (service_manifest_t),
16497 16499 offsetof(service_manifest_t, svcmfst_node),
16498 16500 service_manifest_compare, UU_DEFAULT);
16499 16501 if (service_manifest_pool == NULL)
16500 16502 uu_die(gettext("service_manifest pool creation failed: %s\n"),
16501 16503 uu_strerror(uu_error()));
16502 16504
16503 16505 /*
16504 16506 * Create the list
16505 16507 */
16506 16508 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16507 16509 UU_DEFAULT);
16508 16510 if (service_manifest_tree == NULL)
16509 16511 uu_die(gettext("service_manifest tree creation failed: %s\n"),
16510 16512 uu_strerror(uu_error()));
16511 16513
16512 16514 /*
16513 16515 * Walk the manifests adding the service(s) from each manifest.
16514 16516 *
16515 16517 * If a service already exists add the manifest to the manifest
16516 16518 * list for that service. This covers the case of a service that
16517 16519 * is supported by multiple manifest files.
16518 16520 */
16519 16521 for (c = 0; dirs[c]; c++) {
16520 16522 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16521 16523 if (status < 0) {
16522 16524 uu_warn(gettext("file tree walk of %s encountered "
16523 16525 "error %s\n"), dirs[c], strerror(errno));
16524 16526
16525 16527 uu_avl_destroy(service_manifest_tree);
16526 16528 service_manifest_tree = NULL;
16527 16529 return;
16528 16530 }
16529 16531
16530 16532 /*
16531 16533 * If a manifest that was in the list is not found
16532 16534 * then skip and go to the next manifest file.
16533 16535 */
16534 16536 if (manifests != NULL) {
16535 16537 for (entry = manifests; *entry != NULL; entry++) {
16536 16538 b = internal_bundle_new();
16537 16539 if (lxml_get_bundle_file(b, (*entry)->mi_path,
16538 16540 SVCCFG_OP_IMPORT) != 0) {
16539 16541 internal_bundle_free(b);
16540 16542 continue;
16541 16543 }
16542 16544
16543 16545 svcs = uu_list_walk_start(b->sc_bundle_services,
16544 16546 0);
16545 16547 if (svcs == NULL) {
16546 16548 internal_bundle_free(b);
16547 16549 continue;
16548 16550 }
16549 16551
16550 16552 while ((mfsvc = uu_list_walk_next(svcs)) !=
16551 16553 NULL) {
16552 16554 /* Add manifest to service */
16553 16555 (void) find_add_svc_mfst(mfsvc->sc_name,
16554 16556 (*entry)->mi_path);
16555 16557 }
16556 16558
16557 16559 uu_list_walk_end(svcs);
16558 16560 internal_bundle_free(b);
16559 16561 }
16560 16562
16561 16563 free_manifest_array(manifests);
16562 16564 }
16563 16565 }
16564 16566 }
16565 16567
16566 16568 /*
16567 16569 * Check the manifest history file to see
16568 16570 * if the service was ever installed from
16569 16571 * one of the supported directories.
16570 16572 *
16571 16573 * Return Values :
16572 16574 * -1 - if there's error reading manifest history file
16573 16575 * 1 - if the service is not found
16574 16576 * 0 - if the service is found
16575 16577 */
16576 16578 static int
16577 16579 check_mfst_history(const char *svcname)
16578 16580 {
16579 16581 struct stat st;
16580 16582 caddr_t mfsthist_start;
16581 16583 char *svnbuf;
16582 16584 int fd;
16583 16585 int r = 1;
16584 16586
16585 16587 fd = open(MFSTHISTFILE, O_RDONLY);
16586 16588 if (fd == -1) {
16587 16589 uu_warn(gettext("Unable to open the history file\n"));
16588 16590 return (-1);
16589 16591 }
16590 16592
16591 16593 if (fstat(fd, &st) == -1) {
16592 16594 uu_warn(gettext("Unable to stat the history file\n"));
16593 16595 return (-1);
16594 16596 }
16595 16597
16596 16598 mfsthist_start = mmap(0, st.st_size, PROT_READ,
16597 16599 MAP_PRIVATE, fd, 0);
16598 16600
16599 16601 (void) close(fd);
16600 16602 if (mfsthist_start == MAP_FAILED ||
16601 16603 *(mfsthist_start + st.st_size) != '\0') {
16602 16604 (void) munmap(mfsthist_start, st.st_size);
16603 16605 return (-1);
16604 16606 }
16605 16607
16606 16608 /*
16607 16609 * The manifest history file is a space delimited list
16608 16610 * of service and instance to manifest linkage. Adding
16609 16611 * a space to the end of the service name so to get only
16610 16612 * the service that is being searched for.
16611 16613 */
16612 16614 svnbuf = uu_msprintf("%s ", svcname);
16613 16615 if (svnbuf == NULL)
16614 16616 uu_die(gettext("Out of memory"));
16615 16617
16616 16618 if (strstr(mfsthist_start, svnbuf) != NULL)
16617 16619 r = 0;
16618 16620
16619 16621 (void) munmap(mfsthist_start, st.st_size);
16620 16622 uu_free(svnbuf);
16621 16623 return (r);
16622 16624 }
16623 16625
16624 16626 /*
16625 16627 * Take down each of the instances in the service
16626 16628 * and remove them, then delete the service.
16627 16629 */
16628 16630 static void
16629 16631 teardown_service(scf_service_t *svc, const char *svnbuf)
16630 16632 {
16631 16633 scf_instance_t *instance;
16632 16634 scf_iter_t *iter;
16633 16635 int r;
16634 16636
16635 16637 safe_printf(gettext("Delete service %s as there are no "
16636 16638 "supporting manifests\n"), svnbuf);
16637 16639
16638 16640 instance = scf_instance_create(g_hndl);
16639 16641 iter = scf_iter_create(g_hndl);
16640 16642 if (iter == NULL || instance == NULL) {
16641 16643 uu_warn(gettext("Unable to create supporting entities to "
16642 16644 "teardown the service\n"));
16643 16645 uu_warn(gettext("scf error is : %s\n"),
16644 16646 scf_strerror(scf_error()));
16645 16647 scfdie();
16646 16648 }
16647 16649
16648 16650 if (scf_iter_service_instances(iter, svc) != 0) {
16649 16651 switch (scf_error()) {
16650 16652 case SCF_ERROR_CONNECTION_BROKEN:
16651 16653 case SCF_ERROR_DELETED:
16652 16654 goto out;
16653 16655
16654 16656 case SCF_ERROR_HANDLE_MISMATCH:
16655 16657 case SCF_ERROR_NOT_BOUND:
16656 16658 case SCF_ERROR_NOT_SET:
16657 16659 default:
16658 16660 bad_error("scf_iter_service_instances",
16659 16661 scf_error());
16660 16662 }
16661 16663 }
16662 16664
16663 16665 while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16664 16666 if (r == -1) {
16665 16667 uu_warn(gettext("Error - %s\n"),
16666 16668 scf_strerror(scf_error()));
16667 16669 goto out;
16668 16670 }
16669 16671
16670 16672 (void) disable_instance(instance);
16671 16673 }
16672 16674
16673 16675 /*
16674 16676 * Delete the service... forcing the deletion in case
16675 16677 * any of the instances did not disable.
16676 16678 */
16677 16679 (void) lscf_service_delete(svc, 1);
16678 16680 out:
16679 16681 scf_instance_destroy(instance);
16680 16682 scf_iter_destroy(iter);
16681 16683 }
16682 16684
16683 16685 /*
16684 16686 * Get the list of instances supported by the manifest
16685 16687 * file.
16686 16688 *
16687 16689 * Return 0 if there are no instances.
16688 16690 *
16689 16691 * Return -1 if there are errors attempting to collect instances.
16690 16692 *
16691 16693 * Return the count of instances found if there are no errors.
16692 16694 *
16693 16695 */
16694 16696 static int
16695 16697 check_instance_support(char *mfstfile, const char *svcname,
16696 16698 uu_list_t *instances)
16697 16699 {
16698 16700 uu_list_walk_t *svcs, *insts;
16699 16701 uu_list_t *ilist;
16700 16702 bundle_t *b;
16701 16703 entity_t *mfsvc, *mfinst;
16702 16704 const char *svcn;
16703 16705 int rminstcnt = 0;
16704 16706
16705 16707
16706 16708 b = internal_bundle_new();
16707 16709
16708 16710 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16709 16711 /*
16710 16712 * Unable to process the manifest file for
16711 16713 * instance support, so just return as
16712 16714 * don't want to remove instances that could
16713 16715 * not be accounted for that might exist here.
16714 16716 */
16715 16717 internal_bundle_free(b);
16716 16718 return (0);
16717 16719 }
16718 16720
16719 16721 svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16720 16722 if (svcs == NULL) {
16721 16723 internal_bundle_free(b);
16722 16724 return (0);
16723 16725 }
16724 16726
16725 16727 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16726 16728 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16727 16729
16728 16730 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16729 16731 if (strcmp(mfsvc->sc_name, svcn) == 0)
16730 16732 break;
16731 16733 }
16732 16734 uu_list_walk_end(svcs);
16733 16735
16734 16736 if (mfsvc == NULL) {
16735 16737 internal_bundle_free(b);
16736 16738 return (-1);
16737 16739 }
16738 16740
16739 16741 ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16740 16742 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16741 16743 internal_bundle_free(b);
16742 16744 return (0);
16743 16745 }
16744 16746
16745 16747 while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16746 16748 /*
16747 16749 * Remove the instance from the instances list.
16748 16750 * The unaccounted for instances will be removed
16749 16751 * from the service once all manifests are
16750 16752 * processed.
16751 16753 */
16752 16754 (void) remove_string(instances,
16753 16755 mfinst->sc_name);
16754 16756 rminstcnt++;
16755 16757 }
16756 16758
16757 16759 uu_list_walk_end(insts);
16758 16760 internal_bundle_free(b);
16759 16761
16760 16762 return (rminstcnt);
16761 16763 }
16762 16764
16763 16765 /*
16764 16766 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16765 16767 * 'false' to indicate there's no manifest file(s) found for the service.
16766 16768 */
16767 16769 static void
16768 16770 svc_add_no_support(scf_service_t *svc)
16769 16771 {
16770 16772 char *pname;
16771 16773
16772 16774 /* Add no support */
16773 16775 cur_svc = svc;
16774 16776 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16775 16777 return;
16776 16778
16777 16779 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16778 16780 if (pname == NULL)
16779 16781 uu_die(gettext("Out of memory.\n"));
16780 16782
16781 16783 (void) lscf_addpropvalue(pname, "boolean:", "0");
16782 16784
16783 16785 uu_free(pname);
16784 16786 cur_svc = NULL;
16785 16787 }
16786 16788
16787 16789 /*
16788 16790 * This function handles all upgrade scenarios for a service that doesn't have
16789 16791 * SCF_PG_MANIFESTFILES pg. The function creates and populates
16790 16792 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16791 16793 * manifest(s) mapping. Manifests under supported directories are inventoried
16792 16794 * and a property is added for each file that delivers configuration to the
16793 16795 * service. A service that has no corresponding manifest files (deleted) are
16794 16796 * removed from repository.
16795 16797 *
16796 16798 * Unsupported services:
16797 16799 *
16798 16800 * A service is considered unsupported if there is no corresponding manifest
16799 16801 * in the supported directories for that service and the service isn't in the
16800 16802 * history file list. The history file, MFSTHISTFILE, contains a list of all
16801 16803 * services and instances that were delivered by Solaris before the introduction
16802 16804 * of the SCF_PG_MANIFESTFILES property group. The history file also contains
16803 16805 * the path to the manifest file that defined the service or instance.
16804 16806 *
16805 16807 * Another type of unsupported services is 'handcrafted' services,
16806 16808 * programmatically created services or services created by dependent entries
16807 16809 * in other manifests. A handcrafted service is identified by its lack of any
16808 16810 * instance containing last-import snapshot which is created during svccfg
16809 16811 * import.
16810 16812 *
16811 16813 * This function sets a flag for unsupported services by setting services'
16812 16814 * SCF_PG_MANIFESTFILES/support property to false.
16813 16815 */
16814 16816 static void
16815 16817 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16816 16818 {
16817 16819 service_manifest_t *elem;
16818 16820 uu_list_walk_t *mfwalk;
16819 16821 string_list_t *mfile;
16820 16822 uu_list_t *instances;
16821 16823 const char *sname;
16822 16824 char *pname;
16823 16825 int r;
16824 16826
16825 16827 /*
16826 16828 * Since there's no guarantee manifests under /var are available during
16827 16829 * early import, don't perform any upgrade during early import.
16828 16830 */
16829 16831 if (IGNORE_VAR)
16830 16832 return;
16831 16833
16832 16834 if (service_manifest_tree == NULL) {
16833 16835 create_manifest_tree();
16834 16836 }
16835 16837
16836 16838 /*
16837 16839 * Find service's supporting manifest(s) after
16838 16840 * stripping off the svc:/ prefix that is part
16839 16841 * of the fmri that is not used in the service
16840 16842 * manifest bundle list.
16841 16843 */
16842 16844 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16843 16845 strlen(SCF_FMRI_SERVICE_PREFIX);
16844 16846 elem = find_add_svc_mfst(sname, NULL);
16845 16847 if (elem == NULL) {
16846 16848
16847 16849 /*
16848 16850 * A handcrafted service, one that has no instance containing
16849 16851 * last-import snapshot, should get unsupported flag.
16850 16852 */
16851 16853 instances = create_instance_list(svc, 1);
16852 16854 if (instances == NULL) {
16853 16855 uu_warn(gettext("Unable to create instance list %s\n"),
16854 16856 svcname);
16855 16857 return;
16856 16858 }
16857 16859
16858 16860 if (uu_list_numnodes(instances) == 0) {
16859 16861 svc_add_no_support(svc);
16860 16862 return;
16861 16863 }
16862 16864
16863 16865 /*
16864 16866 * If the service is in the history file, and its supporting
16865 16867 * manifests are not found, we can safely delete the service
16866 16868 * because its manifests are removed from the system.
16867 16869 *
16868 16870 * Services not found in the history file are not delivered by
16869 16871 * Solaris and/or delivered outside supported directories, set
16870 16872 * unsupported flag for these services.
16871 16873 */
16872 16874 r = check_mfst_history(svcname);
16873 16875 if (r == -1)
16874 16876 return;
16875 16877
16876 16878 if (r) {
16877 16879 /* Set unsupported flag for service */
16878 16880 svc_add_no_support(svc);
16879 16881 } else {
16880 16882 /* Delete the service */
16881 16883 teardown_service(svc, svcname);
16882 16884 }
16883 16885
16884 16886 return;
16885 16887 }
16886 16888
16887 16889 /*
16888 16890 * Walk through the list of manifests and add them
16889 16891 * to the service.
16890 16892 *
16891 16893 * Create a manifestfiles pg and add the property.
16892 16894 */
16893 16895 mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16894 16896 if (mfwalk == NULL)
16895 16897 return;
16896 16898
16897 16899 cur_svc = svc;
16898 16900 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16899 16901 if (r != 0) {
16900 16902 cur_svc = NULL;
16901 16903 return;
16902 16904 }
16903 16905
16904 16906 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16905 16907 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16906 16908 mhash_filename_to_propname(mfile->str, 0));
16907 16909 if (pname == NULL)
16908 16910 uu_die(gettext("Out of memory.\n"));
16909 16911
16910 16912 (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16911 16913 uu_free(pname);
16912 16914 }
16913 16915 uu_list_walk_end(mfwalk);
16914 16916
16915 16917 cur_svc = NULL;
16916 16918 }
16917 16919
16918 16920 /*
16919 16921 * Take a service and process the manifest file entires to see if
16920 16922 * there is continued support for the service and instances. If
16921 16923 * not cleanup as appropriate.
16922 16924 *
16923 16925 * If a service does not have a manifest files entry flag it for
16924 16926 * upgrade and return.
16925 16927 *
16926 16928 * For each manifestfiles property check if the manifest file is
16927 16929 * under the supported /lib/svc/manifest or /var/svc/manifest path
16928 16930 * and if not then return immediately as this service is not supported
16929 16931 * by the cleanup mechanism and should be ignored.
16930 16932 *
16931 16933 * For each manifest file that is supported, check to see if the
16932 16934 * file exists. If not then remove the manifest file property
16933 16935 * from the service and the smf/manifest hash table. If the manifest
16934 16936 * file exists then verify that it supports the instances that are
16935 16937 * part of the service.
16936 16938 *
16937 16939 * Once all manifest files have been accounted for remove any instances
16938 16940 * that are no longer supported in the service.
16939 16941 *
16940 16942 * Return values :
16941 16943 * 0 - Successfully processed the service
16942 16944 * non-zero - failed to process the service
16943 16945 *
16944 16946 * On most errors, will just return to wait and get the next service,
16945 16947 * unless in case of unable to create the needed structures which is
16946 16948 * most likely a fatal error that is not going to be recoverable.
16947 16949 */
16948 16950 int
16949 16951 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16950 16952 {
16951 16953 struct mpg_mfile *mpntov = NULL;
16952 16954 struct mpg_mfile **mpvarry = NULL;
16953 16955 scf_service_t *svc;
16954 16956 scf_propertygroup_t *mpg;
16955 16957 scf_property_t *mp;
16956 16958 scf_value_t *mv;
16957 16959 scf_iter_t *mi;
16958 16960 scf_instance_t *instance;
16959 16961 uu_list_walk_t *insts;
16960 16962 uu_list_t *instances = NULL;
16961 16963 boolean_t activity = (boolean_t)act;
16962 16964 char *mpnbuf = NULL;
16963 16965 char *mpvbuf = NULL;
16964 16966 char *pgpropbuf;
16965 16967 int mfstcnt, rminstct, instct, mfstmax;
16966 16968 int index;
16967 16969 int r = 0;
16968 16970
16969 16971 assert(g_hndl != NULL);
16970 16972 assert(wip->svc != NULL);
16971 16973 assert(wip->fmri != NULL);
16972 16974
16973 16975 svc = wip->svc;
16974 16976
16975 16977 mpg = scf_pg_create(g_hndl);
16976 16978 mp = scf_property_create(g_hndl);
16977 16979 mi = scf_iter_create(g_hndl);
16978 16980 mv = scf_value_create(g_hndl);
16979 16981 instance = scf_instance_create(g_hndl);
16980 16982
16981 16983 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16982 16984 instance == NULL) {
16983 16985 uu_warn(gettext("Unable to create the supporting entities\n"));
16984 16986 uu_warn(gettext("scf error is : %s\n"),
16985 16987 scf_strerror(scf_error()));
16986 16988 scfdie();
16987 16989 }
16988 16990
16989 16991 /*
16990 16992 * Get the manifestfiles property group to be parsed for
16991 16993 * files existence.
16992 16994 */
16993 16995 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16994 16996 switch (scf_error()) {
16995 16997 case SCF_ERROR_NOT_FOUND:
16996 16998 upgrade_svc_mfst_connection(svc, wip->fmri);
16997 16999 break;
16998 17000 case SCF_ERROR_DELETED:
16999 17001 case SCF_ERROR_CONNECTION_BROKEN:
17000 17002 goto out;
17001 17003
17002 17004 case SCF_ERROR_HANDLE_MISMATCH:
17003 17005 case SCF_ERROR_NOT_BOUND:
17004 17006 case SCF_ERROR_NOT_SET:
17005 17007 default:
17006 17008 bad_error("scf_iter_pg_properties",
17007 17009 scf_error());
17008 17010 }
17009 17011
17010 17012 goto out;
17011 17013 }
17012 17014
17013 17015 /*
17014 17016 * Iterate through each of the manifestfiles properties
17015 17017 * to determine what manifestfiles are available.
17016 17018 *
17017 17019 * If a manifest file is supported then increment the
17018 17020 * count and therefore the service is safe.
17019 17021 */
17020 17022 if (scf_iter_pg_properties(mi, mpg) != 0) {
17021 17023 switch (scf_error()) {
17022 17024 case SCF_ERROR_DELETED:
17023 17025 case SCF_ERROR_CONNECTION_BROKEN:
17024 17026 goto out;
17025 17027
17026 17028 case SCF_ERROR_HANDLE_MISMATCH:
17027 17029 case SCF_ERROR_NOT_BOUND:
17028 17030 case SCF_ERROR_NOT_SET:
17029 17031 default:
17030 17032 bad_error("scf_iter_pg_properties",
17031 17033 scf_error());
17032 17034 }
17033 17035 }
17034 17036
17035 17037 mfstcnt = 0;
17036 17038 mfstmax = MFSTFILE_MAX;
17037 17039 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17038 17040 while ((r = scf_iter_next_property(mi, mp)) != 0) {
17039 17041 if (r == -1)
17040 17042 bad_error(gettext("Unable to iterate through "
17041 17043 "manifestfiles properties : %s"),
17042 17044 scf_error());
17043 17045
17044 17046 mpntov = safe_malloc(sizeof (struct mpg_mfile));
17045 17047 mpnbuf = safe_malloc(max_scf_name_len + 1);
17046 17048 mpvbuf = safe_malloc(max_scf_value_len + 1);
17047 17049 mpntov->mpg = mpnbuf;
17048 17050 mpntov->mfile = mpvbuf;
17049 17051 mpntov->access = 1;
17050 17052 if (scf_property_get_name(mp, mpnbuf,
17051 17053 max_scf_name_len + 1) < 0) {
17052 17054 uu_warn(gettext("Unable to get manifest file "
17053 17055 "property : %s\n"),
17054 17056 scf_strerror(scf_error()));
17055 17057
17056 17058 switch (scf_error()) {
17057 17059 case SCF_ERROR_DELETED:
17058 17060 case SCF_ERROR_CONNECTION_BROKEN:
17059 17061 r = scferror2errno(scf_error());
17060 17062 goto out_free;
17061 17063
17062 17064 case SCF_ERROR_HANDLE_MISMATCH:
17063 17065 case SCF_ERROR_NOT_BOUND:
17064 17066 case SCF_ERROR_NOT_SET:
17065 17067 default:
17066 17068 bad_error("scf_iter_pg_properties",
17067 17069 scf_error());
17068 17070 }
17069 17071 }
17070 17072
17071 17073 /*
17072 17074 * The support property is a boolean value that indicates
17073 17075 * if the service is supported for manifest file deletion.
17074 17076 * Currently at this time there is no code that sets this
17075 17077 * value to true. So while we could just let this be caught
17076 17078 * by the support check below, in the future this by be set
17077 17079 * to true and require processing. So for that, go ahead
17078 17080 * and check here, and just return if false. Otherwise,
17079 17081 * fall through expecting that other support checks will
17080 17082 * handle the entries.
17081 17083 */
17082 17084 if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17083 17085 uint8_t support;
17084 17086
17085 17087 if (scf_property_get_value(mp, mv) != 0 ||
17086 17088 scf_value_get_boolean(mv, &support) != 0) {
17087 17089 uu_warn(gettext("Unable to get the manifest "
17088 17090 "support value: %s\n"),
17089 17091 scf_strerror(scf_error()));
17090 17092
17091 17093 switch (scf_error()) {
17092 17094 case SCF_ERROR_DELETED:
17093 17095 case SCF_ERROR_CONNECTION_BROKEN:
17094 17096 r = scferror2errno(scf_error());
17095 17097 goto out_free;
17096 17098
17097 17099 case SCF_ERROR_HANDLE_MISMATCH:
17098 17100 case SCF_ERROR_NOT_BOUND:
17099 17101 case SCF_ERROR_NOT_SET:
17100 17102 default:
17101 17103 bad_error("scf_iter_pg_properties",
17102 17104 scf_error());
17103 17105 }
17104 17106 }
17105 17107
17106 17108 if (support == B_FALSE)
17107 17109 goto out_free;
17108 17110 }
17109 17111
17110 17112 /*
17111 17113 * Anything with a manifest outside of the supported
17112 17114 * directories, immediately bail out because that makes
17113 17115 * this service non-supported. We don't even want
17114 17116 * to do instance processing in this case because the
17115 17117 * instances could be part of the non-supported manifest.
17116 17118 */
17117 17119 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17118 17120 /*
17119 17121 * Manifest is not in /lib/svc, so we need to
17120 17122 * consider the /var/svc case.
17121 17123 */
17122 17124 if (strncmp(mpnbuf, VARSVC_PR,
17123 17125 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17124 17126 /*
17125 17127 * Either the manifest is not in /var/svc or
17126 17128 * /var is not yet mounted. We ignore the
17127 17129 * manifest either because it is not in a
17128 17130 * standard location or because we cannot
17129 17131 * currently access the manifest.
17130 17132 */
17131 17133 goto out_free;
17132 17134 }
17133 17135 }
17134 17136
17135 17137 /*
17136 17138 * Get the value to of the manifest file for this entry
17137 17139 * for access verification and instance support
17138 17140 * verification if it still exists.
17139 17141 *
17140 17142 * During Early Manifest Import if the manifest is in
17141 17143 * /var/svc then it may not yet be available for checking
17142 17144 * so we must determine if /var/svc is available. If not
17143 17145 * then defer until Late Manifest Import to cleanup.
17144 17146 */
17145 17147 if (scf_property_get_value(mp, mv) != 0) {
17146 17148 uu_warn(gettext("Unable to get the manifest file "
17147 17149 "value: %s\n"),
17148 17150 scf_strerror(scf_error()));
17149 17151
17150 17152 switch (scf_error()) {
17151 17153 case SCF_ERROR_DELETED:
17152 17154 case SCF_ERROR_CONNECTION_BROKEN:
17153 17155 r = scferror2errno(scf_error());
17154 17156 goto out_free;
17155 17157
17156 17158 case SCF_ERROR_HANDLE_MISMATCH:
17157 17159 case SCF_ERROR_NOT_BOUND:
17158 17160 case SCF_ERROR_NOT_SET:
17159 17161 default:
17160 17162 bad_error("scf_property_get_value",
17161 17163 scf_error());
17162 17164 }
17163 17165 }
17164 17166
17165 17167 if (scf_value_get_astring(mv, mpvbuf,
17166 17168 max_scf_value_len + 1) < 0) {
17167 17169 uu_warn(gettext("Unable to get the manifest "
17168 17170 "file : %s\n"),
17169 17171 scf_strerror(scf_error()));
17170 17172
17171 17173 switch (scf_error()) {
17172 17174 case SCF_ERROR_DELETED:
17173 17175 case SCF_ERROR_CONNECTION_BROKEN:
17174 17176 r = scferror2errno(scf_error());
17175 17177 goto out_free;
17176 17178
17177 17179 case SCF_ERROR_HANDLE_MISMATCH:
17178 17180 case SCF_ERROR_NOT_BOUND:
17179 17181 case SCF_ERROR_NOT_SET:
17180 17182 default:
17181 17183 bad_error("scf_value_get_astring",
17182 17184 scf_error());
17183 17185 }
17184 17186 }
17185 17187
17186 17188 mpvarry[mfstcnt] = mpntov;
17187 17189 mfstcnt++;
17188 17190
17189 17191 /*
17190 17192 * Check for the need to reallocate array
17191 17193 */
17192 17194 if (mfstcnt >= (mfstmax - 1)) {
17193 17195 struct mpg_mfile **newmpvarry;
17194 17196
17195 17197 mfstmax = mfstmax * 2;
17196 17198 newmpvarry = realloc(mpvarry,
17197 17199 sizeof (struct mpg_mfile *) * mfstmax);
17198 17200
17199 17201 if (newmpvarry == NULL)
17200 17202 goto out_free;
17201 17203
17202 17204 mpvarry = newmpvarry;
17203 17205 }
17204 17206
17205 17207 mpvarry[mfstcnt] = NULL;
17206 17208 }
17207 17209
17208 17210 for (index = 0; mpvarry[index]; index++) {
17209 17211 mpntov = mpvarry[index];
17210 17212
17211 17213 /*
17212 17214 * Check to see if the manifestfile is accessable, if so hand
17213 17215 * this service and manifestfile off to be processed for
17214 17216 * instance support.
17215 17217 */
17216 17218 mpnbuf = mpntov->mpg;
17217 17219 mpvbuf = mpntov->mfile;
17218 17220 if (access(mpvbuf, F_OK) != 0) {
17219 17221 mpntov->access = 0;
17220 17222 activity++;
17221 17223 mfstcnt--;
17222 17224 /* Remove the entry from the service */
17223 17225 cur_svc = svc;
17224 17226 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17225 17227 mpnbuf);
17226 17228 if (pgpropbuf == NULL)
17227 17229 uu_die(gettext("Out of memory.\n"));
17228 17230
17229 17231 lscf_delprop(pgpropbuf);
17230 17232 cur_svc = NULL;
17231 17233
17232 17234 uu_free(pgpropbuf);
17233 17235 }
17234 17236 }
17235 17237
17236 17238 /*
17237 17239 * If mfstcnt is 0, none of the manifests that supported the service
17238 17240 * existed so remove the service.
17239 17241 */
17240 17242 if (mfstcnt == 0) {
17241 17243 teardown_service(svc, wip->fmri);
17242 17244
17243 17245 goto out_free;
17244 17246 }
17245 17247
17246 17248 if (activity) {
17247 17249 int nosvcsupport = 0;
17248 17250
17249 17251 /*
17250 17252 * If the list of service instances is NULL then
17251 17253 * create the list.
17252 17254 */
17253 17255 instances = create_instance_list(svc, 1);
17254 17256 if (instances == NULL) {
17255 17257 uu_warn(gettext("Unable to create instance list %s\n"),
17256 17258 wip->fmri);
17257 17259 goto out_free;
17258 17260 }
17259 17261
17260 17262 rminstct = uu_list_numnodes(instances);
17261 17263 instct = rminstct;
17262 17264
17263 17265 for (index = 0; mpvarry[index]; index++) {
17264 17266 mpntov = mpvarry[index];
17265 17267 if (mpntov->access == 0)
17266 17268 continue;
17267 17269
17268 17270 mpnbuf = mpntov->mpg;
17269 17271 mpvbuf = mpntov->mfile;
17270 17272 r = check_instance_support(mpvbuf, wip->fmri,
17271 17273 instances);
17272 17274 if (r == -1) {
17273 17275 nosvcsupport++;
17274 17276 } else {
17275 17277 rminstct -= r;
17276 17278 }
17277 17279 }
17278 17280
17279 17281 if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17280 17282 teardown_service(svc, wip->fmri);
17281 17283
17282 17284 goto out_free;
17283 17285 }
17284 17286 }
17285 17287
17286 17288 /*
17287 17289 * If there are instances left on the instance list, then
17288 17290 * we must remove them.
17289 17291 */
17290 17292 if (instances != NULL && uu_list_numnodes(instances)) {
17291 17293 string_list_t *sp;
17292 17294
17293 17295 insts = uu_list_walk_start(instances, 0);
17294 17296 while ((sp = uu_list_walk_next(insts)) != NULL) {
17295 17297 /*
17296 17298 * Remove the instance from the instances list.
17297 17299 */
17298 17300 safe_printf(gettext("Delete instance %s from "
17299 17301 "service %s\n"), sp->str, wip->fmri);
17300 17302 if (scf_service_get_instance(svc, sp->str,
17301 17303 instance) != SCF_SUCCESS) {
17302 17304 (void) uu_warn("scf_error - %s\n",
17303 17305 scf_strerror(scf_error()));
17304 17306
17305 17307 continue;
17306 17308 }
17307 17309
17308 17310 (void) disable_instance(instance);
17309 17311
17310 17312 (void) lscf_instance_delete(instance, 1);
17311 17313 }
17312 17314 scf_instance_destroy(instance);
17313 17315 uu_list_walk_end(insts);
17314 17316 }
17315 17317
17316 17318 out_free:
17317 17319 if (mpvarry) {
17318 17320 struct mpg_mfile *fmpntov;
17319 17321
17320 17322 for (index = 0; mpvarry[index]; index++) {
17321 17323 fmpntov = mpvarry[index];
17322 17324 if (fmpntov->mpg == mpnbuf)
17323 17325 mpnbuf = NULL;
17324 17326 free(fmpntov->mpg);
17325 17327
17326 17328 if (fmpntov->mfile == mpvbuf)
17327 17329 mpvbuf = NULL;
17328 17330 free(fmpntov->mfile);
17329 17331
17330 17332 if (fmpntov == mpntov)
17331 17333 mpntov = NULL;
17332 17334 free(fmpntov);
17333 17335 }
17334 17336 if (mpnbuf)
17335 17337 free(mpnbuf);
17336 17338 if (mpvbuf)
17337 17339 free(mpvbuf);
17338 17340 if (mpntov)
17339 17341 free(mpntov);
17340 17342
17341 17343 free(mpvarry);
17342 17344 }
17343 17345 out:
17344 17346 scf_pg_destroy(mpg);
17345 17347 scf_property_destroy(mp);
17346 17348 scf_iter_destroy(mi);
17347 17349 scf_value_destroy(mv);
17348 17350
17349 17351 return (0);
17350 17352 }
17351 17353
17352 17354 /*
17353 17355 * Take the service and search for the manifestfiles property
17354 17356 * in each of the property groups. If the manifest file
17355 17357 * associated with the property does not exist then remove
17356 17358 * the property group.
17357 17359 */
17358 17360 int
17359 17361 lscf_hash_cleanup()
17360 17362 {
17361 17363 scf_service_t *svc;
17362 17364 scf_scope_t *scope;
17363 17365 scf_propertygroup_t *pg;
17364 17366 scf_property_t *prop;
17365 17367 scf_value_t *val;
17366 17368 scf_iter_t *iter;
17367 17369 char *pgname = NULL;
17368 17370 char *mfile = NULL;
17369 17371 int r;
17370 17372
17371 17373 svc = scf_service_create(g_hndl);
17372 17374 scope = scf_scope_create(g_hndl);
17373 17375 pg = scf_pg_create(g_hndl);
17374 17376 prop = scf_property_create(g_hndl);
17375 17377 val = scf_value_create(g_hndl);
17376 17378 iter = scf_iter_create(g_hndl);
17377 17379 if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17378 17380 svc == NULL || scope == NULL) {
17379 17381 uu_warn(gettext("Unable to create a property group, or "
17380 17382 "property\n"));
17381 17383 uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17382 17384 "pg is not NULL");
17383 17385 uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17384 17386 "prop is not NULL");
17385 17387 uu_warn("%s\n", val == NULL ? "val is NULL" :
17386 17388 "val is not NULL");
17387 17389 uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17388 17390 "iter is not NULL");
17389 17391 uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17390 17392 "svc is not NULL");
17391 17393 uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17392 17394 "scope is not NULL");
17393 17395 uu_warn(gettext("scf error is : %s\n"),
17394 17396 scf_strerror(scf_error()));
17395 17397 scfdie();
17396 17398 }
17397 17399
17398 17400 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17399 17401 switch (scf_error()) {
17400 17402 case SCF_ERROR_CONNECTION_BROKEN:
17401 17403 case SCF_ERROR_NOT_FOUND:
17402 17404 goto out;
17403 17405
17404 17406 case SCF_ERROR_HANDLE_MISMATCH:
17405 17407 case SCF_ERROR_NOT_BOUND:
17406 17408 case SCF_ERROR_INVALID_ARGUMENT:
17407 17409 default:
17408 17410 bad_error("scf_handle_get_scope", scf_error());
17409 17411 }
17410 17412 }
17411 17413
17412 17414 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17413 17415 uu_warn(gettext("Unable to process the hash service, %s\n"),
17414 17416 HASH_SVC);
17415 17417 goto out;
17416 17418 }
17417 17419
17418 17420 pgname = safe_malloc(max_scf_name_len + 1);
17419 17421 mfile = safe_malloc(max_scf_value_len + 1);
17420 17422
17421 17423 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17422 17424 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17423 17425 scf_strerror(scf_error()));
17424 17426 goto out;
17425 17427 }
17426 17428
17427 17429 while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17428 17430 if (r == -1)
17429 17431 goto out;
17430 17432
17431 17433 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17432 17434 switch (scf_error()) {
17433 17435 case SCF_ERROR_DELETED:
17434 17436 return (ENODEV);
17435 17437
17436 17438 case SCF_ERROR_CONNECTION_BROKEN:
17437 17439 return (ECONNABORTED);
17438 17440
17439 17441 case SCF_ERROR_NOT_SET:
17440 17442 case SCF_ERROR_NOT_BOUND:
17441 17443 default:
17442 17444 bad_error("scf_pg_get_name", scf_error());
17443 17445 }
17444 17446 }
17445 17447 if (IGNORE_VAR) {
17446 17448 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17447 17449 continue;
17448 17450 }
17449 17451
17450 17452 /*
17451 17453 * If unable to get the property continue as this is an
17452 17454 * entry that has no location to check against.
17453 17455 */
17454 17456 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17455 17457 continue;
17456 17458 }
17457 17459
17458 17460 if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17459 17461 uu_warn(gettext("Unable to get value from %s\n"),
17460 17462 pgname);
17461 17463
17462 17464 switch (scf_error()) {
17463 17465 case SCF_ERROR_DELETED:
17464 17466 case SCF_ERROR_CONSTRAINT_VIOLATED:
17465 17467 case SCF_ERROR_NOT_FOUND:
17466 17468 case SCF_ERROR_NOT_SET:
17467 17469 continue;
17468 17470
17469 17471 case SCF_ERROR_CONNECTION_BROKEN:
17470 17472 r = scferror2errno(scf_error());
17471 17473 goto out;
17472 17474
17473 17475 case SCF_ERROR_HANDLE_MISMATCH:
17474 17476 case SCF_ERROR_NOT_BOUND:
17475 17477 default:
17476 17478 bad_error("scf_property_get_value",
17477 17479 scf_error());
17478 17480 }
17479 17481 }
17480 17482
17481 17483 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17482 17484 == -1) {
17483 17485 uu_warn(gettext("Unable to get astring from %s : %s\n"),
17484 17486 pgname, scf_strerror(scf_error()));
17485 17487
17486 17488 switch (scf_error()) {
17487 17489 case SCF_ERROR_NOT_SET:
17488 17490 case SCF_ERROR_TYPE_MISMATCH:
17489 17491 continue;
17490 17492
17491 17493 default:
17492 17494 bad_error("scf_value_get_astring", scf_error());
17493 17495 }
17494 17496 }
17495 17497
17496 17498 if (access(mfile, F_OK) == 0)
17497 17499 continue;
17498 17500
17499 17501 (void) scf_pg_delete(pg);
17500 17502 }
17501 17503
17502 17504 out:
17503 17505 scf_scope_destroy(scope);
17504 17506 scf_service_destroy(svc);
17505 17507 scf_pg_destroy(pg);
17506 17508 scf_property_destroy(prop);
17507 17509 scf_value_destroy(val);
17508 17510 scf_iter_destroy(iter);
17509 17511 free(pgname);
17510 17512 free(mfile);
17511 17513
17512 17514 return (0);
17513 17515 }
17514 17516
17515 17517 #ifndef NATIVE_BUILD
17516 17518 /* ARGSUSED */
17517 17519 CPL_MATCH_FN(complete_select)
17518 17520 {
17519 17521 const char *arg0, *arg1, *arg1end;
17520 17522 int word_start, err = 0, r;
17521 17523 size_t len;
17522 17524 char *buf;
17523 17525
17524 17526 lscf_prep_hndl();
17525 17527
17526 17528 arg0 = line + strspn(line, " \t");
17527 17529 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17528 17530
17529 17531 arg1 = arg0 + sizeof ("select") - 1;
17530 17532 arg1 += strspn(arg1, " \t");
17531 17533 word_start = arg1 - line;
17532 17534
17533 17535 arg1end = arg1 + strcspn(arg1, " \t");
17534 17536 if (arg1end < line + word_end)
17535 17537 return (0);
17536 17538
17537 17539 len = line + word_end - arg1;
17538 17540
17539 17541 buf = safe_malloc(max_scf_name_len + 1);
17540 17542
17541 17543 if (cur_snap != NULL) {
17542 17544 return (0);
17543 17545 } else if (cur_inst != NULL) {
17544 17546 return (0);
17545 17547 } else if (cur_svc != NULL) {
17546 17548 scf_instance_t *inst;
17547 17549 scf_iter_t *iter;
17548 17550
17549 17551 if ((inst = scf_instance_create(g_hndl)) == NULL ||
17550 17552 (iter = scf_iter_create(g_hndl)) == NULL)
17551 17553 scfdie();
17552 17554
17553 17555 if (scf_iter_service_instances(iter, cur_svc) != 0)
17554 17556 scfdie();
17555 17557
17556 17558 for (;;) {
17557 17559 r = scf_iter_next_instance(iter, inst);
17558 17560 if (r == 0)
17559 17561 break;
17560 17562 if (r != 1)
17561 17563 scfdie();
17562 17564
17563 17565 if (scf_instance_get_name(inst, buf,
17564 17566 max_scf_name_len + 1) < 0)
17565 17567 scfdie();
17566 17568
17567 17569 if (strncmp(buf, arg1, len) == 0) {
17568 17570 err = cpl_add_completion(cpl, line, word_start,
17569 17571 word_end, buf + len, "", " ");
17570 17572 if (err != 0)
17571 17573 break;
17572 17574 }
17573 17575 }
17574 17576
17575 17577 scf_iter_destroy(iter);
17576 17578 scf_instance_destroy(inst);
17577 17579
17578 17580 return (err);
17579 17581 } else {
17580 17582 scf_service_t *svc;
17581 17583 scf_iter_t *iter;
17582 17584
17583 17585 assert(cur_scope != NULL);
17584 17586
17585 17587 if ((svc = scf_service_create(g_hndl)) == NULL ||
17586 17588 (iter = scf_iter_create(g_hndl)) == NULL)
17587 17589 scfdie();
17588 17590
17589 17591 if (scf_iter_scope_services(iter, cur_scope) != 0)
17590 17592 scfdie();
17591 17593
17592 17594 for (;;) {
17593 17595 r = scf_iter_next_service(iter, svc);
17594 17596 if (r == 0)
17595 17597 break;
17596 17598 if (r != 1)
17597 17599 scfdie();
17598 17600
17599 17601 if (scf_service_get_name(svc, buf,
17600 17602 max_scf_name_len + 1) < 0)
17601 17603 scfdie();
17602 17604
17603 17605 if (strncmp(buf, arg1, len) == 0) {
17604 17606 err = cpl_add_completion(cpl, line, word_start,
17605 17607 word_end, buf + len, "", " ");
17606 17608 if (err != 0)
17607 17609 break;
17608 17610 }
17609 17611 }
17610 17612
17611 17613 scf_iter_destroy(iter);
17612 17614 scf_service_destroy(svc);
17613 17615
17614 17616 return (err);
17615 17617 }
17616 17618 }
17617 17619
17618 17620 /* ARGSUSED */
17619 17621 CPL_MATCH_FN(complete_command)
17620 17622 {
17621 17623 uint32_t scope = 0;
17622 17624
17623 17625 if (cur_snap != NULL)
17624 17626 scope = CS_SNAP;
17625 17627 else if (cur_inst != NULL)
17626 17628 scope = CS_INST;
17627 17629 else if (cur_svc != NULL)
17628 17630 scope = CS_SVC;
17629 17631 else
17630 17632 scope = CS_SCOPE;
17631 17633
17632 17634 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17633 17635 }
17634 17636 #endif /* NATIVE_BUILD */
↓ open down ↓ |
7100 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX