Print this page
7029 want per-process exploit mitigation features (secflags)
7030 want basic address space layout randomization (aslr)
7031 noexec_user_stack should be a secflag
7032 want a means to forbid mappings around NULL.
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/svc/svccfg/svccfg_libscf.c
+++ new/usr/src/cmd/svc/svccfg/svccfg_libscf.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright 2015 Joyent, Inc.
25 25 * Copyright 2012 Milan Jurik. All rights reserved.
26 26 */
27 27
28 28
29 29 #include <alloca.h>
30 30 #include <assert.h>
31 31 #include <ctype.h>
32 32 #include <door.h>
33 33 #include <errno.h>
34 34 #include <fcntl.h>
35 35 #include <fnmatch.h>
36 36 #include <inttypes.h>
37 37 #include <libintl.h>
38 38 #include <libnvpair.h>
39 39 #include <libscf.h>
40 40 #include <libscf_priv.h>
41 41 #include <libtecla.h>
42 42 #include <libuutil.h>
43 43 #include <limits.h>
44 44 #include <locale.h>
45 45 #include <stdarg.h>
46 46 #include <string.h>
47 47 #include <strings.h>
48 48 #include <time.h>
49 49 #include <unistd.h>
50 50 #include <wait.h>
51 51 #include <poll.h>
52 52
53 53 #include <libxml/tree.h>
54 54
55 55 #include <sys/param.h>
56 56
57 57 #include <sys/stat.h>
58 58 #include <sys/mman.h>
59 59
60 60 #include "svccfg.h"
61 61 #include "notify_params.h"
62 62 #include "manifest_hash.h"
63 63 #include "manifest_find.h"
64 64
65 65 /* The colon namespaces in each entity (each followed by a newline). */
66 66 #define COLON_NAMESPACES ":properties\n"
67 67
68 68 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX"
69 69
70 70 /* These are characters which the lexer requires to be in double-quotes. */
71 71 #define CHARS_TO_QUOTE " \t\n\\>=\"()"
72 72
73 73 #define HASH_SIZE 16
74 74 #define HASH_PG_TYPE "framework"
75 75 #define HASH_PG_FLAGS 0
76 76 #define HASH_PROP "md5sum"
77 77
78 78 /*
79 79 * Indentation used in the output of the describe subcommand.
80 80 */
81 81 #define TMPL_VALUE_INDENT " "
82 82 #define TMPL_INDENT " "
83 83 #define TMPL_INDENT_2X " "
84 84 #define TMPL_CHOICE_INDENT " "
85 85
86 86 /*
87 87 * Directory locations for manifests
88 88 */
89 89 #define VARSVC_DIR "/var/svc/manifest"
90 90 #define LIBSVC_DIR "/lib/svc/manifest"
91 91 #define VARSVC_PR "var_svc_manifest"
92 92 #define LIBSVC_PR "lib_svc_manifest"
93 93 #define MFSTFILEPR "manifestfile"
94 94
95 95 #define SUPPORTPROP "support"
96 96
97 97 #define MFSTHISTFILE "/lib/svc/share/mfsthistory"
98 98
99 99 #define MFSTFILE_MAX 16
100 100
101 101 /*
102 102 * These are the classes of elements which may appear as children of service
103 103 * or instance elements in XML manifests.
104 104 */
105 105 struct entity_elts {
106 106 xmlNodePtr create_default_instance;
107 107 xmlNodePtr single_instance;
108 108 xmlNodePtr restarter;
109 109 xmlNodePtr dependencies;
110 110 xmlNodePtr dependents;
111 111 xmlNodePtr method_context;
112 112 xmlNodePtr exec_methods;
113 113 xmlNodePtr notify_params;
114 114 xmlNodePtr property_groups;
115 115 xmlNodePtr instances;
116 116 xmlNodePtr stability;
117 117 xmlNodePtr template;
118 118 };
119 119
120 120 /*
121 121 * Likewise for property_group elements.
122 122 */
123 123 struct pg_elts {
124 124 xmlNodePtr stability;
125 125 xmlNodePtr propvals;
126 126 xmlNodePtr properties;
127 127 };
128 128
129 129 /*
130 130 * Likewise for template elements.
131 131 */
132 132 struct template_elts {
133 133 xmlNodePtr common_name;
134 134 xmlNodePtr description;
135 135 xmlNodePtr documentation;
136 136 };
137 137
138 138 /*
139 139 * Likewise for type (for notification parameters) elements.
140 140 */
141 141 struct params_elts {
142 142 xmlNodePtr paramval;
143 143 xmlNodePtr parameter;
144 144 };
145 145
146 146 /*
147 147 * This structure is for snaplevel lists. They are convenient because libscf
148 148 * only allows traversing snaplevels in one direction.
149 149 */
150 150 struct snaplevel {
151 151 uu_list_node_t list_node;
152 152 scf_snaplevel_t *sl;
153 153 };
154 154
155 155 /*
156 156 * This is used for communication between lscf_service_export and
157 157 * export_callback.
158 158 */
159 159 struct export_args {
160 160 const char *filename;
161 161 int flags;
162 162 };
163 163
164 164 /*
165 165 * The service_manifest structure is used by the upgrade process
166 166 * to create a list of service to manifest linkages from the manifests
167 167 * in a set of given directories.
168 168 */
169 169 typedef struct service_manifest {
170 170 const char *servicename;
171 171 uu_list_t *mfstlist;
172 172 size_t mfstlist_sz;
173 173
174 174 uu_avl_node_t svcmfst_node;
175 175 } service_manifest_t;
176 176
177 177 /*
178 178 * Structure to track the manifest file property group
179 179 * and the manifest file associated with that property
180 180 * group. Also, a flag to keep the access once it has
181 181 * been checked.
182 182 */
183 183 struct mpg_mfile {
184 184 char *mpg;
185 185 char *mfile;
186 186 int access;
187 187 };
188 188
189 189 const char * const scf_pg_general = SCF_PG_GENERAL;
190 190 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
191 191 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
192 192 const char * const scf_property_external = "external";
193 193
194 194 const char * const snap_initial = "initial";
195 195 const char * const snap_lastimport = "last-import";
196 196 const char * const snap_previous = "previous";
197 197 const char * const snap_running = "running";
198 198
199 199 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */
200 200
201 201 ssize_t max_scf_fmri_len;
202 202 ssize_t max_scf_name_len;
203 203 ssize_t max_scf_pg_type_len;
204 204 ssize_t max_scf_value_len;
205 205 static size_t max_scf_len;
206 206
207 207 static scf_scope_t *cur_scope;
208 208 static scf_service_t *cur_svc = NULL;
209 209 static scf_instance_t *cur_inst = NULL;
210 210 static scf_snapshot_t *cur_snap = NULL;
211 211 static scf_snaplevel_t *cur_level = NULL;
212 212
213 213 static uu_list_pool_t *snaplevel_pool;
214 214 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
215 215 static uu_list_t *cur_levels;
216 216 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */
217 217
218 218 static FILE *tempfile = NULL;
219 219 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
220 220
221 221 static const char *emsg_entity_not_selected;
222 222 static const char *emsg_permission_denied;
223 223 static const char *emsg_create_xml;
224 224 static const char *emsg_cant_modify_snapshots;
225 225 static const char *emsg_invalid_for_snapshot;
226 226 static const char *emsg_read_only;
227 227 static const char *emsg_deleted;
228 228 static const char *emsg_invalid_pg_name;
229 229 static const char *emsg_invalid_prop_name;
230 230 static const char *emsg_no_such_pg;
231 231 static const char *emsg_fmri_invalid_pg_name;
232 232 static const char *emsg_fmri_invalid_pg_name_type;
233 233 static const char *emsg_pg_added;
234 234 static const char *emsg_pg_changed;
235 235 static const char *emsg_pg_deleted;
236 236 static const char *emsg_pg_mod_perm;
237 237 static const char *emsg_pg_add_perm;
238 238 static const char *emsg_pg_del_perm;
239 239 static const char *emsg_snap_perm;
240 240 static const char *emsg_dpt_dangling;
241 241 static const char *emsg_dpt_no_dep;
242 242
243 243 static int li_only = 0;
244 244 static int no_refresh = 0;
245 245
246 246 /* how long in ns we should wait between checks for a pg */
247 247 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
248 248
249 249 /* import globals, to minimize allocations */
250 250 static scf_scope_t *imp_scope = NULL;
251 251 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
252 252 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
253 253 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
254 254 static scf_snapshot_t *imp_rsnap = NULL;
255 255 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
256 256 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
257 257 static scf_property_t *imp_prop = NULL;
258 258 static scf_iter_t *imp_iter = NULL;
259 259 static scf_iter_t *imp_rpg_iter = NULL;
260 260 static scf_iter_t *imp_up_iter = NULL;
261 261 static scf_transaction_t *imp_tx = NULL; /* always reset this */
262 262 static char *imp_str = NULL;
263 263 static size_t imp_str_sz;
264 264 static char *imp_tsname = NULL;
265 265 static char *imp_fe1 = NULL; /* for fmri_equal() */
266 266 static char *imp_fe2 = NULL;
267 267 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */
268 268
269 269 /* upgrade_dependents() globals */
270 270 static scf_instance_t *ud_inst = NULL;
271 271 static scf_snaplevel_t *ud_snpl = NULL;
272 272 static scf_propertygroup_t *ud_pg = NULL;
273 273 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
274 274 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
275 275 static int ud_run_dpts_pg_set = 0;
276 276 static scf_property_t *ud_prop = NULL;
277 277 static scf_property_t *ud_dpt_prop = NULL;
278 278 static scf_value_t *ud_val = NULL;
279 279 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
280 280 static scf_transaction_t *ud_tx = NULL;
281 281 static char *ud_ctarg = NULL;
282 282 static char *ud_oldtarg = NULL;
283 283 static char *ud_name = NULL;
284 284
285 285 /* export globals */
286 286 static scf_instance_t *exp_inst;
287 287 static scf_propertygroup_t *exp_pg;
288 288 static scf_property_t *exp_prop;
289 289 static scf_value_t *exp_val;
290 290 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
291 291 static char *exp_str;
292 292 static size_t exp_str_sz;
293 293
294 294 /* cleanup globals */
295 295 static uu_avl_pool_t *service_manifest_pool = NULL;
296 296 static uu_avl_t *service_manifest_tree = NULL;
297 297
298 298 static void scfdie_lineno(int lineno) __NORETURN;
299 299
300 300 static char *start_method_names[] = {
301 301 "start",
302 302 "inetd_start",
303 303 NULL
304 304 };
305 305
306 306 static struct uri_scheme {
307 307 const char *scheme;
308 308 const char *protocol;
309 309 } uri_scheme[] = {
310 310 { "mailto", "smtp" },
311 311 { "snmp", "snmp" },
312 312 { "syslog", "syslog" },
313 313 { NULL, NULL }
314 314 };
315 315 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
316 316 sizeof (struct uri_scheme)) - 1)
317 317
318 318 static int
319 319 check_uri_scheme(const char *scheme)
320 320 {
321 321 int i;
322 322
323 323 for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
324 324 if (strcmp(scheme, uri_scheme[i].scheme) == 0)
325 325 return (i);
326 326 }
327 327
328 328 return (-1);
329 329 }
330 330
331 331 static int
332 332 check_uri_protocol(const char *p)
333 333 {
334 334 int i;
335 335
336 336 for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
337 337 if (strcmp(p, uri_scheme[i].protocol) == 0)
338 338 return (i);
339 339 }
340 340
341 341 return (-1);
342 342 }
343 343
344 344 /*
345 345 * For unexpected libscf errors.
346 346 */
347 347 #ifdef NDEBUG
348 348
349 349 static void scfdie(void) __NORETURN;
350 350
351 351 static void
352 352 scfdie(void)
353 353 {
354 354 scf_error_t err = scf_error();
355 355
356 356 if (err == SCF_ERROR_CONNECTION_BROKEN)
357 357 uu_die(gettext("Repository connection broken. Exiting.\n"));
358 358
359 359 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"),
360 360 scf_strerror(err));
361 361 }
362 362
363 363 #else
364 364
365 365 #define scfdie() scfdie_lineno(__LINE__)
366 366
367 367 static void
368 368 scfdie_lineno(int lineno)
369 369 {
370 370 scf_error_t err = scf_error();
371 371
372 372 if (err == SCF_ERROR_CONNECTION_BROKEN)
373 373 uu_die(gettext("Repository connection broken. Exiting.\n"));
374 374
375 375 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
376 376 ": %s.\n"), lineno, scf_strerror(err));
377 377 }
378 378
379 379 #endif
380 380
381 381 static void
382 382 scfwarn(void)
383 383 {
384 384 warn(gettext("Unexpected libscf error: %s.\n"),
385 385 scf_strerror(scf_error()));
386 386 }
387 387
388 388 /*
389 389 * Clear a field of a structure.
390 390 */
391 391 static int
392 392 clear_int(void *a, void *b)
393 393 {
394 394 /* LINTED */
395 395 *(int *)((char *)a + (size_t)b) = 0;
396 396
397 397 return (UU_WALK_NEXT);
398 398 }
399 399
400 400 static int
401 401 scferror2errno(scf_error_t err)
402 402 {
403 403 switch (err) {
404 404 case SCF_ERROR_BACKEND_ACCESS:
405 405 return (EACCES);
406 406
407 407 case SCF_ERROR_BACKEND_READONLY:
408 408 return (EROFS);
409 409
410 410 case SCF_ERROR_CONNECTION_BROKEN:
411 411 return (ECONNABORTED);
412 412
413 413 case SCF_ERROR_CONSTRAINT_VIOLATED:
414 414 case SCF_ERROR_INVALID_ARGUMENT:
415 415 return (EINVAL);
416 416
417 417 case SCF_ERROR_DELETED:
418 418 return (ECANCELED);
419 419
420 420 case SCF_ERROR_EXISTS:
421 421 return (EEXIST);
422 422
423 423 case SCF_ERROR_NO_MEMORY:
424 424 return (ENOMEM);
425 425
426 426 case SCF_ERROR_NO_RESOURCES:
427 427 return (ENOSPC);
428 428
429 429 case SCF_ERROR_NOT_FOUND:
430 430 return (ENOENT);
431 431
432 432 case SCF_ERROR_PERMISSION_DENIED:
433 433 return (EPERM);
434 434
435 435 default:
436 436 #ifndef NDEBUG
437 437 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
438 438 __FILE__, __LINE__, err);
439 439 #else
440 440 (void) fprintf(stderr, "Unknown libscf error %d.\n", err);
441 441 #endif
442 442 abort();
443 443 /* NOTREACHED */
444 444 }
445 445 }
446 446
447 447 static int
448 448 entity_get_pg(void *ent, int issvc, const char *name,
449 449 scf_propertygroup_t *pg)
450 450 {
451 451 if (issvc)
452 452 return (scf_service_get_pg(ent, name, pg));
453 453 else
454 454 return (scf_instance_get_pg(ent, name, pg));
455 455 }
456 456
457 457 static void
458 458 entity_destroy(void *ent, int issvc)
459 459 {
460 460 if (issvc)
461 461 scf_service_destroy(ent);
462 462 else
463 463 scf_instance_destroy(ent);
464 464 }
465 465
466 466 static int
467 467 get_pg(const char *pg_name, scf_propertygroup_t *pg)
468 468 {
469 469 int ret;
470 470
471 471 if (cur_level != NULL)
472 472 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
473 473 else if (cur_inst != NULL)
474 474 ret = scf_instance_get_pg(cur_inst, pg_name, pg);
475 475 else
476 476 ret = scf_service_get_pg(cur_svc, pg_name, pg);
477 477
478 478 return (ret);
479 479 }
480 480
481 481 /*
482 482 * Find a snaplevel in a snapshot. If get_svc is true, find the service
483 483 * snaplevel. Otherwise find the instance snaplevel.
484 484 *
485 485 * Returns
486 486 * 0 - success
487 487 * ECONNABORTED - repository connection broken
488 488 * ECANCELED - instance containing snap was deleted
489 489 * ENOENT - snap has no snaplevels
490 490 * - requested snaplevel not found
491 491 */
492 492 static int
493 493 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
494 494 {
495 495 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
496 496 switch (scf_error()) {
497 497 case SCF_ERROR_CONNECTION_BROKEN:
498 498 case SCF_ERROR_DELETED:
499 499 case SCF_ERROR_NOT_FOUND:
500 500 return (scferror2errno(scf_error()));
501 501
502 502 case SCF_ERROR_HANDLE_MISMATCH:
503 503 case SCF_ERROR_NOT_BOUND:
504 504 case SCF_ERROR_NOT_SET:
505 505 default:
506 506 bad_error("scf_snapshot_get_base_snaplevel",
507 507 scf_error());
508 508 }
509 509 }
510 510
511 511 for (;;) {
512 512 ssize_t ssz;
513 513
514 514 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
515 515 if (ssz >= 0) {
516 516 if (!get_svc)
517 517 return (0);
518 518 } else {
519 519 switch (scf_error()) {
520 520 case SCF_ERROR_CONSTRAINT_VIOLATED:
521 521 if (get_svc)
522 522 return (0);
523 523 break;
524 524
525 525 case SCF_ERROR_DELETED:
526 526 case SCF_ERROR_CONNECTION_BROKEN:
527 527 return (scferror2errno(scf_error()));
528 528
529 529 case SCF_ERROR_NOT_SET:
530 530 case SCF_ERROR_NOT_BOUND:
531 531 default:
532 532 bad_error("scf_snaplevel_get_instance_name",
533 533 scf_error());
534 534 }
535 535 }
536 536
537 537 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
538 538 switch (scf_error()) {
539 539 case SCF_ERROR_NOT_FOUND:
540 540 case SCF_ERROR_CONNECTION_BROKEN:
541 541 case SCF_ERROR_DELETED:
542 542 return (scferror2errno(scf_error()));
543 543
544 544 case SCF_ERROR_HANDLE_MISMATCH:
545 545 case SCF_ERROR_NOT_BOUND:
546 546 case SCF_ERROR_NOT_SET:
547 547 case SCF_ERROR_INVALID_ARGUMENT:
548 548 default:
549 549 bad_error("scf_snaplevel_get_next_snaplevel",
550 550 scf_error());
551 551 }
552 552 }
553 553 }
554 554 }
555 555
556 556 /*
557 557 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has
558 558 * a running snapshot, and that snapshot has an instance snaplevel, set pg to
559 559 * the property group named name in it. If it doesn't have a running
560 560 * snapshot, set pg to the instance's current property group named name.
561 561 *
562 562 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
563 563 * its instances. If one has a running snapshot with a service snaplevel, set
564 564 * pg to the property group named name in it. If no such snaplevel could be
565 565 * found, set pg to the service's current property group named name.
566 566 *
567 567 * iter, inst, snap, and snpl are required scratch objects.
568 568 *
569 569 * Returns
570 570 * 0 - success
571 571 * ECONNABORTED - repository connection broken
572 572 * ECANCELED - ent was deleted
573 573 * ENOENT - no such property group
574 574 * EINVAL - name is an invalid property group name
575 575 * EBADF - found running snapshot is missing a snaplevel
576 576 */
577 577 static int
578 578 entity_get_running_pg(void *ent, int issvc, const char *name,
579 579 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
580 580 scf_snapshot_t *snap, scf_snaplevel_t *snpl)
581 581 {
582 582 int r;
583 583
584 584 if (issvc) {
585 585 /* Search for an instance with a running snapshot. */
586 586 if (scf_iter_service_instances(iter, ent) != 0) {
587 587 switch (scf_error()) {
588 588 case SCF_ERROR_DELETED:
589 589 case SCF_ERROR_CONNECTION_BROKEN:
590 590 return (scferror2errno(scf_error()));
591 591
592 592 case SCF_ERROR_NOT_SET:
593 593 case SCF_ERROR_NOT_BOUND:
594 594 case SCF_ERROR_HANDLE_MISMATCH:
595 595 default:
596 596 bad_error("scf_iter_service_instances",
597 597 scf_error());
598 598 }
599 599 }
600 600
601 601 for (;;) {
602 602 r = scf_iter_next_instance(iter, inst);
603 603 if (r == 0) {
604 604 if (scf_service_get_pg(ent, name, pg) == 0)
605 605 return (0);
606 606
607 607 switch (scf_error()) {
608 608 case SCF_ERROR_DELETED:
609 609 case SCF_ERROR_NOT_FOUND:
610 610 case SCF_ERROR_INVALID_ARGUMENT:
611 611 case SCF_ERROR_CONNECTION_BROKEN:
612 612 return (scferror2errno(scf_error()));
613 613
614 614 case SCF_ERROR_NOT_BOUND:
615 615 case SCF_ERROR_HANDLE_MISMATCH:
616 616 case SCF_ERROR_NOT_SET:
617 617 default:
618 618 bad_error("scf_service_get_pg",
619 619 scf_error());
620 620 }
621 621 }
622 622 if (r != 1) {
623 623 switch (scf_error()) {
624 624 case SCF_ERROR_DELETED:
625 625 case SCF_ERROR_CONNECTION_BROKEN:
626 626 return (scferror2errno(scf_error()));
627 627
628 628 case SCF_ERROR_INVALID_ARGUMENT:
629 629 case SCF_ERROR_NOT_SET:
630 630 case SCF_ERROR_NOT_BOUND:
631 631 case SCF_ERROR_HANDLE_MISMATCH:
632 632 default:
633 633 bad_error("scf_iter_next_instance",
634 634 scf_error());
635 635 }
636 636 }
637 637
638 638 if (scf_instance_get_snapshot(inst, snap_running,
639 639 snap) == 0)
640 640 break;
641 641
642 642 switch (scf_error()) {
643 643 case SCF_ERROR_NOT_FOUND:
644 644 case SCF_ERROR_DELETED:
645 645 continue;
646 646
647 647 case SCF_ERROR_CONNECTION_BROKEN:
648 648 return (ECONNABORTED);
649 649
650 650 case SCF_ERROR_HANDLE_MISMATCH:
651 651 case SCF_ERROR_INVALID_ARGUMENT:
652 652 case SCF_ERROR_NOT_SET:
653 653 case SCF_ERROR_NOT_BOUND:
654 654 default:
655 655 bad_error("scf_instance_get_snapshot",
656 656 scf_error());
657 657 }
658 658 }
659 659 } else {
660 660 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
661 661 switch (scf_error()) {
662 662 case SCF_ERROR_NOT_FOUND:
663 663 break;
664 664
665 665 case SCF_ERROR_DELETED:
666 666 case SCF_ERROR_CONNECTION_BROKEN:
667 667 return (scferror2errno(scf_error()));
668 668
669 669 case SCF_ERROR_NOT_BOUND:
670 670 case SCF_ERROR_HANDLE_MISMATCH:
671 671 case SCF_ERROR_INVALID_ARGUMENT:
672 672 case SCF_ERROR_NOT_SET:
673 673 default:
674 674 bad_error("scf_instance_get_snapshot",
675 675 scf_error());
676 676 }
677 677
678 678 if (scf_instance_get_pg(ent, name, pg) == 0)
679 679 return (0);
680 680
681 681 switch (scf_error()) {
682 682 case SCF_ERROR_DELETED:
683 683 case SCF_ERROR_NOT_FOUND:
684 684 case SCF_ERROR_INVALID_ARGUMENT:
685 685 case SCF_ERROR_CONNECTION_BROKEN:
686 686 return (scferror2errno(scf_error()));
687 687
688 688 case SCF_ERROR_NOT_BOUND:
689 689 case SCF_ERROR_HANDLE_MISMATCH:
690 690 case SCF_ERROR_NOT_SET:
691 691 default:
692 692 bad_error("scf_instance_get_pg", scf_error());
693 693 }
694 694 }
695 695 }
696 696
697 697 r = get_snaplevel(snap, issvc, snpl);
698 698 switch (r) {
699 699 case 0:
700 700 break;
701 701
702 702 case ECONNABORTED:
703 703 case ECANCELED:
704 704 return (r);
705 705
706 706 case ENOENT:
707 707 return (EBADF);
708 708
709 709 default:
710 710 bad_error("get_snaplevel", r);
711 711 }
712 712
713 713 if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
714 714 return (0);
715 715
716 716 switch (scf_error()) {
717 717 case SCF_ERROR_DELETED:
718 718 case SCF_ERROR_INVALID_ARGUMENT:
719 719 case SCF_ERROR_CONNECTION_BROKEN:
720 720 case SCF_ERROR_NOT_FOUND:
721 721 return (scferror2errno(scf_error()));
722 722
723 723 case SCF_ERROR_NOT_BOUND:
724 724 case SCF_ERROR_HANDLE_MISMATCH:
725 725 case SCF_ERROR_NOT_SET:
726 726 default:
727 727 bad_error("scf_snaplevel_get_pg", scf_error());
728 728 /* NOTREACHED */
729 729 }
730 730 }
731 731
732 732 /*
733 733 * To be registered with atexit().
734 734 */
735 735 static void
736 736 remove_tempfile(void)
737 737 {
738 738 int ret;
739 739
740 740 if (tempfile != NULL) {
741 741 if (fclose(tempfile) == EOF)
742 742 (void) warn(gettext("Could not close temporary file"));
743 743 tempfile = NULL;
744 744 }
745 745
746 746 if (tempfilename[0] != '\0') {
747 747 do {
748 748 ret = remove(tempfilename);
749 749 } while (ret == -1 && errno == EINTR);
750 750 if (ret == -1)
751 751 warn(gettext("Could not remove temporary file"));
752 752 tempfilename[0] = '\0';
753 753 }
754 754 }
755 755
756 756 /*
757 757 * Launch private svc.configd(1M) for manipulating alternate repositories.
758 758 */
759 759 static void
760 760 start_private_repository(engine_state_t *est)
761 761 {
762 762 int fd, stat;
763 763 struct door_info info;
764 764 pid_t pid;
765 765
766 766 /*
767 767 * 1. Create a temporary file for the door.
768 768 */
769 769 if (est->sc_repo_doorname != NULL)
770 770 free((void *)est->sc_repo_doorname);
771 771
772 772 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
773 773 if (est->sc_repo_doorname == NULL)
774 774 uu_die(gettext("Could not acquire temporary filename"));
775 775
776 776 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
777 777 if (fd < 0)
778 778 uu_die(gettext("Could not create temporary file for "
779 779 "repository server"));
780 780
781 781 (void) close(fd);
782 782
783 783 /*
784 784 * 2. Launch a configd with that door, using the specified
785 785 * repository.
786 786 */
787 787 if ((est->sc_repo_pid = fork()) == 0) {
788 788 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
789 789 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
790 790 NULL);
791 791 uu_die(gettext("Could not execute %s"), est->sc_repo_server);
792 792 } else if (est->sc_repo_pid == -1)
793 793 uu_die(gettext("Attempt to fork failed"));
794 794
795 795 do {
796 796 pid = waitpid(est->sc_repo_pid, &stat, 0);
797 797 } while (pid == -1 && errno == EINTR);
798 798
799 799 if (pid == -1)
800 800 uu_die(gettext("Could not waitpid() for repository server"));
801 801
802 802 if (!WIFEXITED(stat)) {
803 803 uu_die(gettext("Repository server failed (status %d).\n"),
804 804 stat);
805 805 } else if (WEXITSTATUS(stat) != 0) {
806 806 uu_die(gettext("Repository server failed (exit %d).\n"),
807 807 WEXITSTATUS(stat));
808 808 }
809 809
810 810 /*
811 811 * See if it was successful by checking if the door is a door.
812 812 */
813 813
814 814 fd = open(est->sc_repo_doorname, O_RDWR);
815 815 if (fd < 0)
816 816 uu_die(gettext("Could not open door \"%s\""),
817 817 est->sc_repo_doorname);
818 818
819 819 if (door_info(fd, &info) < 0)
820 820 uu_die(gettext("Unexpected door_info() error"));
821 821
822 822 if (close(fd) == -1)
823 823 warn(gettext("Could not close repository door"),
824 824 strerror(errno));
825 825
826 826 est->sc_repo_pid = info.di_target;
827 827 }
828 828
829 829 void
830 830 lscf_cleanup(void)
831 831 {
832 832 /*
833 833 * In the case where we've launched a private svc.configd(1M)
834 834 * instance, we must terminate our child and remove the temporary
835 835 * rendezvous point.
836 836 */
837 837 if (est->sc_repo_pid > 0) {
838 838 (void) kill(est->sc_repo_pid, SIGTERM);
839 839 (void) waitpid(est->sc_repo_pid, NULL, 0);
840 840 (void) unlink(est->sc_repo_doorname);
841 841
842 842 est->sc_repo_pid = 0;
843 843 }
844 844 }
845 845
846 846 void
847 847 unselect_cursnap(void)
848 848 {
849 849 void *cookie;
850 850
851 851 cur_level = NULL;
852 852
853 853 cookie = NULL;
854 854 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
855 855 scf_snaplevel_destroy(cur_elt->sl);
856 856 free(cur_elt);
857 857 }
858 858
859 859 scf_snapshot_destroy(cur_snap);
860 860 cur_snap = NULL;
861 861 }
862 862
863 863 void
864 864 lscf_prep_hndl(void)
865 865 {
866 866 if (g_hndl != NULL)
867 867 return;
868 868
869 869 g_hndl = scf_handle_create(SCF_VERSION);
870 870 if (g_hndl == NULL)
871 871 scfdie();
872 872
873 873 if (est->sc_repo_filename != NULL)
874 874 start_private_repository(est);
875 875
876 876 if (est->sc_repo_doorname != NULL) {
877 877 scf_value_t *repo_value;
878 878 int ret;
879 879
880 880 repo_value = scf_value_create(g_hndl);
881 881 if (repo_value == NULL)
882 882 scfdie();
883 883
884 884 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
885 885 assert(ret == SCF_SUCCESS);
886 886
887 887 if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
888 888 SCF_SUCCESS)
889 889 scfdie();
890 890
891 891 scf_value_destroy(repo_value);
892 892 }
893 893
894 894 if (scf_handle_bind(g_hndl) != 0)
895 895 uu_die(gettext("Could not connect to repository server: %s.\n"),
896 896 scf_strerror(scf_error()));
897 897
898 898 cur_scope = scf_scope_create(g_hndl);
899 899 if (cur_scope == NULL)
900 900 scfdie();
901 901
902 902 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
903 903 scfdie();
904 904 }
905 905
906 906 static void
907 907 repository_teardown(void)
908 908 {
909 909 if (g_hndl != NULL) {
910 910 if (cur_snap != NULL)
911 911 unselect_cursnap();
912 912 scf_instance_destroy(cur_inst);
913 913 scf_service_destroy(cur_svc);
914 914 scf_scope_destroy(cur_scope);
915 915 scf_handle_destroy(g_hndl);
916 916 cur_inst = NULL;
917 917 cur_svc = NULL;
918 918 cur_scope = NULL;
919 919 g_hndl = NULL;
920 920 lscf_cleanup();
921 921 }
922 922 }
923 923
924 924 void
925 925 lscf_set_repository(const char *repfile, int force)
926 926 {
927 927 repository_teardown();
928 928
929 929 if (est->sc_repo_filename != NULL) {
930 930 free((void *)est->sc_repo_filename);
931 931 est->sc_repo_filename = NULL;
932 932 }
933 933
934 934 if ((force == 0) && (access(repfile, R_OK) != 0)) {
935 935 /*
936 936 * Repository file does not exist
937 937 * or has no read permission.
938 938 */
939 939 warn(gettext("Cannot access \"%s\": %s\n"),
940 940 repfile, strerror(errno));
941 941 } else {
942 942 est->sc_repo_filename = safe_strdup(repfile);
943 943 }
944 944
945 945 lscf_prep_hndl();
946 946 }
947 947
948 948 void
949 949 lscf_init()
950 950 {
951 951 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
952 952 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
953 953 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
954 954 0 ||
955 955 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
956 956 scfdie();
957 957
958 958 max_scf_len = max_scf_fmri_len;
959 959 if (max_scf_name_len > max_scf_len)
960 960 max_scf_len = max_scf_name_len;
961 961 if (max_scf_pg_type_len > max_scf_len)
962 962 max_scf_len = max_scf_pg_type_len;
963 963 /*
964 964 * When a value of type opaque is represented as a string, the
965 965 * string contains 2 characters for every byte of data. That is
966 966 * because the string contains the hex representation of the opaque
967 967 * value.
968 968 */
969 969 if (2 * max_scf_value_len > max_scf_len)
970 970 max_scf_len = 2 * max_scf_value_len;
971 971
972 972 if (atexit(remove_tempfile) != 0)
973 973 uu_die(gettext("Could not register atexit() function"));
974 974
975 975 emsg_entity_not_selected = gettext("An entity is not selected.\n");
976 976 emsg_permission_denied = gettext("Permission denied.\n");
977 977 emsg_create_xml = gettext("Could not create XML node.\n");
978 978 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
979 979 emsg_invalid_for_snapshot =
980 980 gettext("Invalid operation on a snapshot.\n");
981 981 emsg_read_only = gettext("Backend read-only.\n");
982 982 emsg_deleted = gettext("Current selection has been deleted.\n");
983 983 emsg_invalid_pg_name =
984 984 gettext("Invalid property group name \"%s\".\n");
985 985 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
986 986 emsg_no_such_pg = gettext("No such property group \"%s\".\n");
987 987 emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
988 988 "with invalid name \"%s\".\n");
989 989 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
990 990 "group with invalid name \"%s\" or type \"%s\".\n");
991 991 emsg_pg_added = gettext("%s changed unexpectedly "
992 992 "(property group \"%s\" added).\n");
993 993 emsg_pg_changed = gettext("%s changed unexpectedly "
994 994 "(property group \"%s\" changed).\n");
995 995 emsg_pg_deleted = gettext("%s changed unexpectedly "
996 996 "(property group \"%s\" or an ancestor was deleted).\n");
997 997 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
998 998 "in %s (permission denied).\n");
999 999 emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
1000 1000 "in %s (permission denied).\n");
1001 1001 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
1002 1002 "in %s (permission denied).\n");
1003 1003 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
1004 1004 "(permission denied).\n");
1005 1005 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1006 1006 "new dependent \"%s\" because it already exists). Warning: The "
1007 1007 "current dependent's target (%s) does not exist.\n");
1008 1008 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1009 1009 "dependent \"%s\" because it already exists). Warning: The "
1010 1010 "current dependent's target (%s) does not have a dependency named "
1011 1011 "\"%s\" as expected.\n");
1012 1012
1013 1013 string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1014 1014 offsetof(string_list_t, node), NULL, 0);
1015 1015 snaplevel_pool = uu_list_pool_create("snaplevels",
1016 1016 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1017 1017 NULL, 0);
1018 1018 }
1019 1019
1020 1020
1021 1021 static const char *
1022 1022 prop_to_typestr(const scf_property_t *prop)
1023 1023 {
1024 1024 scf_type_t ty;
1025 1025
1026 1026 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1027 1027 scfdie();
1028 1028
1029 1029 return (scf_type_to_string(ty));
1030 1030 }
1031 1031
1032 1032 static scf_type_t
1033 1033 string_to_type(const char *type)
1034 1034 {
1035 1035 size_t len = strlen(type);
1036 1036 char *buf;
1037 1037
1038 1038 if (len == 0 || type[len - 1] != ':')
1039 1039 return (SCF_TYPE_INVALID);
1040 1040
1041 1041 buf = (char *)alloca(len + 1);
1042 1042 (void) strlcpy(buf, type, len + 1);
1043 1043 buf[len - 1] = 0;
1044 1044
1045 1045 return (scf_string_to_type(buf));
1046 1046 }
1047 1047
1048 1048 static scf_value_t *
1049 1049 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1050 1050 {
1051 1051 scf_value_t *v;
1052 1052 char *dup, *nstr;
1053 1053 size_t len;
1054 1054
1055 1055 v = scf_value_create(g_hndl);
1056 1056 if (v == NULL)
1057 1057 scfdie();
1058 1058
1059 1059 len = strlen(str);
1060 1060 if (require_quotes &&
1061 1061 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1062 1062 semerr(gettext("Multiple string values or string values "
1063 1063 "with spaces must be quoted with '\"'.\n"));
1064 1064 scf_value_destroy(v);
1065 1065 return (NULL);
1066 1066 }
1067 1067
1068 1068 nstr = dup = safe_strdup(str);
1069 1069 if (dup[0] == '\"') {
1070 1070 /*
1071 1071 * Strip out the first and the last quote.
1072 1072 */
1073 1073 dup[len - 1] = '\0';
1074 1074 nstr = dup + 1;
1075 1075 }
1076 1076
1077 1077 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1078 1078 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1079 1079 semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1080 1080 scf_type_to_string(ty), nstr);
1081 1081 scf_value_destroy(v);
1082 1082 v = NULL;
1083 1083 }
1084 1084 free(dup);
1085 1085 return (v);
1086 1086 }
1087 1087
1088 1088 /*
1089 1089 * Print str to strm, quoting double-quotes and backslashes with backslashes.
1090 1090 * Optionally append a comment prefix ('#') to newlines ('\n').
1091 1091 */
1092 1092 static int
1093 1093 quote_and_print(const char *str, FILE *strm, int commentnl)
1094 1094 {
1095 1095 const char *cp;
1096 1096
1097 1097 for (cp = str; *cp != '\0'; ++cp) {
1098 1098 if (*cp == '"' || *cp == '\\')
1099 1099 (void) putc('\\', strm);
1100 1100
1101 1101 (void) putc(*cp, strm);
1102 1102
1103 1103 if (commentnl && *cp == '\n') {
1104 1104 (void) putc('#', strm);
1105 1105 }
1106 1106 }
1107 1107
1108 1108 return (ferror(strm));
1109 1109 }
1110 1110
1111 1111 /*
1112 1112 * These wrappers around lowlevel functions provide consistent error checking
1113 1113 * and warnings.
1114 1114 */
1115 1115 static int
1116 1116 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1117 1117 {
1118 1118 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1119 1119 return (0);
1120 1120
1121 1121 if (scf_error() != SCF_ERROR_NOT_FOUND)
1122 1122 scfdie();
1123 1123
1124 1124 if (g_verbose) {
1125 1125 ssize_t len;
1126 1126 char *fmri;
1127 1127
1128 1128 len = scf_pg_to_fmri(pg, NULL, 0);
1129 1129 if (len < 0)
1130 1130 scfdie();
1131 1131
1132 1132 fmri = safe_malloc(len + 1);
1133 1133
1134 1134 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1135 1135 scfdie();
1136 1136
1137 1137 warn(gettext("Expected property %s of property group %s is "
1138 1138 "missing.\n"), propname, fmri);
1139 1139
1140 1140 free(fmri);
1141 1141 }
1142 1142
1143 1143 return (-1);
1144 1144 }
1145 1145
1146 1146 static int
1147 1147 prop_check_type(scf_property_t *prop, scf_type_t ty)
1148 1148 {
1149 1149 scf_type_t pty;
1150 1150
1151 1151 if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1152 1152 scfdie();
1153 1153
1154 1154 if (ty == pty)
1155 1155 return (0);
1156 1156
1157 1157 if (g_verbose) {
1158 1158 ssize_t len;
1159 1159 char *fmri;
1160 1160 const char *tystr;
1161 1161
1162 1162 len = scf_property_to_fmri(prop, NULL, 0);
1163 1163 if (len < 0)
1164 1164 scfdie();
1165 1165
1166 1166 fmri = safe_malloc(len + 1);
1167 1167
1168 1168 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1169 1169 scfdie();
1170 1170
1171 1171 tystr = scf_type_to_string(ty);
1172 1172 if (tystr == NULL)
1173 1173 tystr = "?";
1174 1174
1175 1175 warn(gettext("Property %s is not of expected type %s.\n"),
1176 1176 fmri, tystr);
1177 1177
1178 1178 free(fmri);
1179 1179 }
1180 1180
1181 1181 return (-1);
1182 1182 }
1183 1183
1184 1184 static int
1185 1185 prop_get_val(scf_property_t *prop, scf_value_t *val)
1186 1186 {
1187 1187 scf_error_t err;
1188 1188
1189 1189 if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1190 1190 return (0);
1191 1191
1192 1192 err = scf_error();
1193 1193
1194 1194 if (err != SCF_ERROR_NOT_FOUND &&
1195 1195 err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1196 1196 err != SCF_ERROR_PERMISSION_DENIED)
1197 1197 scfdie();
1198 1198
1199 1199 if (g_verbose) {
1200 1200 ssize_t len;
1201 1201 char *fmri, *emsg;
1202 1202
1203 1203 len = scf_property_to_fmri(prop, NULL, 0);
1204 1204 if (len < 0)
1205 1205 scfdie();
1206 1206
1207 1207 fmri = safe_malloc(len + 1);
1208 1208
1209 1209 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1210 1210 scfdie();
1211 1211
1212 1212 if (err == SCF_ERROR_NOT_FOUND)
1213 1213 emsg = gettext("Property %s has no values; expected "
1214 1214 "one.\n");
1215 1215 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1216 1216 emsg = gettext("Property %s has multiple values; "
1217 1217 "expected one.\n");
1218 1218 else
1219 1219 emsg = gettext("No permission to read property %s.\n");
1220 1220
1221 1221 warn(emsg, fmri);
1222 1222
1223 1223 free(fmri);
1224 1224 }
1225 1225
1226 1226 return (-1);
1227 1227 }
1228 1228
1229 1229
1230 1230 static boolean_t
1231 1231 snaplevel_is_instance(const scf_snaplevel_t *level)
1232 1232 {
1233 1233 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1234 1234 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1235 1235 scfdie();
1236 1236 return (0);
1237 1237 } else {
1238 1238 return (1);
1239 1239 }
1240 1240 }
1241 1241
1242 1242 /*
1243 1243 * Decode FMRI into a service or instance, and put the result in *ep. If
1244 1244 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is
1245 1245 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify
1246 1246 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be
1247 1247 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point
1248 1248 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1249 1249 * whether *ep is a service.
1250 1250 */
1251 1251 static scf_error_t
1252 1252 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1253 1253 {
1254 1254 char *fmri_copy;
1255 1255 const char *sstr, *istr, *pgstr;
1256 1256 scf_service_t *svc;
1257 1257 scf_instance_t *inst;
1258 1258
1259 1259 fmri_copy = strdup(fmri);
1260 1260 if (fmri_copy == NULL)
1261 1261 return (SCF_ERROR_NO_MEMORY);
1262 1262
1263 1263 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1264 1264 SCF_SUCCESS) {
1265 1265 free(fmri_copy);
1266 1266 return (SCF_ERROR_INVALID_ARGUMENT);
1267 1267 }
1268 1268
1269 1269 free(fmri_copy);
1270 1270
1271 1271 if (sstr == NULL || pgstr != NULL)
1272 1272 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1273 1273
1274 1274 if (istr == NULL) {
1275 1275 svc = scf_service_create(h);
1276 1276 if (svc == NULL)
1277 1277 return (SCF_ERROR_NO_MEMORY);
1278 1278
1279 1279 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1280 1280 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1281 1281 if (scf_error() != SCF_ERROR_NOT_FOUND)
1282 1282 scfdie();
1283 1283
1284 1284 return (SCF_ERROR_NOT_FOUND);
1285 1285 }
1286 1286
1287 1287 *ep = svc;
1288 1288 *isservice = 1;
1289 1289 } else {
1290 1290 inst = scf_instance_create(h);
1291 1291 if (inst == NULL)
1292 1292 return (SCF_ERROR_NO_MEMORY);
1293 1293
1294 1294 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1295 1295 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1296 1296 if (scf_error() != SCF_ERROR_NOT_FOUND)
1297 1297 scfdie();
1298 1298
1299 1299 return (SCF_ERROR_NOT_FOUND);
1300 1300 }
1301 1301
1302 1302 *ep = inst;
1303 1303 *isservice = 0;
1304 1304 }
1305 1305
1306 1306 return (SCF_ERROR_NONE);
1307 1307 }
1308 1308
1309 1309 /*
1310 1310 * Create the entity named by fmri. Place a pointer to its libscf handle in
1311 1311 * *ep, and set or clear *isservicep if it is a service or an instance.
1312 1312 * Returns
1313 1313 * SCF_ERROR_NONE - success
1314 1314 * SCF_ERROR_NO_MEMORY - scf_*_create() failed
1315 1315 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1316 1316 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1317 1317 * SCF_ERROR_NOT_FOUND - no such scope
1318 1318 * SCF_ERROR_PERMISSION_DENIED
1319 1319 * SCF_ERROR_BACKEND_READONLY
1320 1320 * SCF_ERROR_BACKEND_ACCESS
1321 1321 */
1322 1322 static scf_error_t
1323 1323 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1324 1324 {
1325 1325 char *fmri_copy;
1326 1326 const char *scstr, *sstr, *istr, *pgstr;
1327 1327 scf_scope_t *scope = NULL;
1328 1328 scf_service_t *svc = NULL;
1329 1329 scf_instance_t *inst = NULL;
1330 1330 scf_error_t scfe;
1331 1331
1332 1332 fmri_copy = safe_strdup(fmri);
1333 1333
1334 1334 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1335 1335 0) {
1336 1336 free(fmri_copy);
1337 1337 return (SCF_ERROR_INVALID_ARGUMENT);
1338 1338 }
1339 1339
1340 1340 if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1341 1341 free(fmri_copy);
1342 1342 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1343 1343 }
1344 1344
1345 1345 *ep = NULL;
1346 1346
1347 1347 if ((scope = scf_scope_create(h)) == NULL ||
1348 1348 (svc = scf_service_create(h)) == NULL ||
1349 1349 (inst = scf_instance_create(h)) == NULL) {
1350 1350 scfe = SCF_ERROR_NO_MEMORY;
1351 1351 goto out;
1352 1352 }
1353 1353
1354 1354 get_scope:
1355 1355 if (scf_handle_get_scope(h, scstr, scope) != 0) {
1356 1356 switch (scf_error()) {
1357 1357 case SCF_ERROR_CONNECTION_BROKEN:
1358 1358 scfdie();
1359 1359 /* NOTREACHED */
1360 1360
1361 1361 case SCF_ERROR_NOT_FOUND:
1362 1362 scfe = SCF_ERROR_NOT_FOUND;
1363 1363 goto out;
1364 1364
1365 1365 case SCF_ERROR_HANDLE_MISMATCH:
1366 1366 case SCF_ERROR_NOT_BOUND:
1367 1367 case SCF_ERROR_INVALID_ARGUMENT:
1368 1368 default:
1369 1369 bad_error("scf_handle_get_scope", scf_error());
1370 1370 }
1371 1371 }
1372 1372
1373 1373 get_svc:
1374 1374 if (scf_scope_get_service(scope, sstr, svc) != 0) {
1375 1375 switch (scf_error()) {
1376 1376 case SCF_ERROR_CONNECTION_BROKEN:
1377 1377 scfdie();
1378 1378 /* NOTREACHED */
1379 1379
1380 1380 case SCF_ERROR_DELETED:
1381 1381 goto get_scope;
1382 1382
1383 1383 case SCF_ERROR_NOT_FOUND:
1384 1384 break;
1385 1385
1386 1386 case SCF_ERROR_HANDLE_MISMATCH:
1387 1387 case SCF_ERROR_INVALID_ARGUMENT:
1388 1388 case SCF_ERROR_NOT_BOUND:
1389 1389 case SCF_ERROR_NOT_SET:
1390 1390 default:
1391 1391 bad_error("scf_scope_get_service", scf_error());
1392 1392 }
1393 1393
1394 1394 if (scf_scope_add_service(scope, sstr, svc) != 0) {
1395 1395 switch (scf_error()) {
1396 1396 case SCF_ERROR_CONNECTION_BROKEN:
1397 1397 scfdie();
1398 1398 /* NOTREACHED */
1399 1399
1400 1400 case SCF_ERROR_DELETED:
1401 1401 goto get_scope;
1402 1402
1403 1403 case SCF_ERROR_PERMISSION_DENIED:
1404 1404 case SCF_ERROR_BACKEND_READONLY:
1405 1405 case SCF_ERROR_BACKEND_ACCESS:
1406 1406 scfe = scf_error();
1407 1407 goto out;
1408 1408
1409 1409 case SCF_ERROR_HANDLE_MISMATCH:
1410 1410 case SCF_ERROR_INVALID_ARGUMENT:
1411 1411 case SCF_ERROR_NOT_BOUND:
1412 1412 case SCF_ERROR_NOT_SET:
1413 1413 default:
1414 1414 bad_error("scf_scope_get_service", scf_error());
1415 1415 }
1416 1416 }
1417 1417 }
1418 1418
1419 1419 if (istr == NULL) {
1420 1420 scfe = SCF_ERROR_NONE;
1421 1421 *ep = svc;
1422 1422 *isservicep = 1;
1423 1423 goto out;
1424 1424 }
1425 1425
1426 1426 get_inst:
1427 1427 if (scf_service_get_instance(svc, istr, inst) != 0) {
1428 1428 switch (scf_error()) {
1429 1429 case SCF_ERROR_CONNECTION_BROKEN:
1430 1430 scfdie();
1431 1431 /* NOTREACHED */
1432 1432
1433 1433 case SCF_ERROR_DELETED:
1434 1434 goto get_svc;
1435 1435
1436 1436 case SCF_ERROR_NOT_FOUND:
1437 1437 break;
1438 1438
1439 1439 case SCF_ERROR_HANDLE_MISMATCH:
1440 1440 case SCF_ERROR_INVALID_ARGUMENT:
1441 1441 case SCF_ERROR_NOT_BOUND:
1442 1442 case SCF_ERROR_NOT_SET:
1443 1443 default:
1444 1444 bad_error("scf_service_get_instance", scf_error());
1445 1445 }
1446 1446
1447 1447 if (scf_service_add_instance(svc, istr, inst) != 0) {
1448 1448 switch (scf_error()) {
1449 1449 case SCF_ERROR_CONNECTION_BROKEN:
1450 1450 scfdie();
1451 1451 /* NOTREACHED */
1452 1452
1453 1453 case SCF_ERROR_DELETED:
1454 1454 goto get_svc;
1455 1455
1456 1456 case SCF_ERROR_PERMISSION_DENIED:
1457 1457 case SCF_ERROR_BACKEND_READONLY:
1458 1458 case SCF_ERROR_BACKEND_ACCESS:
1459 1459 scfe = scf_error();
1460 1460 goto out;
1461 1461
1462 1462 case SCF_ERROR_HANDLE_MISMATCH:
1463 1463 case SCF_ERROR_INVALID_ARGUMENT:
1464 1464 case SCF_ERROR_NOT_BOUND:
1465 1465 case SCF_ERROR_NOT_SET:
1466 1466 default:
1467 1467 bad_error("scf_service_add_instance",
1468 1468 scf_error());
1469 1469 }
1470 1470 }
1471 1471 }
1472 1472
1473 1473 scfe = SCF_ERROR_NONE;
1474 1474 *ep = inst;
1475 1475 *isservicep = 0;
1476 1476
1477 1477 out:
1478 1478 if (*ep != inst)
1479 1479 scf_instance_destroy(inst);
1480 1480 if (*ep != svc)
1481 1481 scf_service_destroy(svc);
1482 1482 scf_scope_destroy(scope);
1483 1483 free(fmri_copy);
1484 1484 return (scfe);
1485 1485 }
1486 1486
1487 1487 /*
1488 1488 * Create or update a snapshot of inst. snap is a required scratch object.
1489 1489 *
1490 1490 * Returns
1491 1491 * 0 - success
1492 1492 * ECONNABORTED - repository connection broken
1493 1493 * EPERM - permission denied
1494 1494 * ENOSPC - configd is out of resources
1495 1495 * ECANCELED - inst was deleted
1496 1496 * -1 - unknown libscf error (message printed)
1497 1497 */
1498 1498 static int
1499 1499 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1500 1500 {
1501 1501 again:
1502 1502 if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1503 1503 if (_scf_snapshot_take_attach(inst, snap) != 0) {
1504 1504 switch (scf_error()) {
1505 1505 case SCF_ERROR_CONNECTION_BROKEN:
1506 1506 case SCF_ERROR_PERMISSION_DENIED:
1507 1507 case SCF_ERROR_NO_RESOURCES:
1508 1508 return (scferror2errno(scf_error()));
1509 1509
1510 1510 case SCF_ERROR_NOT_SET:
1511 1511 case SCF_ERROR_INVALID_ARGUMENT:
1512 1512 default:
1513 1513 bad_error("_scf_snapshot_take_attach",
1514 1514 scf_error());
1515 1515 }
1516 1516 }
1517 1517 } else {
1518 1518 switch (scf_error()) {
1519 1519 case SCF_ERROR_NOT_FOUND:
1520 1520 break;
1521 1521
1522 1522 case SCF_ERROR_DELETED:
1523 1523 case SCF_ERROR_CONNECTION_BROKEN:
1524 1524 return (scferror2errno(scf_error()));
1525 1525
1526 1526 case SCF_ERROR_HANDLE_MISMATCH:
1527 1527 case SCF_ERROR_NOT_BOUND:
1528 1528 case SCF_ERROR_INVALID_ARGUMENT:
1529 1529 case SCF_ERROR_NOT_SET:
1530 1530 default:
1531 1531 bad_error("scf_instance_get_snapshot", scf_error());
1532 1532 }
1533 1533
1534 1534 if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1535 1535 switch (scf_error()) {
1536 1536 case SCF_ERROR_EXISTS:
1537 1537 goto again;
1538 1538
1539 1539 case SCF_ERROR_CONNECTION_BROKEN:
1540 1540 case SCF_ERROR_NO_RESOURCES:
1541 1541 case SCF_ERROR_PERMISSION_DENIED:
1542 1542 return (scferror2errno(scf_error()));
1543 1543
1544 1544 default:
1545 1545 scfwarn();
1546 1546 return (-1);
1547 1547
1548 1548 case SCF_ERROR_NOT_SET:
1549 1549 case SCF_ERROR_INTERNAL:
1550 1550 case SCF_ERROR_INVALID_ARGUMENT:
1551 1551 case SCF_ERROR_HANDLE_MISMATCH:
1552 1552 bad_error("_scf_snapshot_take_new",
1553 1553 scf_error());
1554 1554 }
1555 1555 }
1556 1556 }
1557 1557
1558 1558 return (0);
1559 1559 }
1560 1560
1561 1561 static int
1562 1562 refresh_running_snapshot(void *entity)
1563 1563 {
1564 1564 scf_snapshot_t *snap;
1565 1565 int r;
1566 1566
1567 1567 if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1568 1568 scfdie();
1569 1569 r = take_snap(entity, snap_running, snap);
1570 1570 scf_snapshot_destroy(snap);
1571 1571
1572 1572 return (r);
1573 1573 }
1574 1574
1575 1575 /*
1576 1576 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *.
1577 1577 * Otherwise take entity to be an scf_service_t * and refresh all of its child
1578 1578 * instances. fmri is used for messages. inst, iter, and name_buf are used
1579 1579 * for scratch space. Returns
1580 1580 * 0 - success
1581 1581 * ECONNABORTED - repository connection broken
1582 1582 * ECANCELED - entity was deleted
1583 1583 * EACCES - backend denied access
1584 1584 * EPERM - permission denied
1585 1585 * ENOSPC - repository server out of resources
1586 1586 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set.
1587 1587 */
1588 1588 static int
1589 1589 refresh_entity(int isservice, void *entity, const char *fmri,
1590 1590 scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1591 1591 {
1592 1592 scf_error_t scfe;
1593 1593 int r;
1594 1594
1595 1595 if (!isservice) {
1596 1596 /*
1597 1597 * Let restarter handles refreshing and making new running
1598 1598 * snapshot only if operating on a live repository and not
1599 1599 * running in early import.
1600 1600 */
1601 1601 if (est->sc_repo_filename == NULL &&
1602 1602 est->sc_repo_doorname == NULL &&
1603 1603 est->sc_in_emi == 0) {
1604 1604 if (_smf_refresh_instance_i(entity) == 0) {
1605 1605 if (g_verbose)
1606 1606 warn(gettext("Refreshed %s.\n"), fmri);
1607 1607 return (0);
1608 1608 }
1609 1609
1610 1610 switch (scf_error()) {
1611 1611 case SCF_ERROR_BACKEND_ACCESS:
1612 1612 return (EACCES);
1613 1613
1614 1614 case SCF_ERROR_PERMISSION_DENIED:
1615 1615 return (EPERM);
1616 1616
1617 1617 default:
1618 1618 return (-1);
1619 1619 }
1620 1620 } else {
1621 1621 r = refresh_running_snapshot(entity);
1622 1622 switch (r) {
1623 1623 case 0:
1624 1624 break;
1625 1625
1626 1626 case ECONNABORTED:
1627 1627 case ECANCELED:
1628 1628 case EPERM:
1629 1629 case ENOSPC:
1630 1630 break;
1631 1631
1632 1632 default:
1633 1633 bad_error("refresh_running_snapshot",
1634 1634 scf_error());
1635 1635 }
1636 1636
1637 1637 return (r);
1638 1638 }
1639 1639 }
1640 1640
1641 1641 if (scf_iter_service_instances(iter, entity) != 0) {
1642 1642 switch (scf_error()) {
1643 1643 case SCF_ERROR_CONNECTION_BROKEN:
1644 1644 return (ECONNABORTED);
1645 1645
1646 1646 case SCF_ERROR_DELETED:
1647 1647 return (ECANCELED);
1648 1648
1649 1649 case SCF_ERROR_HANDLE_MISMATCH:
1650 1650 case SCF_ERROR_NOT_BOUND:
1651 1651 case SCF_ERROR_NOT_SET:
1652 1652 default:
1653 1653 bad_error("scf_iter_service_instances", scf_error());
1654 1654 }
1655 1655 }
1656 1656
1657 1657 for (;;) {
1658 1658 r = scf_iter_next_instance(iter, inst);
1659 1659 if (r == 0)
1660 1660 break;
1661 1661 if (r != 1) {
1662 1662 switch (scf_error()) {
1663 1663 case SCF_ERROR_CONNECTION_BROKEN:
1664 1664 return (ECONNABORTED);
1665 1665
1666 1666 case SCF_ERROR_DELETED:
1667 1667 return (ECANCELED);
1668 1668
1669 1669 case SCF_ERROR_HANDLE_MISMATCH:
1670 1670 case SCF_ERROR_NOT_BOUND:
1671 1671 case SCF_ERROR_NOT_SET:
1672 1672 case SCF_ERROR_INVALID_ARGUMENT:
1673 1673 default:
1674 1674 bad_error("scf_iter_next_instance",
1675 1675 scf_error());
1676 1676 }
1677 1677 }
1678 1678
1679 1679 /*
1680 1680 * Similarly, just take a new running snapshot if operating on
1681 1681 * a non-live repository or running during early import.
1682 1682 */
1683 1683 if (est->sc_repo_filename != NULL ||
1684 1684 est->sc_repo_doorname != NULL ||
1685 1685 est->sc_in_emi == 1) {
1686 1686 r = refresh_running_snapshot(inst);
1687 1687 switch (r) {
1688 1688 case 0:
1689 1689 continue;
1690 1690
1691 1691 case ECONNABORTED:
1692 1692 case ECANCELED:
1693 1693 case EPERM:
1694 1694 case ENOSPC:
1695 1695 break;
1696 1696 default:
1697 1697 bad_error("refresh_running_snapshot",
1698 1698 scf_error());
1699 1699 }
1700 1700
1701 1701 return (r);
1702 1702
1703 1703 }
1704 1704
1705 1705 if (_smf_refresh_instance_i(inst) == 0) {
1706 1706 if (g_verbose) {
1707 1707 if (scf_instance_get_name(inst, name_buf,
1708 1708 max_scf_name_len + 1) < 0)
1709 1709 (void) strcpy(name_buf, "?");
1710 1710
1711 1711 warn(gettext("Refreshed %s:%s.\n"),
1712 1712 fmri, name_buf);
1713 1713 }
1714 1714 } else {
1715 1715 if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1716 1716 g_verbose) {
1717 1717 scfe = scf_error();
1718 1718
1719 1719 if (scf_instance_to_fmri(inst, name_buf,
1720 1720 max_scf_name_len + 1) < 0)
1721 1721 (void) strcpy(name_buf, "?");
1722 1722
1723 1723 warn(gettext(
1724 1724 "Refresh of %s:%s failed: %s.\n"), fmri,
1725 1725 name_buf, scf_strerror(scfe));
1726 1726 }
1727 1727 }
1728 1728 }
1729 1729
1730 1730 return (0);
1731 1731 }
1732 1732
1733 1733 static void
1734 1734 private_refresh(void)
1735 1735 {
1736 1736 scf_instance_t *pinst = NULL;
1737 1737 scf_iter_t *piter = NULL;
1738 1738 ssize_t fmrilen;
1739 1739 size_t bufsz;
1740 1740 char *fmribuf;
1741 1741 void *ent;
1742 1742 int issvc;
1743 1743 int r;
1744 1744
1745 1745 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1746 1746 return;
1747 1747
1748 1748 assert(cur_svc != NULL);
1749 1749
1750 1750 bufsz = max_scf_fmri_len + 1;
1751 1751 fmribuf = safe_malloc(bufsz);
1752 1752 if (cur_inst) {
1753 1753 issvc = 0;
1754 1754 ent = cur_inst;
1755 1755 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1756 1756 } else {
1757 1757 issvc = 1;
1758 1758 ent = cur_svc;
1759 1759 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1760 1760 if ((pinst = scf_instance_create(g_hndl)) == NULL)
1761 1761 scfdie();
1762 1762
1763 1763 if ((piter = scf_iter_create(g_hndl)) == NULL)
1764 1764 scfdie();
1765 1765 }
1766 1766 if (fmrilen < 0) {
1767 1767 free(fmribuf);
1768 1768 if (scf_error() != SCF_ERROR_DELETED)
1769 1769 scfdie();
1770 1770
1771 1771 warn(emsg_deleted);
1772 1772 return;
1773 1773 }
1774 1774 assert(fmrilen < bufsz);
1775 1775
1776 1776 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1777 1777 switch (r) {
1778 1778 case 0:
1779 1779 break;
1780 1780
1781 1781 case ECONNABORTED:
1782 1782 warn(gettext("Could not refresh %s "
1783 1783 "(repository connection broken).\n"), fmribuf);
1784 1784 break;
1785 1785
1786 1786 case ECANCELED:
1787 1787 warn(emsg_deleted);
1788 1788 break;
1789 1789
1790 1790 case EPERM:
1791 1791 warn(gettext("Could not refresh %s "
1792 1792 "(permission denied).\n"), fmribuf);
1793 1793 break;
1794 1794
1795 1795 case ENOSPC:
1796 1796 warn(gettext("Could not refresh %s "
1797 1797 "(repository server out of resources).\n"),
1798 1798 fmribuf);
1799 1799 break;
1800 1800
1801 1801 case EACCES:
1802 1802 default:
1803 1803 bad_error("refresh_entity", scf_error());
1804 1804 }
1805 1805
1806 1806 if (issvc) {
1807 1807 scf_instance_destroy(pinst);
1808 1808 scf_iter_destroy(piter);
1809 1809 }
1810 1810
1811 1811 free(fmribuf);
1812 1812 }
1813 1813
1814 1814
1815 1815 static int
1816 1816 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1817 1817 {
1818 1818 cbp->sc_err = scferror2errno(err);
1819 1819 return (UU_WALK_ERROR);
1820 1820 }
1821 1821
1822 1822 static int
1823 1823 stash_scferror(scf_callback_t *cbp)
1824 1824 {
1825 1825 return (stash_scferror_err(cbp, scf_error()));
1826 1826 }
1827 1827
1828 1828 static int select_inst(const char *);
1829 1829 static int select_svc(const char *);
1830 1830
1831 1831 /*
1832 1832 * Take a property that does not have a type and check to see if a type
1833 1833 * exists or can be gleened from the current data. Set the type.
1834 1834 *
1835 1835 * Check the current level (instance) and then check the higher level
1836 1836 * (service). This could be the case for adding a new property to
1837 1837 * the instance that's going to "override" a service level property.
1838 1838 *
1839 1839 * For a property :
1840 1840 * 1. Take the type from an existing property
1841 1841 * 2. Take the type from a template entry
1842 1842 *
1843 1843 * If the type can not be found, then leave the type as is, and let the import
1844 1844 * report the problem of the missing type.
1845 1845 */
1846 1846 static int
1847 1847 find_current_prop_type(void *p, void *g)
1848 1848 {
1849 1849 property_t *prop = p;
1850 1850 scf_callback_t *lcb = g;
1851 1851 pgroup_t *pg = NULL;
1852 1852
1853 1853 const char *fmri = NULL;
1854 1854 char *lfmri = NULL;
1855 1855 char *cur_selection = NULL;
1856 1856
1857 1857 scf_propertygroup_t *sc_pg = NULL;
1858 1858 scf_property_t *sc_prop = NULL;
1859 1859 scf_pg_tmpl_t *t_pg = NULL;
1860 1860 scf_prop_tmpl_t *t_prop = NULL;
1861 1861 scf_type_t prop_type;
1862 1862
1863 1863 value_t *vp;
1864 1864 int issvc = lcb->sc_service;
1865 1865 int r = UU_WALK_ERROR;
1866 1866
1867 1867 if (prop->sc_value_type != SCF_TYPE_INVALID)
1868 1868 return (UU_WALK_NEXT);
1869 1869
1870 1870 t_prop = scf_tmpl_prop_create(g_hndl);
1871 1871 sc_prop = scf_property_create(g_hndl);
1872 1872 if (sc_prop == NULL || t_prop == NULL) {
1873 1873 warn(gettext("Unable to create the property to attempt and "
1874 1874 "find a missing type.\n"));
1875 1875
1876 1876 scf_property_destroy(sc_prop);
1877 1877 scf_tmpl_prop_destroy(t_prop);
1878 1878
1879 1879 return (UU_WALK_ERROR);
1880 1880 }
1881 1881
1882 1882 if (lcb->sc_flags == 1) {
1883 1883 pg = lcb->sc_parent;
1884 1884 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1885 1885 fmri = pg->sc_parent->sc_fmri;
1886 1886 retry_pg:
1887 1887 if (cur_svc && cur_selection == NULL) {
1888 1888 cur_selection = safe_malloc(max_scf_fmri_len + 1);
1889 1889 lscf_get_selection_str(cur_selection,
1890 1890 max_scf_fmri_len + 1);
1891 1891
1892 1892 if (strcmp(cur_selection, fmri) != 0) {
1893 1893 lscf_select(fmri);
1894 1894 } else {
1895 1895 free(cur_selection);
1896 1896 cur_selection = NULL;
1897 1897 }
1898 1898 } else {
1899 1899 lscf_select(fmri);
1900 1900 }
1901 1901
1902 1902 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1903 1903 warn(gettext("Unable to create property group to "
1904 1904 "find a missing property type.\n"));
1905 1905
1906 1906 goto out;
1907 1907 }
1908 1908
1909 1909 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1910 1910 /*
1911 1911 * If this is the sc_pg from the parent
1912 1912 * let the caller clean up the sc_pg,
1913 1913 * and just throw it away in this case.
1914 1914 */
1915 1915 if (sc_pg != lcb->sc_parent)
1916 1916 scf_pg_destroy(sc_pg);
1917 1917
1918 1918 sc_pg = NULL;
1919 1919 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1920 1920 warn(gettext("Unable to create template "
1921 1921 "property group to find a property "
1922 1922 "type.\n"));
1923 1923
1924 1924 goto out;
1925 1925 }
1926 1926
1927 1927 if (scf_tmpl_get_by_pg_name(fmri, NULL,
1928 1928 pg->sc_pgroup_name, NULL, t_pg,
1929 1929 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1930 1930 /*
1931 1931 * if instance get service and jump back
1932 1932 */
1933 1933 scf_tmpl_pg_destroy(t_pg);
1934 1934 t_pg = NULL;
1935 1935 if (issvc == 0) {
1936 1936 entity_t *e = pg->sc_parent->sc_parent;
1937 1937
1938 1938 fmri = e->sc_fmri;
1939 1939 issvc = 1;
1940 1940 goto retry_pg;
1941 1941 } else {
1942 1942 goto out;
1943 1943 }
1944 1944 }
1945 1945 }
1946 1946 } else {
1947 1947 sc_pg = lcb->sc_parent;
1948 1948 }
1949 1949
1950 1950 /*
1951 1951 * Attempt to get the type from an existing property. If the property
1952 1952 * cannot be found then attempt to get the type from a template entry
1953 1953 * for the property.
1954 1954 *
1955 1955 * Finally, if at the instance level look at the service level.
1956 1956 */
1957 1957 if (sc_pg != NULL &&
1958 1958 pg_get_prop(sc_pg, prop->sc_property_name,
1959 1959 sc_prop) == SCF_SUCCESS &&
1960 1960 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1961 1961 prop->sc_value_type = prop_type;
1962 1962
1963 1963 /*
1964 1964 * Found a type, update the value types and validate
1965 1965 * the actual value against this type.
1966 1966 */
1967 1967 for (vp = uu_list_first(prop->sc_property_values);
1968 1968 vp != NULL;
1969 1969 vp = uu_list_next(prop->sc_property_values, vp)) {
1970 1970 vp->sc_type = prop->sc_value_type;
1971 1971 lxml_store_value(vp, 0, NULL);
1972 1972 }
1973 1973
1974 1974 r = UU_WALK_NEXT;
1975 1975 goto out;
1976 1976 }
1977 1977
1978 1978 /*
1979 1979 * If we get here with t_pg set to NULL then we had to have
1980 1980 * gotten an sc_pg but that sc_pg did not have the property
1981 1981 * we are looking for. So if the t_pg is not null look up
1982 1982 * the template entry for the property.
1983 1983 *
1984 1984 * If the t_pg is null then need to attempt to get a matching
1985 1985 * template entry for the sc_pg, and see if there is a property
1986 1986 * entry for that template entry.
1987 1987 */
1988 1988 do_tmpl :
1989 1989 if (t_pg != NULL &&
1990 1990 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1991 1991 t_prop, 0) == SCF_SUCCESS) {
1992 1992 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1993 1993 prop->sc_value_type = prop_type;
1994 1994
1995 1995 /*
1996 1996 * Found a type, update the value types and validate
1997 1997 * the actual value against this type.
1998 1998 */
1999 1999 for (vp = uu_list_first(prop->sc_property_values);
2000 2000 vp != NULL;
2001 2001 vp = uu_list_next(prop->sc_property_values, vp)) {
2002 2002 vp->sc_type = prop->sc_value_type;
2003 2003 lxml_store_value(vp, 0, NULL);
2004 2004 }
2005 2005
2006 2006 r = UU_WALK_NEXT;
2007 2007 goto out;
2008 2008 }
2009 2009 } else {
2010 2010 if (t_pg == NULL && sc_pg) {
2011 2011 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2012 2012 warn(gettext("Unable to create template "
2013 2013 "property group to find a property "
2014 2014 "type.\n"));
2015 2015
2016 2016 goto out;
2017 2017 }
2018 2018
2019 2019 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2020 2020 scf_tmpl_pg_destroy(t_pg);
2021 2021 t_pg = NULL;
2022 2022 } else {
2023 2023 goto do_tmpl;
2024 2024 }
2025 2025 }
2026 2026 }
2027 2027
2028 2028 if (issvc == 0) {
2029 2029 scf_instance_t *i;
2030 2030 scf_service_t *s;
2031 2031
2032 2032 issvc = 1;
2033 2033 if (lcb->sc_flags == 1) {
2034 2034 entity_t *e = pg->sc_parent->sc_parent;
2035 2035
2036 2036 fmri = e->sc_fmri;
2037 2037 goto retry_pg;
2038 2038 }
2039 2039
2040 2040 /*
2041 2041 * because lcb->sc_flags was not set then this means
2042 2042 * the pg was not used and can be used here.
2043 2043 */
2044 2044 if ((pg = internal_pgroup_new()) == NULL) {
2045 2045 warn(gettext("Could not create internal property group "
2046 2046 "to find a missing type."));
2047 2047
2048 2048 goto out;
2049 2049 }
2050 2050
2051 2051 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2052 2052 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2053 2053 max_scf_name_len + 1) < 0)
2054 2054 goto out;
2055 2055
2056 2056 i = scf_instance_create(g_hndl);
2057 2057 s = scf_service_create(g_hndl);
2058 2058 if (i == NULL || s == NULL ||
2059 2059 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2060 2060 warn(gettext("Could not get a service for the instance "
2061 2061 "to find a missing type."));
2062 2062
2063 2063 goto out;
2064 2064 }
2065 2065
2066 2066 /*
2067 2067 * Check to see truly at the instance level.
2068 2068 */
2069 2069 lfmri = safe_malloc(max_scf_fmri_len + 1);
2070 2070 if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2071 2071 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2072 2072 goto out;
2073 2073 else
2074 2074 fmri = (const char *)lfmri;
2075 2075
2076 2076 goto retry_pg;
2077 2077 }
2078 2078
2079 2079 out :
2080 2080 if (sc_pg != lcb->sc_parent) {
2081 2081 scf_pg_destroy(sc_pg);
2082 2082 }
2083 2083
2084 2084 /*
2085 2085 * If this is true then the pg was allocated
2086 2086 * here, and the name was set so need to free
2087 2087 * the name and the pg.
2088 2088 */
2089 2089 if (pg != NULL && pg != lcb->sc_parent) {
2090 2090 free((char *)pg->sc_pgroup_name);
2091 2091 internal_pgroup_free(pg);
2092 2092 }
2093 2093
2094 2094 if (cur_selection) {
2095 2095 lscf_select(cur_selection);
2096 2096 free(cur_selection);
2097 2097 }
2098 2098
2099 2099 scf_tmpl_pg_destroy(t_pg);
2100 2100 scf_tmpl_prop_destroy(t_prop);
2101 2101 scf_property_destroy(sc_prop);
2102 2102
2103 2103 if (r != UU_WALK_NEXT)
2104 2104 warn(gettext("Could not find property type for \"%s\" "
2105 2105 "from \"%s\"\n"), prop->sc_property_name,
2106 2106 fmri != NULL ? fmri : lcb->sc_source_fmri);
2107 2107
2108 2108 free(lfmri);
2109 2109
2110 2110 return (r);
2111 2111 }
2112 2112
2113 2113 /*
2114 2114 * Take a property group that does not have a type and check to see if a type
2115 2115 * exists or can be gleened from the current data. Set the type.
2116 2116 *
2117 2117 * Check the current level (instance) and then check the higher level
2118 2118 * (service). This could be the case for adding a new property to
2119 2119 * the instance that's going to "override" a service level property.
2120 2120 *
2121 2121 * For a property group
2122 2122 * 1. Take the type from an existing property group
2123 2123 * 2. Take the type from a template entry
2124 2124 *
2125 2125 * If the type can not be found, then leave the type as is, and let the import
2126 2126 * report the problem of the missing type.
2127 2127 */
2128 2128 static int
2129 2129 find_current_pg_type(void *p, void *sori)
2130 2130 {
2131 2131 entity_t *si = sori;
2132 2132 pgroup_t *pg = p;
2133 2133
2134 2134 const char *ofmri, *fmri;
2135 2135 char *cur_selection = NULL;
2136 2136 char *pg_type = NULL;
2137 2137
2138 2138 scf_propertygroup_t *sc_pg = NULL;
2139 2139 scf_pg_tmpl_t *t_pg = NULL;
2140 2140
2141 2141 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2142 2142 int r = UU_WALK_ERROR;
2143 2143
2144 2144 ofmri = fmri = si->sc_fmri;
2145 2145 if (pg->sc_pgroup_type != NULL) {
2146 2146 r = UU_WALK_NEXT;
2147 2147
2148 2148 goto out;
2149 2149 }
2150 2150
2151 2151 sc_pg = scf_pg_create(g_hndl);
2152 2152 if (sc_pg == NULL) {
2153 2153 warn(gettext("Unable to create property group to attempt "
2154 2154 "and find a missing type.\n"));
2155 2155
2156 2156 return (UU_WALK_ERROR);
2157 2157 }
2158 2158
2159 2159 /*
2160 2160 * Using get_pg() requires that the cur_svc/cur_inst be
2161 2161 * via lscf_select. Need to preserve the current selection
2162 2162 * if going to use lscf_select() to set up the cur_svc/cur_inst
2163 2163 */
2164 2164 if (cur_svc) {
2165 2165 cur_selection = safe_malloc(max_scf_fmri_len + 1);
2166 2166 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2167 2167 }
2168 2168
2169 2169 /*
2170 2170 * If the property group exists get the type, and set
2171 2171 * the pgroup_t type of that type.
2172 2172 *
2173 2173 * If not the check for a template pg_pattern entry
2174 2174 * and take the type from that.
2175 2175 */
2176 2176 retry_svc:
2177 2177 lscf_select(fmri);
2178 2178
2179 2179 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2180 2180 pg_type = safe_malloc(max_scf_pg_type_len + 1);
2181 2181 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2182 2182 max_scf_pg_type_len + 1) != -1) {
2183 2183 pg->sc_pgroup_type = pg_type;
2184 2184
2185 2185 r = UU_WALK_NEXT;
2186 2186 goto out;
2187 2187 } else {
2188 2188 free(pg_type);
2189 2189 }
2190 2190 } else {
2191 2191 if ((t_pg == NULL) &&
2192 2192 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2193 2193 goto out;
2194 2194
2195 2195 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2196 2196 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2197 2197 scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2198 2198 pg->sc_pgroup_type = pg_type;
2199 2199
2200 2200 r = UU_WALK_NEXT;
2201 2201 goto out;
2202 2202 }
2203 2203 }
2204 2204
2205 2205 /*
2206 2206 * If type is not found at the instance level then attempt to
2207 2207 * find the type at the service level.
2208 2208 */
2209 2209 if (!issvc) {
2210 2210 si = si->sc_parent;
2211 2211 fmri = si->sc_fmri;
2212 2212 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2213 2213 goto retry_svc;
2214 2214 }
2215 2215
2216 2216 out :
2217 2217 if (cur_selection) {
2218 2218 lscf_select(cur_selection);
2219 2219 free(cur_selection);
2220 2220 }
2221 2221
2222 2222 /*
2223 2223 * Now walk the properties of the property group to make sure that
2224 2224 * all properties have the correct type and values are valid for
2225 2225 * those types.
2226 2226 */
2227 2227 if (r == UU_WALK_NEXT) {
2228 2228 scf_callback_t cb;
2229 2229
2230 2230 cb.sc_service = issvc;
2231 2231 cb.sc_source_fmri = ofmri;
2232 2232 if (sc_pg != NULL) {
2233 2233 cb.sc_parent = sc_pg;
2234 2234 cb.sc_flags = 0;
2235 2235 } else {
2236 2236 cb.sc_parent = pg;
2237 2237 cb.sc_flags = 1;
2238 2238 }
2239 2239
2240 2240 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2241 2241 &cb, UU_DEFAULT) != 0) {
2242 2242 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2243 2243 bad_error("uu_list_walk", uu_error());
2244 2244
2245 2245 r = UU_WALK_ERROR;
2246 2246 }
2247 2247 } else {
2248 2248 warn(gettext("Could not find property group type for "
2249 2249 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2250 2250 }
2251 2251
2252 2252 scf_tmpl_pg_destroy(t_pg);
2253 2253 scf_pg_destroy(sc_pg);
2254 2254
2255 2255 return (r);
2256 2256 }
2257 2257
2258 2258 /*
2259 2259 * Import. These functions import a bundle into the repository.
2260 2260 */
2261 2261
2262 2262 /*
2263 2263 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses
2264 2264 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success,
2265 2265 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2266 2266 * lcbdata->sc_err to
2267 2267 * ENOMEM - out of memory
2268 2268 * ECONNABORTED - repository connection broken
2269 2269 * ECANCELED - sc_trans's property group was deleted
2270 2270 * EINVAL - p's name is invalid (error printed)
2271 2271 * - p has an invalid value (error printed)
2272 2272 */
2273 2273 static int
2274 2274 lscf_property_import(void *v, void *pvt)
2275 2275 {
2276 2276 property_t *p = v;
2277 2277 scf_callback_t *lcbdata = pvt;
2278 2278 value_t *vp;
2279 2279 scf_transaction_t *trans = lcbdata->sc_trans;
2280 2280 scf_transaction_entry_t *entr;
2281 2281 scf_value_t *val;
2282 2282 scf_type_t tp;
2283 2283
2284 2284 if ((lcbdata->sc_flags & SCI_NOENABLED ||
2285 2285 lcbdata->sc_flags & SCI_DELAYENABLE) &&
2286 2286 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2287 2287 lcbdata->sc_enable = p;
2288 2288 return (UU_WALK_NEXT);
2289 2289 }
2290 2290
2291 2291 entr = scf_entry_create(lcbdata->sc_handle);
2292 2292 if (entr == NULL) {
2293 2293 switch (scf_error()) {
2294 2294 case SCF_ERROR_NO_MEMORY:
2295 2295 return (stash_scferror(lcbdata));
2296 2296
2297 2297 case SCF_ERROR_INVALID_ARGUMENT:
2298 2298 default:
2299 2299 bad_error("scf_entry_create", scf_error());
2300 2300 }
2301 2301 }
2302 2302
2303 2303 tp = p->sc_value_type;
2304 2304
2305 2305 if (scf_transaction_property_new(trans, entr,
2306 2306 p->sc_property_name, tp) != 0) {
2307 2307 switch (scf_error()) {
2308 2308 case SCF_ERROR_INVALID_ARGUMENT:
2309 2309 semerr(emsg_invalid_prop_name, p->sc_property_name);
2310 2310 scf_entry_destroy(entr);
2311 2311 return (stash_scferror(lcbdata));
2312 2312
2313 2313 case SCF_ERROR_EXISTS:
2314 2314 break;
2315 2315
2316 2316 case SCF_ERROR_DELETED:
2317 2317 case SCF_ERROR_CONNECTION_BROKEN:
2318 2318 scf_entry_destroy(entr);
2319 2319 return (stash_scferror(lcbdata));
2320 2320
2321 2321 case SCF_ERROR_NOT_BOUND:
2322 2322 case SCF_ERROR_HANDLE_MISMATCH:
2323 2323 case SCF_ERROR_NOT_SET:
2324 2324 default:
2325 2325 bad_error("scf_transaction_property_new", scf_error());
2326 2326 }
2327 2327
2328 2328 if (scf_transaction_property_change_type(trans, entr,
2329 2329 p->sc_property_name, tp) != 0) {
2330 2330 switch (scf_error()) {
2331 2331 case SCF_ERROR_DELETED:
2332 2332 case SCF_ERROR_CONNECTION_BROKEN:
2333 2333 scf_entry_destroy(entr);
2334 2334 return (stash_scferror(lcbdata));
2335 2335
2336 2336 case SCF_ERROR_INVALID_ARGUMENT:
2337 2337 semerr(emsg_invalid_prop_name,
2338 2338 p->sc_property_name);
2339 2339 scf_entry_destroy(entr);
2340 2340 return (stash_scferror(lcbdata));
2341 2341
2342 2342 case SCF_ERROR_NOT_FOUND:
2343 2343 case SCF_ERROR_NOT_SET:
2344 2344 case SCF_ERROR_HANDLE_MISMATCH:
2345 2345 case SCF_ERROR_NOT_BOUND:
2346 2346 default:
2347 2347 bad_error(
2348 2348 "scf_transaction_property_change_type",
2349 2349 scf_error());
2350 2350 }
2351 2351 }
2352 2352 }
2353 2353
2354 2354 for (vp = uu_list_first(p->sc_property_values);
2355 2355 vp != NULL;
2356 2356 vp = uu_list_next(p->sc_property_values, vp)) {
2357 2357 val = scf_value_create(g_hndl);
2358 2358 if (val == NULL) {
2359 2359 switch (scf_error()) {
2360 2360 case SCF_ERROR_NO_MEMORY:
2361 2361 return (stash_scferror(lcbdata));
2362 2362
2363 2363 case SCF_ERROR_INVALID_ARGUMENT:
2364 2364 default:
2365 2365 bad_error("scf_value_create", scf_error());
2366 2366 }
2367 2367 }
2368 2368
2369 2369 switch (tp) {
2370 2370 case SCF_TYPE_BOOLEAN:
2371 2371 scf_value_set_boolean(val, vp->sc_u.sc_count);
2372 2372 break;
2373 2373 case SCF_TYPE_COUNT:
2374 2374 scf_value_set_count(val, vp->sc_u.sc_count);
2375 2375 break;
2376 2376 case SCF_TYPE_INTEGER:
2377 2377 scf_value_set_integer(val, vp->sc_u.sc_integer);
2378 2378 break;
2379 2379 default:
2380 2380 assert(vp->sc_u.sc_string != NULL);
2381 2381 if (scf_value_set_from_string(val, tp,
2382 2382 vp->sc_u.sc_string) != 0) {
2383 2383 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2384 2384 bad_error("scf_value_set_from_string",
2385 2385 scf_error());
2386 2386
2387 2387 warn(gettext("Value \"%s\" is not a valid "
2388 2388 "%s.\n"), vp->sc_u.sc_string,
2389 2389 scf_type_to_string(tp));
2390 2390 scf_value_destroy(val);
2391 2391 return (stash_scferror(lcbdata));
2392 2392 }
2393 2393 break;
2394 2394 }
2395 2395
2396 2396 if (scf_entry_add_value(entr, val) != 0)
2397 2397 bad_error("scf_entry_add_value", scf_error());
2398 2398 }
2399 2399
2400 2400 return (UU_WALK_NEXT);
2401 2401 }
2402 2402
2403 2403 /*
2404 2404 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent,
2405 2405 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2406 2406 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2407 2407 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2408 2408 * lcbdata->sc_err to
2409 2409 * ECONNABORTED - repository connection broken
2410 2410 * ENOMEM - out of memory
2411 2411 * ENOSPC - svc.configd is out of resources
2412 2412 * ECANCELED - sc_parent was deleted
2413 2413 * EPERM - could not create property group (permission denied) (error printed)
2414 2414 * - could not modify property group (permission denied) (error printed)
2415 2415 * - could not delete property group (permission denied) (error printed)
2416 2416 * EROFS - could not create property group (repository is read-only)
2417 2417 * - could not delete property group (repository is read-only)
2418 2418 * EACCES - could not create property group (backend access denied)
2419 2419 * - could not delete property group (backend access denied)
2420 2420 * EEXIST - could not create property group (already exists)
2421 2421 * EINVAL - invalid property group name (error printed)
2422 2422 * - invalid property name (error printed)
2423 2423 * - invalid value (error printed)
2424 2424 * EBUSY - new property group deleted (error printed)
2425 2425 * - new property group changed (error printed)
2426 2426 * - property group added (error printed)
2427 2427 * - property group deleted (error printed)
2428 2428 */
2429 2429 static int
2430 2430 entity_pgroup_import(void *v, void *pvt)
2431 2431 {
2432 2432 pgroup_t *p = v;
2433 2433 scf_callback_t cbdata;
2434 2434 scf_callback_t *lcbdata = pvt;
2435 2435 void *ent = lcbdata->sc_parent;
2436 2436 int issvc = lcbdata->sc_service;
2437 2437 int r;
2438 2438
2439 2439 const char * const pg_changed = gettext("%s changed unexpectedly "
2440 2440 "(new property group \"%s\" changed).\n");
2441 2441
2442 2442 /* Never import deleted property groups. */
2443 2443 if (p->sc_pgroup_delete) {
2444 2444 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2445 2445 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2446 2446 goto delete_pg;
2447 2447 }
2448 2448 return (UU_WALK_NEXT);
2449 2449 }
2450 2450
2451 2451 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2452 2452 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2453 2453 lcbdata->sc_general = p;
2454 2454 return (UU_WALK_NEXT);
2455 2455 }
2456 2456
2457 2457 add_pg:
2458 2458 if (issvc)
2459 2459 r = scf_service_add_pg(ent, p->sc_pgroup_name,
2460 2460 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2461 2461 else
2462 2462 r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2463 2463 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2464 2464 if (r != 0) {
2465 2465 switch (scf_error()) {
2466 2466 case SCF_ERROR_DELETED:
2467 2467 case SCF_ERROR_CONNECTION_BROKEN:
2468 2468 case SCF_ERROR_BACKEND_READONLY:
2469 2469 case SCF_ERROR_BACKEND_ACCESS:
2470 2470 case SCF_ERROR_NO_RESOURCES:
2471 2471 return (stash_scferror(lcbdata));
2472 2472
2473 2473 case SCF_ERROR_EXISTS:
2474 2474 if (lcbdata->sc_flags & SCI_FORCE)
2475 2475 break;
2476 2476 return (stash_scferror(lcbdata));
2477 2477
2478 2478 case SCF_ERROR_INVALID_ARGUMENT:
2479 2479 warn(emsg_fmri_invalid_pg_name_type,
2480 2480 lcbdata->sc_source_fmri,
2481 2481 p->sc_pgroup_name, p->sc_pgroup_type);
2482 2482 return (stash_scferror(lcbdata));
2483 2483
2484 2484 case SCF_ERROR_PERMISSION_DENIED:
2485 2485 warn(emsg_pg_add_perm, p->sc_pgroup_name,
2486 2486 lcbdata->sc_target_fmri);
2487 2487 return (stash_scferror(lcbdata));
2488 2488
2489 2489 case SCF_ERROR_NOT_BOUND:
2490 2490 case SCF_ERROR_HANDLE_MISMATCH:
2491 2491 case SCF_ERROR_NOT_SET:
2492 2492 default:
2493 2493 bad_error("scf_service_add_pg", scf_error());
2494 2494 }
2495 2495
2496 2496 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2497 2497 switch (scf_error()) {
2498 2498 case SCF_ERROR_CONNECTION_BROKEN:
2499 2499 case SCF_ERROR_DELETED:
2500 2500 return (stash_scferror(lcbdata));
2501 2501
2502 2502 case SCF_ERROR_INVALID_ARGUMENT:
2503 2503 warn(emsg_fmri_invalid_pg_name,
2504 2504 lcbdata->sc_source_fmri,
2505 2505 p->sc_pgroup_name);
2506 2506 return (stash_scferror(lcbdata));
2507 2507
2508 2508 case SCF_ERROR_NOT_FOUND:
2509 2509 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2510 2510 p->sc_pgroup_name);
2511 2511 lcbdata->sc_err = EBUSY;
2512 2512 return (UU_WALK_ERROR);
2513 2513
2514 2514 case SCF_ERROR_NOT_BOUND:
2515 2515 case SCF_ERROR_HANDLE_MISMATCH:
2516 2516 case SCF_ERROR_NOT_SET:
2517 2517 default:
2518 2518 bad_error("entity_get_pg", scf_error());
2519 2519 }
2520 2520 }
2521 2521
2522 2522 if (lcbdata->sc_flags & SCI_KEEP)
2523 2523 goto props;
2524 2524
2525 2525 delete_pg:
2526 2526 if (scf_pg_delete(imp_pg) != 0) {
2527 2527 switch (scf_error()) {
2528 2528 case SCF_ERROR_DELETED:
2529 2529 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2530 2530 p->sc_pgroup_name);
2531 2531 lcbdata->sc_err = EBUSY;
2532 2532 return (UU_WALK_ERROR);
2533 2533
2534 2534 case SCF_ERROR_PERMISSION_DENIED:
2535 2535 warn(emsg_pg_del_perm, p->sc_pgroup_name,
2536 2536 lcbdata->sc_target_fmri);
2537 2537 return (stash_scferror(lcbdata));
2538 2538
2539 2539 case SCF_ERROR_BACKEND_READONLY:
2540 2540 case SCF_ERROR_BACKEND_ACCESS:
2541 2541 case SCF_ERROR_CONNECTION_BROKEN:
2542 2542 return (stash_scferror(lcbdata));
2543 2543
2544 2544 case SCF_ERROR_NOT_SET:
2545 2545 default:
2546 2546 bad_error("scf_pg_delete", scf_error());
2547 2547 }
2548 2548 }
2549 2549
2550 2550 if (p->sc_pgroup_delete)
2551 2551 return (UU_WALK_NEXT);
2552 2552
2553 2553 goto add_pg;
2554 2554 }
2555 2555
2556 2556 props:
2557 2557
2558 2558 /*
2559 2559 * Add properties to property group, if any.
2560 2560 */
2561 2561 cbdata.sc_handle = lcbdata->sc_handle;
2562 2562 cbdata.sc_parent = imp_pg;
2563 2563 cbdata.sc_flags = lcbdata->sc_flags;
2564 2564 cbdata.sc_trans = imp_tx;
2565 2565 cbdata.sc_enable = NULL;
2566 2566
2567 2567 if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2568 2568 switch (scf_error()) {
2569 2569 case SCF_ERROR_BACKEND_ACCESS:
2570 2570 case SCF_ERROR_BACKEND_READONLY:
2571 2571 case SCF_ERROR_CONNECTION_BROKEN:
2572 2572 return (stash_scferror(lcbdata));
2573 2573
2574 2574 case SCF_ERROR_DELETED:
2575 2575 warn(pg_changed, lcbdata->sc_target_fmri,
2576 2576 p->sc_pgroup_name);
2577 2577 lcbdata->sc_err = EBUSY;
2578 2578 return (UU_WALK_ERROR);
2579 2579
2580 2580 case SCF_ERROR_PERMISSION_DENIED:
2581 2581 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2582 2582 lcbdata->sc_target_fmri);
2583 2583 return (stash_scferror(lcbdata));
2584 2584
2585 2585 case SCF_ERROR_NOT_BOUND:
2586 2586 case SCF_ERROR_NOT_SET:
2587 2587 case SCF_ERROR_IN_USE:
2588 2588 case SCF_ERROR_HANDLE_MISMATCH:
2589 2589 default:
2590 2590 bad_error("scf_transaction_start", scf_error());
2591 2591 }
2592 2592 }
2593 2593
2594 2594 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2595 2595 UU_DEFAULT) != 0) {
2596 2596 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2597 2597 bad_error("uu_list_walk", uu_error());
2598 2598 scf_transaction_reset(imp_tx);
2599 2599
2600 2600 lcbdata->sc_err = cbdata.sc_err;
2601 2601 if (cbdata.sc_err == ECANCELED) {
2602 2602 warn(pg_changed, lcbdata->sc_target_fmri,
2603 2603 p->sc_pgroup_name);
2604 2604 lcbdata->sc_err = EBUSY;
2605 2605 }
2606 2606 return (UU_WALK_ERROR);
2607 2607 }
2608 2608
2609 2609 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2610 2610 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2611 2611
2612 2612 /*
2613 2613 * take the snapshot running snapshot then
2614 2614 * import the stored general/enable property
2615 2615 */
2616 2616 r = take_snap(ent, snap_running, imp_rsnap);
2617 2617 switch (r) {
2618 2618 case 0:
2619 2619 break;
2620 2620
2621 2621 case ECONNABORTED:
2622 2622 warn(gettext("Could not take %s snapshot on import "
2623 2623 "(repository connection broken).\n"),
2624 2624 snap_running);
2625 2625 lcbdata->sc_err = r;
2626 2626 return (UU_WALK_ERROR);
2627 2627 case ECANCELED:
2628 2628 warn(emsg_deleted);
2629 2629 lcbdata->sc_err = r;
2630 2630 return (UU_WALK_ERROR);
2631 2631
2632 2632 case EPERM:
2633 2633 warn(gettext("Could not take %s snapshot "
2634 2634 "(permission denied).\n"), snap_running);
2635 2635 lcbdata->sc_err = r;
2636 2636 return (UU_WALK_ERROR);
2637 2637
2638 2638 case ENOSPC:
2639 2639 warn(gettext("Could not take %s snapshot"
2640 2640 "(repository server out of resources).\n"),
2641 2641 snap_running);
2642 2642 lcbdata->sc_err = r;
2643 2643 return (UU_WALK_ERROR);
2644 2644
2645 2645 default:
2646 2646 bad_error("take_snap", r);
2647 2647 }
2648 2648
2649 2649 r = lscf_property_import(cbdata.sc_enable, &cbdata);
2650 2650 if (r != UU_WALK_NEXT) {
2651 2651 if (r != UU_WALK_ERROR)
2652 2652 bad_error("lscf_property_import", r);
2653 2653 return (EINVAL);
2654 2654 }
2655 2655 }
2656 2656
2657 2657 r = scf_transaction_commit(imp_tx);
2658 2658 switch (r) {
2659 2659 case 1:
2660 2660 r = UU_WALK_NEXT;
2661 2661 break;
2662 2662
2663 2663 case 0:
2664 2664 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2665 2665 lcbdata->sc_err = EBUSY;
2666 2666 r = UU_WALK_ERROR;
2667 2667 break;
2668 2668
2669 2669 case -1:
2670 2670 switch (scf_error()) {
2671 2671 case SCF_ERROR_BACKEND_READONLY:
2672 2672 case SCF_ERROR_BACKEND_ACCESS:
2673 2673 case SCF_ERROR_CONNECTION_BROKEN:
2674 2674 case SCF_ERROR_NO_RESOURCES:
2675 2675 r = stash_scferror(lcbdata);
2676 2676 break;
2677 2677
2678 2678 case SCF_ERROR_DELETED:
2679 2679 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2680 2680 p->sc_pgroup_name);
2681 2681 lcbdata->sc_err = EBUSY;
2682 2682 r = UU_WALK_ERROR;
2683 2683 break;
2684 2684
2685 2685 case SCF_ERROR_PERMISSION_DENIED:
2686 2686 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2687 2687 lcbdata->sc_target_fmri);
2688 2688 r = stash_scferror(lcbdata);
2689 2689 break;
2690 2690
2691 2691 case SCF_ERROR_NOT_SET:
2692 2692 case SCF_ERROR_INVALID_ARGUMENT:
2693 2693 case SCF_ERROR_NOT_BOUND:
2694 2694 default:
2695 2695 bad_error("scf_transaction_commit", scf_error());
2696 2696 }
2697 2697 break;
2698 2698
2699 2699 default:
2700 2700 bad_error("scf_transaction_commit", r);
2701 2701 }
2702 2702
2703 2703 scf_transaction_destroy_children(imp_tx);
2704 2704
2705 2705 return (r);
2706 2706 }
2707 2707
2708 2708 /*
2709 2709 * Returns
2710 2710 * 0 - success
2711 2711 * ECONNABORTED - repository connection broken
2712 2712 * ENOMEM - out of memory
2713 2713 * ENOSPC - svc.configd is out of resources
2714 2714 * ECANCELED - inst was deleted
2715 2715 * EPERM - could not create property group (permission denied) (error printed)
2716 2716 * - could not modify property group (permission denied) (error printed)
2717 2717 * EROFS - could not create property group (repository is read-only)
2718 2718 * EACCES - could not create property group (backend access denied)
2719 2719 * EEXIST - could not create property group (already exists)
2720 2720 * EINVAL - invalid property group name (error printed)
2721 2721 * - invalid property name (error printed)
2722 2722 * - invalid value (error printed)
2723 2723 * EBUSY - new property group changed (error printed)
2724 2724 */
2725 2725 static int
2726 2726 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2727 2727 const entity_t *isvc, int flags)
2728 2728 {
2729 2729 scf_callback_t cbdata;
2730 2730
2731 2731 cbdata.sc_handle = scf_service_handle(svc);
2732 2732 cbdata.sc_parent = svc;
2733 2733 cbdata.sc_service = 1;
2734 2734 cbdata.sc_general = 0;
2735 2735 cbdata.sc_enable = 0;
2736 2736 cbdata.sc_flags = flags;
2737 2737 cbdata.sc_source_fmri = isvc->sc_fmri;
2738 2738 cbdata.sc_target_fmri = target_fmri;
2739 2739
2740 2740 /*
2741 2741 * If the op is set, then add the flag to the callback
2742 2742 * flags for later use.
2743 2743 */
2744 2744 if (isvc->sc_op != SVCCFG_OP_NONE) {
2745 2745 switch (isvc->sc_op) {
2746 2746 case SVCCFG_OP_IMPORT :
2747 2747 cbdata.sc_flags |= SCI_OP_IMPORT;
2748 2748 break;
2749 2749 case SVCCFG_OP_APPLY :
2750 2750 cbdata.sc_flags |= SCI_OP_APPLY;
2751 2751 break;
2752 2752 case SVCCFG_OP_RESTORE :
2753 2753 cbdata.sc_flags |= SCI_OP_RESTORE;
2754 2754 break;
2755 2755 default :
2756 2756 uu_die(gettext("lscf_import_service_pgs : "
2757 2757 "Unknown op stored in the service entity\n"));
2758 2758
2759 2759 }
2760 2760 }
2761 2761
2762 2762 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2763 2763 UU_DEFAULT) != 0) {
2764 2764 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2765 2765 bad_error("uu_list_walk", uu_error());
2766 2766
2767 2767 return (cbdata.sc_err);
2768 2768 }
2769 2769
2770 2770 return (0);
2771 2771 }
2772 2772
2773 2773 /*
2774 2774 * Returns
2775 2775 * 0 - success
2776 2776 * ECONNABORTED - repository connection broken
2777 2777 * ENOMEM - out of memory
2778 2778 * ENOSPC - svc.configd is out of resources
2779 2779 * ECANCELED - inst was deleted
2780 2780 * EPERM - could not create property group (permission denied) (error printed)
2781 2781 * - could not modify property group (permission denied) (error printed)
2782 2782 * EROFS - could not create property group (repository is read-only)
2783 2783 * EACCES - could not create property group (backend access denied)
2784 2784 * EEXIST - could not create property group (already exists)
2785 2785 * EINVAL - invalid property group name (error printed)
2786 2786 * - invalid property name (error printed)
2787 2787 * - invalid value (error printed)
2788 2788 * EBUSY - new property group changed (error printed)
2789 2789 */
2790 2790 static int
2791 2791 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2792 2792 const entity_t *iinst, int flags)
2793 2793 {
2794 2794 scf_callback_t cbdata;
2795 2795
2796 2796 cbdata.sc_handle = scf_instance_handle(inst);
2797 2797 cbdata.sc_parent = inst;
2798 2798 cbdata.sc_service = 0;
2799 2799 cbdata.sc_general = NULL;
2800 2800 cbdata.sc_enable = NULL;
2801 2801 cbdata.sc_flags = flags;
2802 2802 cbdata.sc_source_fmri = iinst->sc_fmri;
2803 2803 cbdata.sc_target_fmri = target_fmri;
2804 2804
2805 2805 /*
2806 2806 * If the op is set, then add the flag to the callback
2807 2807 * flags for later use.
2808 2808 */
2809 2809 if (iinst->sc_op != SVCCFG_OP_NONE) {
2810 2810 switch (iinst->sc_op) {
2811 2811 case SVCCFG_OP_IMPORT :
2812 2812 cbdata.sc_flags |= SCI_OP_IMPORT;
2813 2813 break;
2814 2814 case SVCCFG_OP_APPLY :
2815 2815 cbdata.sc_flags |= SCI_OP_APPLY;
2816 2816 break;
2817 2817 case SVCCFG_OP_RESTORE :
2818 2818 cbdata.sc_flags |= SCI_OP_RESTORE;
2819 2819 break;
2820 2820 default :
2821 2821 uu_die(gettext("lscf_import_instance_pgs : "
2822 2822 "Unknown op stored in the instance entity\n"));
2823 2823 }
2824 2824 }
2825 2825
2826 2826 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2827 2827 UU_DEFAULT) != 0) {
2828 2828 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2829 2829 bad_error("uu_list_walk", uu_error());
2830 2830
2831 2831 return (cbdata.sc_err);
2832 2832 }
2833 2833
2834 2834 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2835 2835 cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2836 2836 /*
2837 2837 * If importing with the SCI_NOENABLED flag then
2838 2838 * skip the delay, but if not then add the delay
2839 2839 * of the enable property.
2840 2840 */
2841 2841 if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2842 2842 cbdata.sc_flags |= SCI_DELAYENABLE;
2843 2843 }
2844 2844
2845 2845 if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2846 2846 != UU_WALK_NEXT)
2847 2847 return (cbdata.sc_err);
2848 2848 }
2849 2849
2850 2850 return (0);
2851 2851 }
2852 2852
2853 2853 /*
2854 2854 * Report the reasons why we can't upgrade pg2 to pg1.
2855 2855 */
2856 2856 static void
2857 2857 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2858 2858 int new)
2859 2859 {
2860 2860 property_t *p1, *p2;
2861 2861
2862 2862 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2863 2863
2864 2864 if (!pg_attrs_equal(pg1, pg2, fmri, new))
2865 2865 return;
2866 2866
2867 2867 for (p1 = uu_list_first(pg1->sc_pgroup_props);
2868 2868 p1 != NULL;
2869 2869 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2870 2870 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2871 2871 if (p2 != NULL) {
2872 2872 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2873 2873 new);
2874 2874 continue;
2875 2875 }
2876 2876
2877 2877 if (new)
2878 2878 warn(gettext("Conflict upgrading %s (new property "
2879 2879 "group \"%s\" is missing property \"%s\").\n"),
2880 2880 fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2881 2881 else
2882 2882 warn(gettext("Conflict upgrading %s (property "
2883 2883 "\"%s/%s\" is missing).\n"), fmri,
2884 2884 pg1->sc_pgroup_name, p1->sc_property_name);
2885 2885 }
2886 2886
2887 2887 /*
2888 2888 * Since pg1 should be from the manifest, any properties in pg2 which
2889 2889 * aren't in pg1 shouldn't be reported as conflicts.
2890 2890 */
2891 2891 }
2892 2892
2893 2893 /*
2894 2894 * Add transaction entries to tx which will upgrade cur's pg according to old
2895 2895 * & new.
2896 2896 *
2897 2897 * Returns
2898 2898 * 0 - success
2899 2899 * EINVAL - new has a property with an invalid name or value (message emitted)
2900 2900 * ENOMEM - out of memory
2901 2901 */
2902 2902 static int
2903 2903 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2904 2904 pgroup_t *cur, int speak, const char *fmri)
2905 2905 {
2906 2906 property_t *p, *new_p, *cur_p;
2907 2907 scf_transaction_entry_t *e;
2908 2908 int r;
2909 2909 int is_general;
2910 2910 int is_protected;
2911 2911
2912 2912 if (uu_list_walk(new->sc_pgroup_props, clear_int,
2913 2913 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2914 2914 bad_error("uu_list_walk", uu_error());
2915 2915
2916 2916 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2917 2917
2918 2918 for (p = uu_list_first(old->sc_pgroup_props);
2919 2919 p != NULL;
2920 2920 p = uu_list_next(old->sc_pgroup_props, p)) {
2921 2921 /* p is a property in the old property group. */
2922 2922
2923 2923 /* Protect live properties. */
2924 2924 is_protected = 0;
2925 2925 if (is_general) {
2926 2926 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2927 2927 0 ||
2928 2928 strcmp(p->sc_property_name,
2929 2929 SCF_PROPERTY_RESTARTER) == 0)
2930 2930 is_protected = 1;
2931 2931 }
2932 2932
2933 2933 /* Look for the same property in the new properties. */
2934 2934 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2935 2935 if (new_p != NULL) {
2936 2936 new_p->sc_seen = 1;
2937 2937
2938 2938 /*
2939 2939 * If the new property is the same as the old, don't do
2940 2940 * anything (leave any user customizations).
2941 2941 */
2942 2942 if (prop_equal(p, new_p, NULL, NULL, 0))
2943 2943 continue;
2944 2944
2945 2945 if (new_p->sc_property_override)
2946 2946 goto upgrade;
2947 2947 }
2948 2948
2949 2949 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2950 2950 if (cur_p == NULL) {
2951 2951 /*
2952 2952 * p has been deleted from the repository. If we were
2953 2953 * going to delete it anyway, do nothing. Otherwise
2954 2954 * report a conflict.
2955 2955 */
2956 2956 if (new_p == NULL)
2957 2957 continue;
2958 2958
2959 2959 if (is_protected)
2960 2960 continue;
2961 2961
2962 2962 warn(gettext("Conflict upgrading %s "
2963 2963 "(property \"%s/%s\" is missing).\n"), fmri,
2964 2964 old->sc_pgroup_name, p->sc_property_name);
2965 2965 continue;
2966 2966 }
2967 2967
2968 2968 if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2969 2969 /*
2970 2970 * Conflict. Don't warn if the property is already the
2971 2971 * way we want it, though.
2972 2972 */
2973 2973 if (is_protected)
2974 2974 continue;
2975 2975
2976 2976 if (new_p == NULL)
2977 2977 (void) prop_equal(p, cur_p, fmri,
2978 2978 old->sc_pgroup_name, 0);
2979 2979 else
2980 2980 (void) prop_equal(cur_p, new_p, fmri,
2981 2981 old->sc_pgroup_name, 0);
2982 2982 continue;
2983 2983 }
2984 2984
2985 2985 if (is_protected) {
2986 2986 if (speak)
2987 2987 warn(gettext("%s: Refusing to upgrade "
2988 2988 "\"%s/%s\" (live property).\n"), fmri,
2989 2989 old->sc_pgroup_name, p->sc_property_name);
2990 2990 continue;
2991 2991 }
2992 2992
2993 2993 upgrade:
2994 2994 /* p hasn't been customized in the repository. Upgrade it. */
2995 2995 if (new_p == NULL) {
2996 2996 /* p was deleted. Delete from cur if unchanged. */
2997 2997 if (speak)
2998 2998 warn(gettext(
2999 2999 "%s: Deleting property \"%s/%s\".\n"),
3000 3000 fmri, old->sc_pgroup_name,
3001 3001 p->sc_property_name);
3002 3002
3003 3003 e = scf_entry_create(g_hndl);
3004 3004 if (e == NULL)
3005 3005 return (ENOMEM);
3006 3006
3007 3007 if (scf_transaction_property_delete(tx, e,
3008 3008 p->sc_property_name) != 0) {
3009 3009 switch (scf_error()) {
3010 3010 case SCF_ERROR_DELETED:
3011 3011 scf_entry_destroy(e);
3012 3012 return (ECANCELED);
3013 3013
3014 3014 case SCF_ERROR_CONNECTION_BROKEN:
3015 3015 scf_entry_destroy(e);
3016 3016 return (ECONNABORTED);
3017 3017
3018 3018 case SCF_ERROR_NOT_FOUND:
3019 3019 /*
3020 3020 * This can happen if cur is from the
3021 3021 * running snapshot (and it differs
3022 3022 * from the live properties).
3023 3023 */
3024 3024 scf_entry_destroy(e);
3025 3025 break;
3026 3026
3027 3027 case SCF_ERROR_HANDLE_MISMATCH:
3028 3028 case SCF_ERROR_NOT_BOUND:
3029 3029 case SCF_ERROR_NOT_SET:
3030 3030 case SCF_ERROR_INVALID_ARGUMENT:
3031 3031 default:
3032 3032 bad_error(
3033 3033 "scf_transaction_property_delete",
3034 3034 scf_error());
3035 3035 }
3036 3036 }
3037 3037 } else {
3038 3038 scf_callback_t ctx;
3039 3039
3040 3040 if (speak)
3041 3041 warn(gettext(
3042 3042 "%s: Upgrading property \"%s/%s\".\n"),
3043 3043 fmri, old->sc_pgroup_name,
3044 3044 p->sc_property_name);
3045 3045
3046 3046 ctx.sc_handle = g_hndl;
3047 3047 ctx.sc_trans = tx;
3048 3048 ctx.sc_flags = 0;
3049 3049
3050 3050 r = lscf_property_import(new_p, &ctx);
3051 3051 if (r != UU_WALK_NEXT) {
3052 3052 if (r != UU_WALK_ERROR)
3053 3053 bad_error("lscf_property_import", r);
3054 3054 return (EINVAL);
3055 3055 }
3056 3056 }
3057 3057 }
3058 3058
3059 3059 /* Go over the properties which were added. */
3060 3060 for (new_p = uu_list_first(new->sc_pgroup_props);
3061 3061 new_p != NULL;
3062 3062 new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3063 3063 if (new_p->sc_seen)
3064 3064 continue;
3065 3065
3066 3066 /* This is a new property. */
3067 3067 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3068 3068 if (cur_p == NULL) {
3069 3069 scf_callback_t ctx;
3070 3070
3071 3071 ctx.sc_handle = g_hndl;
3072 3072 ctx.sc_trans = tx;
3073 3073 ctx.sc_flags = 0;
3074 3074
3075 3075 r = lscf_property_import(new_p, &ctx);
3076 3076 if (r != UU_WALK_NEXT) {
3077 3077 if (r != UU_WALK_ERROR)
3078 3078 bad_error("lscf_property_import", r);
3079 3079 return (EINVAL);
3080 3080 }
3081 3081 continue;
3082 3082 }
3083 3083
3084 3084 /*
3085 3085 * Report a conflict if the new property differs from the
3086 3086 * current one. Unless it's general/enabled, since that's
3087 3087 * never in the last-import snapshot.
3088 3088 */
3089 3089 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3090 3090 0 &&
3091 3091 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3092 3092 continue;
3093 3093
3094 3094 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3095 3095 }
3096 3096
3097 3097 return (0);
3098 3098 }
3099 3099
3100 3100 /*
3101 3101 * Upgrade pg according to old & new.
3102 3102 *
3103 3103 * Returns
3104 3104 * 0 - success
3105 3105 * ECONNABORTED - repository connection broken
3106 3106 * ENOMEM - out of memory
3107 3107 * ENOSPC - svc.configd is out of resources
3108 3108 * ECANCELED - pg was deleted
3109 3109 * EPERM - couldn't modify pg (permission denied)
3110 3110 * EROFS - couldn't modify pg (backend read-only)
3111 3111 * EACCES - couldn't modify pg (backend access denied)
3112 3112 * EINVAL - new has a property with invalid name or value (error printed)
3113 3113 * EBUSY - pg changed unexpectedly
3114 3114 */
3115 3115 static int
3116 3116 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3117 3117 pgroup_t *new, int speak, const char *fmri)
3118 3118 {
3119 3119 int r;
3120 3120
3121 3121 if (scf_transaction_start(imp_tx, pg) != 0) {
3122 3122 switch (scf_error()) {
3123 3123 case SCF_ERROR_CONNECTION_BROKEN:
3124 3124 case SCF_ERROR_DELETED:
3125 3125 case SCF_ERROR_PERMISSION_DENIED:
3126 3126 case SCF_ERROR_BACKEND_READONLY:
3127 3127 case SCF_ERROR_BACKEND_ACCESS:
3128 3128 return (scferror2errno(scf_error()));
3129 3129
3130 3130 case SCF_ERROR_HANDLE_MISMATCH:
3131 3131 case SCF_ERROR_IN_USE:
3132 3132 case SCF_ERROR_NOT_BOUND:
3133 3133 case SCF_ERROR_NOT_SET:
3134 3134 default:
3135 3135 bad_error("scf_transaction_start", scf_error());
3136 3136 }
3137 3137 }
3138 3138
3139 3139 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3140 3140 switch (r) {
3141 3141 case 0:
3142 3142 break;
3143 3143
3144 3144 case EINVAL:
3145 3145 case ENOMEM:
3146 3146 scf_transaction_destroy_children(imp_tx);
3147 3147 return (r);
3148 3148
3149 3149 default:
3150 3150 bad_error("add_upgrade_entries", r);
3151 3151 }
3152 3152
3153 3153 r = scf_transaction_commit(imp_tx);
3154 3154
3155 3155 scf_transaction_destroy_children(imp_tx);
3156 3156
3157 3157 switch (r) {
3158 3158 case 1:
3159 3159 break;
3160 3160
3161 3161 case 0:
3162 3162 return (EBUSY);
3163 3163
3164 3164 case -1:
3165 3165 switch (scf_error()) {
3166 3166 case SCF_ERROR_CONNECTION_BROKEN:
3167 3167 case SCF_ERROR_NO_RESOURCES:
3168 3168 case SCF_ERROR_PERMISSION_DENIED:
3169 3169 case SCF_ERROR_BACKEND_READONLY:
3170 3170 case SCF_ERROR_BACKEND_ACCESS:
3171 3171 case SCF_ERROR_DELETED:
3172 3172 return (scferror2errno(scf_error()));
3173 3173
3174 3174 case SCF_ERROR_NOT_BOUND:
3175 3175 case SCF_ERROR_INVALID_ARGUMENT:
3176 3176 case SCF_ERROR_NOT_SET:
3177 3177 default:
3178 3178 bad_error("scf_transaction_commit", scf_error());
3179 3179 }
3180 3180
3181 3181 default:
3182 3182 bad_error("scf_transaction_commit", r);
3183 3183 }
3184 3184
3185 3185 return (0);
3186 3186 }
3187 3187
3188 3188 /*
3189 3189 * Compares two entity FMRIs. Returns
3190 3190 *
3191 3191 * 1 - equal
3192 3192 * 0 - not equal
3193 3193 * -1 - f1 is invalid or not an entity
3194 3194 * -2 - f2 is invalid or not an entity
3195 3195 */
3196 3196 static int
3197 3197 fmri_equal(const char *f1, const char *f2)
3198 3198 {
3199 3199 int r;
3200 3200 const char *s1, *i1, *pg1;
3201 3201 const char *s2, *i2, *pg2;
3202 3202
3203 3203 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3204 3204 return (-1);
3205 3205 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3206 3206 return (-1);
3207 3207
3208 3208 if (s1 == NULL || pg1 != NULL)
3209 3209 return (-1);
3210 3210
3211 3211 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3212 3212 return (-2);
3213 3213 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3214 3214 return (-2);
3215 3215
3216 3216 if (s2 == NULL || pg2 != NULL)
3217 3217 return (-2);
3218 3218
3219 3219 r = strcmp(s1, s2);
3220 3220 if (r != 0)
3221 3221 return (0);
3222 3222
3223 3223 if (i1 == NULL && i2 == NULL)
3224 3224 return (1);
3225 3225
3226 3226 if (i1 == NULL || i2 == NULL)
3227 3227 return (0);
3228 3228
3229 3229 return (strcmp(i1, i2) == 0);
3230 3230 }
3231 3231
3232 3232 /*
3233 3233 * Import a dependent by creating a dependency property group in the dependent
3234 3234 * entity. If lcbdata->sc_trans is set, assume it's been started on the
3235 3235 * dependents pg, and add an entry to create a new property for this
3236 3236 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3237 3237 *
3238 3238 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets
3239 3239 * lcbdata->sc_err to
3240 3240 * ECONNABORTED - repository connection broken
3241 3241 * ENOMEM - out of memory
3242 3242 * ENOSPC - configd is out of resources
3243 3243 * EINVAL - target is invalid (error printed)
3244 3244 * - target is not an entity (error printed)
3245 3245 * - dependent has invalid name (error printed)
3246 3246 * - invalid property name (error printed)
3247 3247 * - invalid value (error printed)
3248 3248 * - scope of target does not exist (error printed)
3249 3249 * EPERM - couldn't create target (permission denied) (error printed)
3250 3250 * - couldn't create dependency pg (permission denied) (error printed)
3251 3251 * - couldn't modify dependency pg (permission denied) (error printed)
3252 3252 * EROFS - couldn't create target (repository read-only)
3253 3253 * - couldn't create dependency pg (repository read-only)
3254 3254 * EACCES - couldn't create target (backend access denied)
3255 3255 * - couldn't create dependency pg (backend access denied)
3256 3256 * ECANCELED - sc_trans's pg was deleted
3257 3257 * EALREADY - property for dependent already exists in sc_trans's pg
3258 3258 * EEXIST - dependency pg already exists in target (error printed)
3259 3259 * EBUSY - target deleted (error printed)
3260 3260 * - property group changed during import (error printed)
3261 3261 */
3262 3262 static int
3263 3263 lscf_dependent_import(void *a1, void *pvt)
3264 3264 {
3265 3265 pgroup_t *pgrp = a1;
3266 3266 scf_callback_t *lcbdata = pvt;
3267 3267
3268 3268 int isservice;
3269 3269 int ret;
3270 3270 scf_transaction_entry_t *e;
3271 3271 scf_value_t *val;
3272 3272 scf_callback_t dependent_cbdata;
3273 3273 scf_error_t scfe;
3274 3274
3275 3275 /*
3276 3276 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if
3277 3277 * it's invalid, we fail before modifying the repository.
3278 3278 */
3279 3279 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3280 3280 &dependent_cbdata.sc_parent, &isservice);
3281 3281 switch (scfe) {
3282 3282 case SCF_ERROR_NONE:
3283 3283 break;
3284 3284
3285 3285 case SCF_ERROR_NO_MEMORY:
3286 3286 return (stash_scferror_err(lcbdata, scfe));
3287 3287
3288 3288 case SCF_ERROR_INVALID_ARGUMENT:
3289 3289 semerr(gettext("The FMRI for the \"%s\" dependent is "
3290 3290 "invalid.\n"), pgrp->sc_pgroup_name);
3291 3291 return (stash_scferror_err(lcbdata, scfe));
3292 3292
3293 3293 case SCF_ERROR_CONSTRAINT_VIOLATED:
3294 3294 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3295 3295 "specifies neither a service nor an instance.\n"),
3296 3296 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3297 3297 return (stash_scferror_err(lcbdata, scfe));
3298 3298
3299 3299 case SCF_ERROR_NOT_FOUND:
3300 3300 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3301 3301 &dependent_cbdata.sc_parent, &isservice);
3302 3302 switch (scfe) {
3303 3303 case SCF_ERROR_NONE:
3304 3304 break;
3305 3305
3306 3306 case SCF_ERROR_NO_MEMORY:
3307 3307 case SCF_ERROR_BACKEND_READONLY:
3308 3308 case SCF_ERROR_BACKEND_ACCESS:
3309 3309 return (stash_scferror_err(lcbdata, scfe));
3310 3310
3311 3311 case SCF_ERROR_NOT_FOUND:
3312 3312 semerr(gettext("The scope in FMRI \"%s\" for the "
3313 3313 "\"%s\" dependent does not exist.\n"),
3314 3314 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3315 3315 lcbdata->sc_err = EINVAL;
3316 3316 return (UU_WALK_ERROR);
3317 3317
3318 3318 case SCF_ERROR_PERMISSION_DENIED:
3319 3319 warn(gettext(
3320 3320 "Could not create %s (permission denied).\n"),
3321 3321 pgrp->sc_pgroup_fmri);
3322 3322 return (stash_scferror_err(lcbdata, scfe));
3323 3323
3324 3324 case SCF_ERROR_INVALID_ARGUMENT:
3325 3325 case SCF_ERROR_CONSTRAINT_VIOLATED:
3326 3326 default:
3327 3327 bad_error("create_entity", scfe);
3328 3328 }
3329 3329 break;
3330 3330
3331 3331 default:
3332 3332 bad_error("fmri_to_entity", scfe);
3333 3333 }
3334 3334
3335 3335 if (lcbdata->sc_trans != NULL) {
3336 3336 e = scf_entry_create(lcbdata->sc_handle);
3337 3337 if (e == NULL) {
3338 3338 if (scf_error() != SCF_ERROR_NO_MEMORY)
3339 3339 bad_error("scf_entry_create", scf_error());
3340 3340
3341 3341 entity_destroy(dependent_cbdata.sc_parent, isservice);
3342 3342 return (stash_scferror(lcbdata));
3343 3343 }
3344 3344
3345 3345 if (scf_transaction_property_new(lcbdata->sc_trans, e,
3346 3346 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3347 3347 switch (scf_error()) {
3348 3348 case SCF_ERROR_INVALID_ARGUMENT:
3349 3349 warn(gettext("Dependent of %s has invalid name "
3350 3350 "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3351 3351 pgrp->sc_pgroup_name);
3352 3352 /* FALLTHROUGH */
3353 3353
3354 3354 case SCF_ERROR_DELETED:
3355 3355 case SCF_ERROR_CONNECTION_BROKEN:
3356 3356 scf_entry_destroy(e);
3357 3357 entity_destroy(dependent_cbdata.sc_parent,
3358 3358 isservice);
3359 3359 return (stash_scferror(lcbdata));
3360 3360
3361 3361 case SCF_ERROR_EXISTS:
3362 3362 scf_entry_destroy(e);
3363 3363 entity_destroy(dependent_cbdata.sc_parent,
3364 3364 isservice);
3365 3365 lcbdata->sc_err = EALREADY;
3366 3366 return (UU_WALK_ERROR);
3367 3367
3368 3368 case SCF_ERROR_NOT_BOUND:
3369 3369 case SCF_ERROR_HANDLE_MISMATCH:
3370 3370 case SCF_ERROR_NOT_SET:
3371 3371 default:
3372 3372 bad_error("scf_transaction_property_new",
3373 3373 scf_error());
3374 3374 }
3375 3375 }
3376 3376
3377 3377 val = scf_value_create(lcbdata->sc_handle);
3378 3378 if (val == NULL) {
3379 3379 if (scf_error() != SCF_ERROR_NO_MEMORY)
3380 3380 bad_error("scf_value_create", scf_error());
3381 3381
3382 3382 entity_destroy(dependent_cbdata.sc_parent, isservice);
3383 3383 return (stash_scferror(lcbdata));
3384 3384 }
3385 3385
3386 3386 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3387 3387 pgrp->sc_pgroup_fmri) != 0)
3388 3388 /* invalid should have been caught above */
3389 3389 bad_error("scf_value_set_from_string", scf_error());
3390 3390
3391 3391 if (scf_entry_add_value(e, val) != 0)
3392 3392 bad_error("scf_entry_add_value", scf_error());
3393 3393 }
3394 3394
3395 3395 /* Add the property group to the target entity. */
3396 3396
3397 3397 dependent_cbdata.sc_handle = lcbdata->sc_handle;
3398 3398 dependent_cbdata.sc_flags = lcbdata->sc_flags;
3399 3399 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3400 3400 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3401 3401
3402 3402 ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3403 3403
3404 3404 entity_destroy(dependent_cbdata.sc_parent, isservice);
3405 3405
3406 3406 if (ret == UU_WALK_NEXT)
3407 3407 return (ret);
3408 3408
3409 3409 if (ret != UU_WALK_ERROR)
3410 3410 bad_error("entity_pgroup_import", ret);
3411 3411
3412 3412 switch (dependent_cbdata.sc_err) {
3413 3413 case ECANCELED:
3414 3414 warn(gettext("%s deleted unexpectedly.\n"),
3415 3415 pgrp->sc_pgroup_fmri);
3416 3416 lcbdata->sc_err = EBUSY;
3417 3417 break;
3418 3418
3419 3419 case EEXIST:
3420 3420 warn(gettext("Could not create \"%s\" dependency in %s "
3421 3421 "(already exists).\n"), pgrp->sc_pgroup_name,
3422 3422 pgrp->sc_pgroup_fmri);
3423 3423 /* FALLTHROUGH */
3424 3424
3425 3425 default:
3426 3426 lcbdata->sc_err = dependent_cbdata.sc_err;
3427 3427 }
3428 3428
3429 3429 return (UU_WALK_ERROR);
3430 3430 }
3431 3431
3432 3432 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3433 3433 const scf_snaplevel_t *, scf_transaction_t *);
3434 3434 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3435 3435 const pgroup_t *);
3436 3436
3437 3437 /*
3438 3438 * Upgrade uncustomized dependents of ent to those specified in ient. Read
3439 3439 * the current dependent targets from running (the snaplevel of a running
3440 3440 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3441 3441 * scf_instance_t * according to ient, otherwise). Draw the ancestral
3442 3442 * dependent targets and dependency properties from li_dpts_pg (the
3443 3443 * "dependents" property group in snpl) and snpl (the snaplevel which
3444 3444 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then
3445 3445 * snpl doesn't have a "dependents" property group, and any dependents in ient
3446 3446 * are new.
3447 3447 *
3448 3448 * Returns
3449 3449 * 0 - success
3450 3450 * ECONNABORTED - repository connection broken
3451 3451 * ENOMEM - out of memory
3452 3452 * ENOSPC - configd is out of resources
3453 3453 * ECANCELED - ent was deleted
3454 3454 * ENODEV - the entity containing li_dpts_pg was deleted
3455 3455 * EPERM - could not modify dependents pg (permission denied) (error printed)
3456 3456 * - couldn't upgrade dependent (permission denied) (error printed)
3457 3457 * - couldn't create dependent (permission denied) (error printed)
3458 3458 * EROFS - could not modify dependents pg (repository read-only)
3459 3459 * - couldn't upgrade dependent (repository read-only)
3460 3460 * - couldn't create dependent (repository read-only)
3461 3461 * EACCES - could not modify dependents pg (backend access denied)
3462 3462 * - could not upgrade dependent (backend access denied)
3463 3463 * - could not create dependent (backend access denied)
3464 3464 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3465 3465 * - dependent target deleted (error printed)
3466 3466 * - dependent pg changed (error printed)
3467 3467 * EINVAL - new dependent is invalid (error printed)
3468 3468 * EBADF - snpl is corrupt (error printed)
3469 3469 * - snpl has corrupt pg (error printed)
3470 3470 * - dependency pg in target is corrupt (error printed)
3471 3471 * - target has corrupt snapshot (error printed)
3472 3472 * EEXIST - dependency pg already existed in target service (error printed)
3473 3473 */
3474 3474 static int
3475 3475 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3476 3476 const scf_snaplevel_t *snpl, const entity_t *ient,
3477 3477 const scf_snaplevel_t *running, void *ent)
3478 3478 {
3479 3479 pgroup_t *new_dpt_pgroup;
3480 3480 scf_callback_t cbdata;
3481 3481 int r, unseen, tx_started = 0;
3482 3482 int have_cur_depts;
3483 3483
3484 3484 const char * const dependents = "dependents";
3485 3485
3486 3486 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3487 3487
3488 3488 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3489 3489 /* Nothing to do. */
3490 3490 return (0);
3491 3491
3492 3492 /* Fetch the current version of the "dependents" property group. */
3493 3493 have_cur_depts = 1;
3494 3494 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3495 3495 switch (scf_error()) {
3496 3496 case SCF_ERROR_NOT_FOUND:
3497 3497 break;
3498 3498
3499 3499 case SCF_ERROR_DELETED:
3500 3500 case SCF_ERROR_CONNECTION_BROKEN:
3501 3501 return (scferror2errno(scf_error()));
3502 3502
3503 3503 case SCF_ERROR_NOT_SET:
3504 3504 case SCF_ERROR_INVALID_ARGUMENT:
3505 3505 case SCF_ERROR_HANDLE_MISMATCH:
3506 3506 case SCF_ERROR_NOT_BOUND:
3507 3507 default:
3508 3508 bad_error("entity_get_pg", scf_error());
3509 3509 }
3510 3510
3511 3511 have_cur_depts = 0;
3512 3512 }
3513 3513
3514 3514 /* Fetch the running version of the "dependents" property group. */
3515 3515 ud_run_dpts_pg_set = 0;
3516 3516 if (running != NULL)
3517 3517 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3518 3518 else
3519 3519 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3520 3520 if (r == 0) {
3521 3521 ud_run_dpts_pg_set = 1;
3522 3522 } else {
3523 3523 switch (scf_error()) {
3524 3524 case SCF_ERROR_NOT_FOUND:
3525 3525 break;
3526 3526
3527 3527 case SCF_ERROR_DELETED:
3528 3528 case SCF_ERROR_CONNECTION_BROKEN:
3529 3529 return (scferror2errno(scf_error()));
3530 3530
3531 3531 case SCF_ERROR_NOT_SET:
3532 3532 case SCF_ERROR_INVALID_ARGUMENT:
3533 3533 case SCF_ERROR_HANDLE_MISMATCH:
3534 3534 case SCF_ERROR_NOT_BOUND:
3535 3535 default:
3536 3536 bad_error(running ? "scf_snaplevel_get_pg" :
3537 3537 "entity_get_pg", scf_error());
3538 3538 }
3539 3539 }
3540 3540
3541 3541 /*
3542 3542 * Clear the seen fields of the dependents, so we can tell which ones
3543 3543 * are new.
3544 3544 */
3545 3545 if (uu_list_walk(ient->sc_dependents, clear_int,
3546 3546 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3547 3547 bad_error("uu_list_walk", uu_error());
3548 3548
3549 3549 if (li_dpts_pg != NULL) {
3550 3550 /*
3551 3551 * Each property in li_dpts_pg represents a dependent tag in
3552 3552 * the old manifest. For each, call upgrade_dependent(),
3553 3553 * which will change ud_cur_depts_pg or dependencies in other
3554 3554 * services as appropriate. Note (a) that changes to
3555 3555 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3556 3556 * made en masse, and (b) it's ok if the entity doesn't have
3557 3557 * a current version of the "dependents" property group,
3558 3558 * because we'll just consider all dependents as customized
3559 3559 * (by being deleted).
3560 3560 */
3561 3561
3562 3562 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3563 3563 switch (scf_error()) {
3564 3564 case SCF_ERROR_DELETED:
3565 3565 return (ENODEV);
3566 3566
3567 3567 case SCF_ERROR_CONNECTION_BROKEN:
3568 3568 return (ECONNABORTED);
3569 3569
3570 3570 case SCF_ERROR_HANDLE_MISMATCH:
3571 3571 case SCF_ERROR_NOT_BOUND:
3572 3572 case SCF_ERROR_NOT_SET:
3573 3573 default:
3574 3574 bad_error("scf_iter_pg_properties",
3575 3575 scf_error());
3576 3576 }
3577 3577 }
3578 3578
3579 3579 if (have_cur_depts &&
3580 3580 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3581 3581 switch (scf_error()) {
3582 3582 case SCF_ERROR_BACKEND_ACCESS:
3583 3583 case SCF_ERROR_BACKEND_READONLY:
3584 3584 case SCF_ERROR_CONNECTION_BROKEN:
3585 3585 return (scferror2errno(scf_error()));
3586 3586
3587 3587 case SCF_ERROR_DELETED:
3588 3588 warn(emsg_pg_deleted, ient->sc_fmri,
3589 3589 dependents);
3590 3590 return (EBUSY);
3591 3591
3592 3592 case SCF_ERROR_PERMISSION_DENIED:
3593 3593 warn(emsg_pg_mod_perm, dependents,
3594 3594 ient->sc_fmri);
3595 3595 return (scferror2errno(scf_error()));
3596 3596
3597 3597 case SCF_ERROR_HANDLE_MISMATCH:
3598 3598 case SCF_ERROR_IN_USE:
3599 3599 case SCF_ERROR_NOT_BOUND:
3600 3600 case SCF_ERROR_NOT_SET:
3601 3601 default:
3602 3602 bad_error("scf_transaction_start", scf_error());
3603 3603 }
3604 3604 }
3605 3605 tx_started = have_cur_depts;
3606 3606
3607 3607 for (;;) {
3608 3608 r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3609 3609 if (r == 0)
3610 3610 break;
3611 3611 if (r == 1) {
3612 3612 r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3613 3613 tx_started ? ud_tx : NULL);
3614 3614 switch (r) {
3615 3615 case 0:
3616 3616 continue;
3617 3617
3618 3618 case ECONNABORTED:
3619 3619 case ENOMEM:
3620 3620 case ENOSPC:
3621 3621 case EBADF:
3622 3622 case EBUSY:
3623 3623 case EINVAL:
3624 3624 case EPERM:
3625 3625 case EROFS:
3626 3626 case EACCES:
3627 3627 case EEXIST:
3628 3628 break;
3629 3629
3630 3630 case ECANCELED:
3631 3631 r = ENODEV;
3632 3632 break;
3633 3633
3634 3634 default:
3635 3635 bad_error("upgrade_dependent", r);
3636 3636 }
3637 3637
3638 3638 if (tx_started)
3639 3639 scf_transaction_destroy_children(ud_tx);
3640 3640 return (r);
3641 3641 }
3642 3642 if (r != -1)
3643 3643 bad_error("scf_iter_next_property", r);
3644 3644
3645 3645 switch (scf_error()) {
3646 3646 case SCF_ERROR_DELETED:
3647 3647 r = ENODEV;
3648 3648 break;
3649 3649
3650 3650 case SCF_ERROR_CONNECTION_BROKEN:
3651 3651 r = ECONNABORTED;
3652 3652 break;
3653 3653
3654 3654 case SCF_ERROR_NOT_SET:
3655 3655 case SCF_ERROR_INVALID_ARGUMENT:
3656 3656 case SCF_ERROR_NOT_BOUND:
3657 3657 case SCF_ERROR_HANDLE_MISMATCH:
3658 3658 default:
3659 3659 bad_error("scf_iter_next_property",
3660 3660 scf_error());
3661 3661 }
3662 3662
3663 3663 if (tx_started)
3664 3664 scf_transaction_destroy_children(ud_tx);
3665 3665 return (r);
3666 3666 }
3667 3667 }
3668 3668
3669 3669 /* import unseen dependents */
3670 3670 unseen = 0;
3671 3671 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3672 3672 new_dpt_pgroup != NULL;
3673 3673 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3674 3674 new_dpt_pgroup)) {
3675 3675 if (!new_dpt_pgroup->sc_pgroup_seen) {
3676 3676 unseen = 1;
3677 3677 break;
3678 3678 }
3679 3679 }
3680 3680
3681 3681 /* If there are none, exit early. */
3682 3682 if (unseen == 0)
3683 3683 goto commit;
3684 3684
3685 3685 /* Set up for lscf_dependent_import() */
3686 3686 cbdata.sc_handle = g_hndl;
3687 3687 cbdata.sc_parent = ent;
3688 3688 cbdata.sc_service = issvc;
3689 3689 cbdata.sc_flags = 0;
3690 3690
3691 3691 if (!have_cur_depts) {
3692 3692 /*
3693 3693 * We have new dependents to import, so we need a "dependents"
3694 3694 * property group.
3695 3695 */
3696 3696 if (issvc)
3697 3697 r = scf_service_add_pg(ent, dependents,
3698 3698 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3699 3699 else
3700 3700 r = scf_instance_add_pg(ent, dependents,
3701 3701 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3702 3702 if (r != 0) {
3703 3703 switch (scf_error()) {
3704 3704 case SCF_ERROR_DELETED:
3705 3705 case SCF_ERROR_CONNECTION_BROKEN:
3706 3706 case SCF_ERROR_BACKEND_READONLY:
3707 3707 case SCF_ERROR_BACKEND_ACCESS:
3708 3708 case SCF_ERROR_NO_RESOURCES:
3709 3709 return (scferror2errno(scf_error()));
3710 3710
3711 3711 case SCF_ERROR_EXISTS:
3712 3712 warn(emsg_pg_added, ient->sc_fmri, dependents);
3713 3713 return (EBUSY);
3714 3714
3715 3715 case SCF_ERROR_PERMISSION_DENIED:
3716 3716 warn(emsg_pg_add_perm, dependents,
3717 3717 ient->sc_fmri);
3718 3718 return (scferror2errno(scf_error()));
3719 3719
3720 3720 case SCF_ERROR_NOT_BOUND:
3721 3721 case SCF_ERROR_HANDLE_MISMATCH:
3722 3722 case SCF_ERROR_INVALID_ARGUMENT:
3723 3723 case SCF_ERROR_NOT_SET:
3724 3724 default:
3725 3725 bad_error("scf_service_add_pg", scf_error());
3726 3726 }
3727 3727 }
3728 3728 }
3729 3729
3730 3730 cbdata.sc_trans = ud_tx;
3731 3731
3732 3732 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3733 3733 switch (scf_error()) {
3734 3734 case SCF_ERROR_CONNECTION_BROKEN:
3735 3735 case SCF_ERROR_BACKEND_ACCESS:
3736 3736 case SCF_ERROR_BACKEND_READONLY:
3737 3737 return (scferror2errno(scf_error()));
3738 3738
3739 3739 case SCF_ERROR_DELETED:
3740 3740 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3741 3741 return (EBUSY);
3742 3742
3743 3743 case SCF_ERROR_PERMISSION_DENIED:
3744 3744 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3745 3745 return (scferror2errno(scf_error()));
3746 3746
3747 3747 case SCF_ERROR_HANDLE_MISMATCH:
3748 3748 case SCF_ERROR_IN_USE:
3749 3749 case SCF_ERROR_NOT_BOUND:
3750 3750 case SCF_ERROR_NOT_SET:
3751 3751 default:
3752 3752 bad_error("scf_transaction_start", scf_error());
3753 3753 }
3754 3754 }
3755 3755 tx_started = 1;
3756 3756
3757 3757 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3758 3758 new_dpt_pgroup != NULL;
3759 3759 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3760 3760 new_dpt_pgroup)) {
3761 3761 if (new_dpt_pgroup->sc_pgroup_seen)
3762 3762 continue;
3763 3763
3764 3764 if (ud_run_dpts_pg_set) {
3765 3765 /*
3766 3766 * If the dependent is already there, then we have
3767 3767 * a conflict.
3768 3768 */
3769 3769 if (scf_pg_get_property(ud_run_dpts_pg,
3770 3770 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3771 3771 r = handle_dependent_conflict(ient, ud_prop,
3772 3772 new_dpt_pgroup);
3773 3773 switch (r) {
3774 3774 case 0:
3775 3775 continue;
3776 3776
3777 3777 case ECONNABORTED:
3778 3778 case ENOMEM:
3779 3779 case EBUSY:
3780 3780 case EBADF:
3781 3781 case EINVAL:
3782 3782 scf_transaction_destroy_children(ud_tx);
3783 3783 return (r);
3784 3784
3785 3785 default:
3786 3786 bad_error("handle_dependent_conflict",
3787 3787 r);
3788 3788 }
3789 3789 } else {
3790 3790 switch (scf_error()) {
3791 3791 case SCF_ERROR_NOT_FOUND:
3792 3792 break;
3793 3793
3794 3794 case SCF_ERROR_INVALID_ARGUMENT:
3795 3795 warn(emsg_fmri_invalid_pg_name,
3796 3796 ient->sc_fmri,
3797 3797 new_dpt_pgroup->sc_pgroup_name);
3798 3798 scf_transaction_destroy_children(ud_tx);
3799 3799 return (EINVAL);
3800 3800
3801 3801 case SCF_ERROR_DELETED:
3802 3802 warn(emsg_pg_deleted, ient->sc_fmri,
3803 3803 new_dpt_pgroup->sc_pgroup_name);
3804 3804 scf_transaction_destroy_children(ud_tx);
3805 3805 return (EBUSY);
3806 3806
3807 3807 case SCF_ERROR_CONNECTION_BROKEN:
3808 3808 scf_transaction_destroy_children(ud_tx);
3809 3809 return (ECONNABORTED);
3810 3810
3811 3811 case SCF_ERROR_NOT_BOUND:
3812 3812 case SCF_ERROR_HANDLE_MISMATCH:
3813 3813 case SCF_ERROR_NOT_SET:
3814 3814 default:
3815 3815 bad_error("scf_pg_get_property",
3816 3816 scf_error());
3817 3817 }
3818 3818 }
3819 3819 }
3820 3820
3821 3821 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3822 3822 if (r != UU_WALK_NEXT) {
3823 3823 if (r != UU_WALK_ERROR)
3824 3824 bad_error("lscf_dependent_import", r);
3825 3825
3826 3826 if (cbdata.sc_err == EALREADY) {
3827 3827 /* Collisions were handled preemptively. */
3828 3828 bad_error("lscf_dependent_import",
3829 3829 cbdata.sc_err);
3830 3830 }
3831 3831
3832 3832 scf_transaction_destroy_children(ud_tx);
3833 3833 return (cbdata.sc_err);
3834 3834 }
3835 3835 }
3836 3836
3837 3837 commit:
3838 3838 if (!tx_started)
3839 3839 return (0);
3840 3840
3841 3841 r = scf_transaction_commit(ud_tx);
3842 3842
3843 3843 scf_transaction_destroy_children(ud_tx);
3844 3844
3845 3845 switch (r) {
3846 3846 case 1:
3847 3847 return (0);
3848 3848
3849 3849 case 0:
3850 3850 warn(emsg_pg_changed, ient->sc_fmri, dependents);
3851 3851 return (EBUSY);
3852 3852
3853 3853 case -1:
3854 3854 break;
3855 3855
3856 3856 default:
3857 3857 bad_error("scf_transaction_commit", r);
3858 3858 }
3859 3859
3860 3860 switch (scf_error()) {
3861 3861 case SCF_ERROR_CONNECTION_BROKEN:
3862 3862 case SCF_ERROR_BACKEND_READONLY:
3863 3863 case SCF_ERROR_BACKEND_ACCESS:
3864 3864 case SCF_ERROR_NO_RESOURCES:
3865 3865 return (scferror2errno(scf_error()));
3866 3866
3867 3867 case SCF_ERROR_DELETED:
3868 3868 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3869 3869 return (EBUSY);
3870 3870
3871 3871 case SCF_ERROR_PERMISSION_DENIED:
3872 3872 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3873 3873 return (scferror2errno(scf_error()));
3874 3874
3875 3875 case SCF_ERROR_NOT_BOUND:
3876 3876 case SCF_ERROR_INVALID_ARGUMENT:
3877 3877 case SCF_ERROR_NOT_SET:
3878 3878 default:
3879 3879 bad_error("scf_transaction_destroy", scf_error());
3880 3880 /* NOTREACHED */
3881 3881 }
3882 3882 }
3883 3883
3884 3884 /*
3885 3885 * Used to add the manifests to the list of currently supported manifests.
3886 3886 * We can modify the existing manifest list removing entries if the files
3887 3887 * don't exist.
3888 3888 *
3889 3889 * Get the old list and the new file name
3890 3890 * If the new file name is in the list return
3891 3891 * If not then add the file to the list.
3892 3892 * As we process the list check to see if the files in the old list exist
3893 3893 * if not then remove the file from the list.
3894 3894 * Commit the list of manifest file names.
3895 3895 *
3896 3896 */
3897 3897 static int
3898 3898 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient,
3899 3899 const scf_snaplevel_t *running, void *ent)
3900 3900 {
3901 3901 scf_propertygroup_t *ud_mfsts_pg = NULL;
3902 3902 scf_property_t *ud_prop = NULL;
3903 3903 scf_iter_t *ud_prop_iter;
3904 3904 scf_value_t *fname_value;
3905 3905 scf_callback_t cbdata;
3906 3906 pgroup_t *mfst_pgroup;
3907 3907 property_t *mfst_prop;
3908 3908 property_t *old_prop;
3909 3909 char *pname;
3910 3910 char *fval;
3911 3911 char *old_pname;
3912 3912 char *old_fval;
3913 3913 int no_upgrade_pg;
3914 3914 int mfst_seen;
3915 3915 int r;
3916 3916
3917 3917 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3918 3918
3919 3919 /*
3920 3920 * This should always be the service base on the code
3921 3921 * path, and the fact that the manifests pg is a service
3922 3922 * level property group only.
3923 3923 */
3924 3924 ud_mfsts_pg = scf_pg_create(g_hndl);
3925 3925 ud_prop = scf_property_create(g_hndl);
3926 3926 ud_prop_iter = scf_iter_create(g_hndl);
3927 3927 fname_value = scf_value_create(g_hndl);
3928 3928
3929 3929 /* Fetch the "manifests" property group */
3930 3930 no_upgrade_pg = 0;
3931 3931 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3932 3932 ud_mfsts_pg);
3933 3933 if (r != 0) {
3934 3934 switch (scf_error()) {
3935 3935 case SCF_ERROR_NOT_FOUND:
3936 3936 no_upgrade_pg = 1;
3937 3937 break;
3938 3938
3939 3939 case SCF_ERROR_DELETED:
3940 3940 case SCF_ERROR_CONNECTION_BROKEN:
3941 3941 return (scferror2errno(scf_error()));
3942 3942
3943 3943 case SCF_ERROR_NOT_SET:
3944 3944 case SCF_ERROR_INVALID_ARGUMENT:
3945 3945 case SCF_ERROR_HANDLE_MISMATCH:
3946 3946 case SCF_ERROR_NOT_BOUND:
3947 3947 default:
3948 3948 bad_error(running ? "scf_snaplevel_get_pg" :
3949 3949 "entity_get_pg", scf_error());
3950 3950 }
3951 3951 }
3952 3952
3953 3953 if (no_upgrade_pg) {
3954 3954 cbdata.sc_handle = g_hndl;
3955 3955 cbdata.sc_parent = ent;
3956 3956 cbdata.sc_service = issvc;
3957 3957 cbdata.sc_flags = SCI_FORCE;
3958 3958 cbdata.sc_source_fmri = ient->sc_fmri;
3959 3959 cbdata.sc_target_fmri = ient->sc_fmri;
3960 3960
3961 3961 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3962 3962 return (cbdata.sc_err);
3963 3963
3964 3964 return (0);
3965 3965 }
3966 3966
3967 3967 /* Fetch the new manifests property group */
3968 3968 for (mfst_pgroup = uu_list_first(ient->sc_pgroups);
3969 3969 mfst_pgroup != NULL;
3970 3970 mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) {
3971 3971 if (strcmp(mfst_pgroup->sc_pgroup_name,
3972 3972 SCF_PG_MANIFESTFILES) == 0)
3973 3973 break;
3974 3974 }
3975 3975
3976 3976 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3977 3977 SCF_SUCCESS)
3978 3978 return (-1);
3979 3979
3980 3980 if ((pname = malloc(MAXPATHLEN)) == NULL)
3981 3981 return (ENOMEM);
3982 3982 if ((fval = malloc(MAXPATHLEN)) == NULL) {
3983 3983 free(pname);
3984 3984 return (ENOMEM);
3985 3985 }
3986 3986
3987 3987 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3988 3988 mfst_seen = 0;
3989 3989 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3990 3990 continue;
3991 3991
3992 3992 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3993 3993 mfst_prop != NULL;
3994 3994 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3995 3995 mfst_prop)) {
3996 3996 if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3997 3997 mfst_seen = 1;
3998 3998 }
3999 3999 }
4000 4000
4001 4001 /*
4002 4002 * If the manifest is not seen then add it to the new mfst
4003 4003 * property list to get proccessed into the repo.
4004 4004 */
4005 4005 if (mfst_seen == 0) {
4006 4006 /*
4007 4007 * If we cannot get the value then there is no
4008 4008 * reason to attempt to attach the value to
4009 4009 * the property group
4010 4010 */
4011 4011 if (prop_get_val(ud_prop, fname_value) == 0 &&
4012 4012 scf_value_get_astring(fname_value, fval,
4013 4013 MAXPATHLEN) != -1) {
4014 4014 old_pname = safe_strdup(pname);
4015 4015 old_fval = safe_strdup(fval);
4016 4016 old_prop = internal_property_create(old_pname,
4017 4017 SCF_TYPE_ASTRING, 1, old_fval);
4018 4018
4019 4019 /*
4020 4020 * Already checked to see if the property exists
4021 4021 * in the group, and it does not.
4022 4022 */
4023 4023 (void) internal_attach_property(mfst_pgroup,
4024 4024 old_prop);
4025 4025 }
4026 4026 }
4027 4027 }
4028 4028 free(pname);
4029 4029 free(fval);
4030 4030
4031 4031 cbdata.sc_handle = g_hndl;
4032 4032 cbdata.sc_parent = ent;
4033 4033 cbdata.sc_service = issvc;
4034 4034 cbdata.sc_flags = SCI_FORCE;
4035 4035 cbdata.sc_source_fmri = ient->sc_fmri;
4036 4036 cbdata.sc_target_fmri = ient->sc_fmri;
4037 4037
4038 4038 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4039 4039 return (cbdata.sc_err);
4040 4040
4041 4041 return (r);
4042 4042 }
4043 4043
4044 4044 /*
4045 4045 * prop is taken to be a property in the "dependents" property group of snpl,
4046 4046 * which is taken to be the snaplevel of a last-import snapshot corresponding
4047 4047 * to ient. If prop is a valid dependents property, upgrade the dependent it
4048 4048 * represents according to the repository & ient. If ud_run_dpts_pg_set is
4049 4049 * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4050 4050 * of the entity ient represents (possibly in the running snapshot). If it
4051 4051 * needs to be changed, an entry will be added to tx, if not NULL.
4052 4052 *
4053 4053 * Returns
4054 4054 * 0 - success
4055 4055 * ECONNABORTED - repository connection broken
4056 4056 * ENOMEM - out of memory
4057 4057 * ENOSPC - configd was out of resources
4058 4058 * ECANCELED - snpl's entity was deleted
4059 4059 * EINVAL - dependent target is invalid (error printed)
4060 4060 * - dependent is invalid (error printed)
4061 4061 * EBADF - snpl is corrupt (error printed)
4062 4062 * - snpl has corrupt pg (error printed)
4063 4063 * - dependency pg in target is corrupt (error printed)
4064 4064 * - running snapshot in dependent is missing snaplevel (error printed)
4065 4065 * EPERM - couldn't delete dependency pg (permission denied) (error printed)
4066 4066 * - couldn't create dependent (permission denied) (error printed)
4067 4067 * - couldn't modify dependent pg (permission denied) (error printed)
4068 4068 * EROFS - couldn't delete dependency pg (repository read-only)
4069 4069 * - couldn't create dependent (repository read-only)
4070 4070 * EACCES - couldn't delete dependency pg (backend access denied)
4071 4071 * - couldn't create dependent (backend access denied)
4072 4072 * EBUSY - ud_run_dpts_pg was deleted (error printed)
4073 4073 * - tx's pg was deleted (error printed)
4074 4074 * - dependent pg was changed or deleted (error printed)
4075 4075 * EEXIST - dependency pg already exists in new target (error printed)
4076 4076 */
4077 4077 static int
4078 4078 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4079 4079 const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4080 4080 {
4081 4081 pgroup_t pgrp;
4082 4082 scf_type_t ty;
4083 4083 pgroup_t *new_dpt_pgroup;
4084 4084 pgroup_t *old_dpt_pgroup = NULL;
4085 4085 pgroup_t *current_pg;
4086 4086 pgroup_t *dpt;
4087 4087 scf_callback_t cbdata;
4088 4088 int tissvc;
4089 4089 void *target_ent;
4090 4090 scf_error_t serr;
4091 4091 int r;
4092 4092 scf_transaction_entry_t *ent;
4093 4093
4094 4094 const char * const cf_inval = gettext("Conflict upgrading %s "
4095 4095 "(dependent \"%s\" has invalid dependents property).\n");
4096 4096 const char * const cf_missing = gettext("Conflict upgrading %s "
4097 4097 "(dependent \"%s\" is missing).\n");
4098 4098 const char * const cf_newdpg = gettext("Conflict upgrading %s "
4099 4099 "(dependent \"%s\" has new dependency property group).\n");
4100 4100 const char * const cf_newtarg = gettext("Conflict upgrading %s "
4101 4101 "(dependent \"%s\" has new target).\n");
4102 4102 const char * const li_corrupt =
4103 4103 gettext("%s: \"last-import\" snapshot is corrupt.\n");
4104 4104 const char * const upgrading =
4105 4105 gettext("%s: Upgrading dependent \"%s\".\n");
4106 4106 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4107 4107 "corrupt (missing snaplevel).\n");
4108 4108
4109 4109 if (scf_property_type(prop, &ty) != 0) {
4110 4110 switch (scf_error()) {
4111 4111 case SCF_ERROR_DELETED:
4112 4112 case SCF_ERROR_CONNECTION_BROKEN:
4113 4113 return (scferror2errno(scf_error()));
4114 4114
4115 4115 case SCF_ERROR_NOT_BOUND:
4116 4116 case SCF_ERROR_NOT_SET:
4117 4117 default:
4118 4118 bad_error("scf_property_type", scf_error());
4119 4119 }
4120 4120 }
4121 4121
4122 4122 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4123 4123 warn(li_corrupt, ient->sc_fmri);
4124 4124 return (EBADF);
4125 4125 }
4126 4126
4127 4127 /*
4128 4128 * prop represents a dependent in the old manifest. It is named after
4129 4129 * the dependent.
4130 4130 */
4131 4131 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4132 4132 switch (scf_error()) {
4133 4133 case SCF_ERROR_DELETED:
4134 4134 case SCF_ERROR_CONNECTION_BROKEN:
4135 4135 return (scferror2errno(scf_error()));
4136 4136
4137 4137 case SCF_ERROR_NOT_BOUND:
4138 4138 case SCF_ERROR_NOT_SET:
4139 4139 default:
4140 4140 bad_error("scf_property_get_name", scf_error());
4141 4141 }
4142 4142 }
4143 4143
4144 4144 /* See if it's in the new manifest. */
4145 4145 pgrp.sc_pgroup_name = ud_name;
4146 4146 new_dpt_pgroup =
4147 4147 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4148 4148
4149 4149 /* If it's not, delete it... if it hasn't been customized. */
4150 4150 if (new_dpt_pgroup == NULL) {
4151 4151 if (!ud_run_dpts_pg_set)
4152 4152 return (0);
4153 4153
4154 4154 if (scf_property_get_value(prop, ud_val) != 0) {
4155 4155 switch (scf_error()) {
4156 4156 case SCF_ERROR_NOT_FOUND:
4157 4157 case SCF_ERROR_CONSTRAINT_VIOLATED:
4158 4158 warn(li_corrupt, ient->sc_fmri);
4159 4159 return (EBADF);
4160 4160
4161 4161 case SCF_ERROR_DELETED:
4162 4162 case SCF_ERROR_CONNECTION_BROKEN:
4163 4163 return (scferror2errno(scf_error()));
4164 4164
4165 4165 case SCF_ERROR_HANDLE_MISMATCH:
4166 4166 case SCF_ERROR_NOT_BOUND:
4167 4167 case SCF_ERROR_NOT_SET:
4168 4168 case SCF_ERROR_PERMISSION_DENIED:
4169 4169 default:
4170 4170 bad_error("scf_property_get_value",
4171 4171 scf_error());
4172 4172 }
4173 4173 }
4174 4174
4175 4175 if (scf_value_get_as_string(ud_val, ud_oldtarg,
4176 4176 max_scf_value_len + 1) < 0)
4177 4177 bad_error("scf_value_get_as_string", scf_error());
4178 4178
4179 4179 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4180 4180 0) {
4181 4181 switch (scf_error()) {
4182 4182 case SCF_ERROR_NOT_FOUND:
4183 4183 return (0);
4184 4184
4185 4185 case SCF_ERROR_CONNECTION_BROKEN:
4186 4186 return (scferror2errno(scf_error()));
4187 4187
4188 4188 case SCF_ERROR_DELETED:
4189 4189 warn(emsg_pg_deleted, ient->sc_fmri,
4190 4190 "dependents");
4191 4191 return (EBUSY);
4192 4192
4193 4193 case SCF_ERROR_INVALID_ARGUMENT:
4194 4194 case SCF_ERROR_NOT_BOUND:
4195 4195 case SCF_ERROR_HANDLE_MISMATCH:
4196 4196 case SCF_ERROR_NOT_SET:
4197 4197 default:
4198 4198 bad_error("scf_pg_get_property", scf_error());
4199 4199 }
4200 4200 }
4201 4201 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4202 4202 switch (scf_error()) {
4203 4203 case SCF_ERROR_NOT_FOUND:
4204 4204 case SCF_ERROR_CONSTRAINT_VIOLATED:
4205 4205 warn(cf_inval, ient->sc_fmri, ud_name);
4206 4206 return (0);
4207 4207
4208 4208 case SCF_ERROR_DELETED:
4209 4209 case SCF_ERROR_CONNECTION_BROKEN:
4210 4210 return (scferror2errno(scf_error()));
4211 4211
4212 4212 case SCF_ERROR_HANDLE_MISMATCH:
4213 4213 case SCF_ERROR_NOT_BOUND:
4214 4214 case SCF_ERROR_NOT_SET:
4215 4215 case SCF_ERROR_PERMISSION_DENIED:
4216 4216 default:
4217 4217 bad_error("scf_property_get_value",
4218 4218 scf_error());
4219 4219 }
4220 4220 }
4221 4221
4222 4222 ty = scf_value_type(ud_val);
4223 4223 assert(ty != SCF_TYPE_INVALID);
4224 4224 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4225 4225 warn(cf_inval, ient->sc_fmri, ud_name);
4226 4226 return (0);
4227 4227 }
4228 4228
4229 4229 if (scf_value_get_as_string(ud_val, ud_ctarg,
4230 4230 max_scf_value_len + 1) < 0)
4231 4231 bad_error("scf_value_get_as_string", scf_error());
4232 4232
4233 4233 r = fmri_equal(ud_ctarg, ud_oldtarg);
4234 4234 switch (r) {
4235 4235 case 1:
4236 4236 break;
4237 4237
4238 4238 case 0:
4239 4239 case -1: /* warn? */
4240 4240 warn(cf_newtarg, ient->sc_fmri, ud_name);
4241 4241 return (0);
4242 4242
4243 4243 case -2:
4244 4244 warn(li_corrupt, ient->sc_fmri);
4245 4245 return (EBADF);
4246 4246
4247 4247 default:
4248 4248 bad_error("fmri_equal", r);
4249 4249 }
4250 4250
4251 4251 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4252 4252 switch (scf_error()) {
4253 4253 case SCF_ERROR_NOT_FOUND:
4254 4254 warn(li_corrupt, ient->sc_fmri);
4255 4255 return (EBADF);
4256 4256
4257 4257 case SCF_ERROR_DELETED:
4258 4258 case SCF_ERROR_CONNECTION_BROKEN:
4259 4259 return (scferror2errno(scf_error()));
4260 4260
4261 4261 case SCF_ERROR_NOT_BOUND:
4262 4262 case SCF_ERROR_HANDLE_MISMATCH:
4263 4263 case SCF_ERROR_INVALID_ARGUMENT:
4264 4264 case SCF_ERROR_NOT_SET:
4265 4265 default:
4266 4266 bad_error("scf_snaplevel_get_pg", scf_error());
4267 4267 }
4268 4268 }
4269 4269
4270 4270 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4271 4271 snap_lastimport);
4272 4272 switch (r) {
4273 4273 case 0:
4274 4274 break;
4275 4275
4276 4276 case ECANCELED:
4277 4277 case ECONNABORTED:
4278 4278 case ENOMEM:
4279 4279 case EBADF:
4280 4280 return (r);
4281 4281
4282 4282 case EACCES:
4283 4283 default:
4284 4284 bad_error("load_pg", r);
4285 4285 }
4286 4286
4287 4287 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4288 4288 switch (serr) {
4289 4289 case SCF_ERROR_NONE:
4290 4290 break;
4291 4291
4292 4292 case SCF_ERROR_NO_MEMORY:
4293 4293 internal_pgroup_free(old_dpt_pgroup);
4294 4294 return (ENOMEM);
4295 4295
4296 4296 case SCF_ERROR_NOT_FOUND:
4297 4297 internal_pgroup_free(old_dpt_pgroup);
4298 4298 goto delprop;
4299 4299
4300 4300 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */
4301 4301 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
4302 4302 default:
4303 4303 bad_error("fmri_to_entity", serr);
4304 4304 }
4305 4305
4306 4306 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4307 4307 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4308 4308 switch (r) {
4309 4309 case 0:
4310 4310 break;
4311 4311
4312 4312 case ECONNABORTED:
4313 4313 internal_pgroup_free(old_dpt_pgroup);
4314 4314 return (r);
4315 4315
4316 4316 case ECANCELED:
4317 4317 case ENOENT:
4318 4318 internal_pgroup_free(old_dpt_pgroup);
4319 4319 goto delprop;
4320 4320
4321 4321 case EBADF:
4322 4322 warn(r_no_lvl, ud_ctarg);
4323 4323 internal_pgroup_free(old_dpt_pgroup);
4324 4324 return (r);
4325 4325
4326 4326 case EINVAL:
4327 4327 default:
4328 4328 bad_error("entity_get_running_pg", r);
4329 4329 }
4330 4330
4331 4331 /* load it */
4332 4332 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4333 4333 switch (r) {
4334 4334 case 0:
4335 4335 break;
4336 4336
4337 4337 case ECANCELED:
4338 4338 internal_pgroup_free(old_dpt_pgroup);
4339 4339 goto delprop;
4340 4340
4341 4341 case ECONNABORTED:
4342 4342 case ENOMEM:
4343 4343 case EBADF:
4344 4344 internal_pgroup_free(old_dpt_pgroup);
4345 4345 return (r);
4346 4346
4347 4347 case EACCES:
4348 4348 default:
4349 4349 bad_error("load_pg", r);
4350 4350 }
4351 4351
4352 4352 /* compare property groups */
4353 4353 if (!pg_equal(old_dpt_pgroup, current_pg)) {
4354 4354 warn(cf_newdpg, ient->sc_fmri, ud_name);
4355 4355 internal_pgroup_free(old_dpt_pgroup);
4356 4356 internal_pgroup_free(current_pg);
4357 4357 return (0);
4358 4358 }
4359 4359
4360 4360 internal_pgroup_free(old_dpt_pgroup);
4361 4361 internal_pgroup_free(current_pg);
4362 4362
4363 4363 if (g_verbose)
4364 4364 warn(gettext("%s: Deleting dependent \"%s\".\n"),
4365 4365 ient->sc_fmri, ud_name);
4366 4366
4367 4367 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4368 4368 switch (scf_error()) {
4369 4369 case SCF_ERROR_NOT_FOUND:
4370 4370 case SCF_ERROR_DELETED:
4371 4371 internal_pgroup_free(old_dpt_pgroup);
4372 4372 goto delprop;
4373 4373
4374 4374 case SCF_ERROR_CONNECTION_BROKEN:
4375 4375 internal_pgroup_free(old_dpt_pgroup);
4376 4376 return (ECONNABORTED);
4377 4377
4378 4378 case SCF_ERROR_NOT_SET:
4379 4379 case SCF_ERROR_INVALID_ARGUMENT:
4380 4380 case SCF_ERROR_HANDLE_MISMATCH:
4381 4381 case SCF_ERROR_NOT_BOUND:
4382 4382 default:
4383 4383 bad_error("entity_get_pg", scf_error());
4384 4384 }
4385 4385 }
4386 4386
4387 4387 if (scf_pg_delete(ud_pg) != 0) {
4388 4388 switch (scf_error()) {
4389 4389 case SCF_ERROR_DELETED:
4390 4390 break;
4391 4391
4392 4392 case SCF_ERROR_CONNECTION_BROKEN:
4393 4393 case SCF_ERROR_BACKEND_READONLY:
4394 4394 case SCF_ERROR_BACKEND_ACCESS:
4395 4395 return (scferror2errno(scf_error()));
4396 4396
4397 4397 case SCF_ERROR_PERMISSION_DENIED:
4398 4398 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4399 4399 return (scferror2errno(scf_error()));
4400 4400
4401 4401 case SCF_ERROR_NOT_SET:
4402 4402 default:
4403 4403 bad_error("scf_pg_delete", scf_error());
4404 4404 }
4405 4405 }
4406 4406
4407 4407 /*
4408 4408 * This service was changed, so it must be refreshed. But
4409 4409 * since it's not mentioned in the new manifest, we have to
4410 4410 * record its FMRI here for use later. We record the name
4411 4411 * & the entity (via sc_parent) in case we need to print error
4412 4412 * messages during the refresh.
4413 4413 */
4414 4414 dpt = internal_pgroup_new();
4415 4415 if (dpt == NULL)
4416 4416 return (ENOMEM);
4417 4417 dpt->sc_pgroup_name = strdup(ud_name);
4418 4418 dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4419 4419 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4420 4420 return (ENOMEM);
4421 4421 dpt->sc_parent = (entity_t *)ient;
4422 4422 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4423 4423 uu_die(gettext("libuutil error: %s\n"),
4424 4424 uu_strerror(uu_error()));
4425 4425
4426 4426 delprop:
4427 4427 if (tx == NULL)
4428 4428 return (0);
4429 4429
4430 4430 ent = scf_entry_create(g_hndl);
4431 4431 if (ent == NULL)
4432 4432 return (ENOMEM);
4433 4433
4434 4434 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4435 4435 scf_entry_destroy(ent);
4436 4436 switch (scf_error()) {
4437 4437 case SCF_ERROR_DELETED:
4438 4438 warn(emsg_pg_deleted, ient->sc_fmri,
4439 4439 "dependents");
4440 4440 return (EBUSY);
4441 4441
4442 4442 case SCF_ERROR_CONNECTION_BROKEN:
4443 4443 return (scferror2errno(scf_error()));
4444 4444
4445 4445 case SCF_ERROR_NOT_FOUND:
4446 4446 break;
4447 4447
4448 4448 case SCF_ERROR_HANDLE_MISMATCH:
4449 4449 case SCF_ERROR_NOT_BOUND:
4450 4450 case SCF_ERROR_INVALID_ARGUMENT:
4451 4451 case SCF_ERROR_NOT_SET:
4452 4452 default:
4453 4453 bad_error("scf_transaction_property_delete",
4454 4454 scf_error());
4455 4455 }
4456 4456 }
4457 4457
4458 4458 return (0);
4459 4459 }
4460 4460
4461 4461 new_dpt_pgroup->sc_pgroup_seen = 1;
4462 4462
4463 4463 /*
4464 4464 * Decide whether the dependent has changed in the manifest.
4465 4465 */
4466 4466 /* Compare the target. */
4467 4467 if (scf_property_get_value(prop, ud_val) != 0) {
4468 4468 switch (scf_error()) {
4469 4469 case SCF_ERROR_NOT_FOUND:
4470 4470 case SCF_ERROR_CONSTRAINT_VIOLATED:
4471 4471 warn(li_corrupt, ient->sc_fmri);
4472 4472 return (EBADF);
4473 4473
4474 4474 case SCF_ERROR_DELETED:
4475 4475 case SCF_ERROR_CONNECTION_BROKEN:
4476 4476 return (scferror2errno(scf_error()));
4477 4477
4478 4478 case SCF_ERROR_HANDLE_MISMATCH:
4479 4479 case SCF_ERROR_NOT_BOUND:
4480 4480 case SCF_ERROR_NOT_SET:
4481 4481 case SCF_ERROR_PERMISSION_DENIED:
4482 4482 default:
4483 4483 bad_error("scf_property_get_value", scf_error());
4484 4484 }
4485 4485 }
4486 4486
4487 4487 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4488 4488 0)
4489 4489 bad_error("scf_value_get_as_string", scf_error());
4490 4490
4491 4491 /*
4492 4492 * If the fmri's are not equal then the old fmri will need to
4493 4493 * be refreshed to ensure that the changes are properly updated
4494 4494 * in that service.
4495 4495 */
4496 4496 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4497 4497 switch (r) {
4498 4498 case 0:
4499 4499 dpt = internal_pgroup_new();
4500 4500 if (dpt == NULL)
4501 4501 return (ENOMEM);
4502 4502 dpt->sc_pgroup_name = strdup(ud_name);
4503 4503 dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4504 4504 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4505 4505 return (ENOMEM);
4506 4506 dpt->sc_parent = (entity_t *)ient;
4507 4507 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4508 4508 uu_die(gettext("libuutil error: %s\n"),
4509 4509 uu_strerror(uu_error()));
4510 4510 break;
4511 4511
4512 4512 case 1:
4513 4513 /* Compare the dependency pgs. */
4514 4514 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4515 4515 switch (scf_error()) {
4516 4516 case SCF_ERROR_NOT_FOUND:
4517 4517 warn(li_corrupt, ient->sc_fmri);
4518 4518 return (EBADF);
4519 4519
4520 4520 case SCF_ERROR_DELETED:
4521 4521 case SCF_ERROR_CONNECTION_BROKEN:
4522 4522 return (scferror2errno(scf_error()));
4523 4523
4524 4524 case SCF_ERROR_NOT_BOUND:
4525 4525 case SCF_ERROR_HANDLE_MISMATCH:
4526 4526 case SCF_ERROR_INVALID_ARGUMENT:
4527 4527 case SCF_ERROR_NOT_SET:
4528 4528 default:
4529 4529 bad_error("scf_snaplevel_get_pg", scf_error());
4530 4530 }
4531 4531 }
4532 4532
4533 4533 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4534 4534 snap_lastimport);
4535 4535 switch (r) {
4536 4536 case 0:
4537 4537 break;
4538 4538
4539 4539 case ECANCELED:
4540 4540 case ECONNABORTED:
4541 4541 case ENOMEM:
4542 4542 case EBADF:
4543 4543 return (r);
4544 4544
4545 4545 case EACCES:
4546 4546 default:
4547 4547 bad_error("load_pg", r);
4548 4548 }
4549 4549
4550 4550 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4551 4551 /* no change, leave customizations */
4552 4552 internal_pgroup_free(old_dpt_pgroup);
4553 4553 return (0);
4554 4554 }
4555 4555 break;
4556 4556
4557 4557 case -1:
4558 4558 warn(li_corrupt, ient->sc_fmri);
4559 4559 return (EBADF);
4560 4560
4561 4561 case -2:
4562 4562 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4563 4563 ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4564 4564 return (EINVAL);
4565 4565
4566 4566 default:
4567 4567 bad_error("fmri_equal", r);
4568 4568 }
4569 4569
4570 4570 /*
4571 4571 * The dependent has changed in the manifest. Upgrade the current
4572 4572 * properties if they haven't been customized.
4573 4573 */
4574 4574
4575 4575 /*
4576 4576 * If new_dpt_pgroup->sc_override, then act as though the property
4577 4577 * group hasn't been customized.
4578 4578 */
4579 4579 if (new_dpt_pgroup->sc_pgroup_override) {
4580 4580 (void) strcpy(ud_ctarg, ud_oldtarg);
4581 4581 goto nocust;
4582 4582 }
4583 4583
4584 4584 if (!ud_run_dpts_pg_set) {
4585 4585 warn(cf_missing, ient->sc_fmri, ud_name);
4586 4586 r = 0;
4587 4587 goto out;
4588 4588 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4589 4589 switch (scf_error()) {
4590 4590 case SCF_ERROR_NOT_FOUND:
4591 4591 warn(cf_missing, ient->sc_fmri, ud_name);
4592 4592 r = 0;
4593 4593 goto out;
4594 4594
4595 4595 case SCF_ERROR_CONNECTION_BROKEN:
4596 4596 r = scferror2errno(scf_error());
4597 4597 goto out;
4598 4598
4599 4599 case SCF_ERROR_DELETED:
4600 4600 warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4601 4601 r = EBUSY;
4602 4602 goto out;
4603 4603
4604 4604 case SCF_ERROR_INVALID_ARGUMENT:
4605 4605 case SCF_ERROR_NOT_BOUND:
4606 4606 case SCF_ERROR_HANDLE_MISMATCH:
4607 4607 case SCF_ERROR_NOT_SET:
4608 4608 default:
4609 4609 bad_error("scf_pg_get_property", scf_error());
4610 4610 }
4611 4611 }
4612 4612
4613 4613 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4614 4614 switch (scf_error()) {
4615 4615 case SCF_ERROR_NOT_FOUND:
4616 4616 case SCF_ERROR_CONSTRAINT_VIOLATED:
4617 4617 warn(cf_inval, ient->sc_fmri, ud_name);
4618 4618 r = 0;
4619 4619 goto out;
4620 4620
4621 4621 case SCF_ERROR_DELETED:
4622 4622 case SCF_ERROR_CONNECTION_BROKEN:
4623 4623 r = scferror2errno(scf_error());
4624 4624 goto out;
4625 4625
4626 4626 case SCF_ERROR_HANDLE_MISMATCH:
4627 4627 case SCF_ERROR_NOT_BOUND:
4628 4628 case SCF_ERROR_NOT_SET:
4629 4629 case SCF_ERROR_PERMISSION_DENIED:
4630 4630 default:
4631 4631 bad_error("scf_property_get_value", scf_error());
4632 4632 }
4633 4633 }
4634 4634
4635 4635 ty = scf_value_type(ud_val);
4636 4636 assert(ty != SCF_TYPE_INVALID);
4637 4637 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4638 4638 warn(cf_inval, ient->sc_fmri, ud_name);
4639 4639 r = 0;
4640 4640 goto out;
4641 4641 }
4642 4642 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4643 4643 0)
4644 4644 bad_error("scf_value_get_as_string", scf_error());
4645 4645
4646 4646 r = fmri_equal(ud_ctarg, ud_oldtarg);
4647 4647 if (r == -1) {
4648 4648 warn(cf_inval, ient->sc_fmri, ud_name);
4649 4649 r = 0;
4650 4650 goto out;
4651 4651 } else if (r == -2) {
4652 4652 warn(li_corrupt, ient->sc_fmri);
4653 4653 r = EBADF;
4654 4654 goto out;
4655 4655 } else if (r == 0) {
4656 4656 /*
4657 4657 * Target has been changed. Only abort now if it's been
4658 4658 * changed to something other than what's in the manifest.
4659 4659 */
4660 4660 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4661 4661 if (r == -1) {
4662 4662 warn(cf_inval, ient->sc_fmri, ud_name);
4663 4663 r = 0;
4664 4664 goto out;
4665 4665 } else if (r == 0) {
4666 4666 warn(cf_newtarg, ient->sc_fmri, ud_name);
4667 4667 r = 0;
4668 4668 goto out;
4669 4669 } else if (r != 1) {
4670 4670 /* invalid sc_pgroup_fmri caught above */
4671 4671 bad_error("fmri_equal", r);
4672 4672 }
4673 4673
4674 4674 /*
4675 4675 * Fetch the current dependency pg. If it's what the manifest
4676 4676 * says, then no problem.
4677 4677 */
4678 4678 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4679 4679 switch (serr) {
4680 4680 case SCF_ERROR_NONE:
4681 4681 break;
4682 4682
4683 4683 case SCF_ERROR_NOT_FOUND:
4684 4684 warn(cf_missing, ient->sc_fmri, ud_name);
4685 4685 r = 0;
4686 4686 goto out;
4687 4687
4688 4688 case SCF_ERROR_NO_MEMORY:
4689 4689 r = ENOMEM;
4690 4690 goto out;
4691 4691
4692 4692 case SCF_ERROR_CONSTRAINT_VIOLATED:
4693 4693 case SCF_ERROR_INVALID_ARGUMENT:
4694 4694 default:
4695 4695 bad_error("fmri_to_entity", serr);
4696 4696 }
4697 4697
4698 4698 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4699 4699 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4700 4700 switch (r) {
4701 4701 case 0:
4702 4702 break;
4703 4703
4704 4704 case ECONNABORTED:
4705 4705 goto out;
4706 4706
4707 4707 case ECANCELED:
4708 4708 case ENOENT:
4709 4709 warn(cf_missing, ient->sc_fmri, ud_name);
4710 4710 r = 0;
4711 4711 goto out;
4712 4712
4713 4713 case EBADF:
4714 4714 warn(r_no_lvl, ud_ctarg);
4715 4715 goto out;
4716 4716
4717 4717 case EINVAL:
4718 4718 default:
4719 4719 bad_error("entity_get_running_pg", r);
4720 4720 }
4721 4721
4722 4722 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4723 4723 switch (r) {
4724 4724 case 0:
4725 4725 break;
4726 4726
4727 4727 case ECANCELED:
4728 4728 warn(cf_missing, ient->sc_fmri, ud_name);
4729 4729 r = 0;
4730 4730 goto out;
4731 4731
4732 4732 case ECONNABORTED:
4733 4733 case ENOMEM:
4734 4734 case EBADF:
4735 4735 goto out;
4736 4736
4737 4737 case EACCES:
4738 4738 default:
4739 4739 bad_error("load_pg", r);
4740 4740 }
4741 4741
4742 4742 if (!pg_equal(current_pg, new_dpt_pgroup))
4743 4743 warn(cf_newdpg, ient->sc_fmri, ud_name);
4744 4744 internal_pgroup_free(current_pg);
4745 4745 r = 0;
4746 4746 goto out;
4747 4747 } else if (r != 1) {
4748 4748 bad_error("fmri_equal", r);
4749 4749 }
4750 4750
4751 4751 nocust:
4752 4752 /*
4753 4753 * Target has not been customized. Check the dependency property
4754 4754 * group.
4755 4755 */
4756 4756
4757 4757 if (old_dpt_pgroup == NULL) {
4758 4758 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4759 4759 ud_pg) != 0) {
4760 4760 switch (scf_error()) {
4761 4761 case SCF_ERROR_NOT_FOUND:
4762 4762 warn(li_corrupt, ient->sc_fmri);
4763 4763 return (EBADF);
4764 4764
4765 4765 case SCF_ERROR_DELETED:
4766 4766 case SCF_ERROR_CONNECTION_BROKEN:
4767 4767 return (scferror2errno(scf_error()));
4768 4768
4769 4769 case SCF_ERROR_NOT_BOUND:
4770 4770 case SCF_ERROR_HANDLE_MISMATCH:
4771 4771 case SCF_ERROR_INVALID_ARGUMENT:
4772 4772 case SCF_ERROR_NOT_SET:
4773 4773 default:
4774 4774 bad_error("scf_snaplevel_get_pg", scf_error());
4775 4775 }
4776 4776 }
4777 4777
4778 4778 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4779 4779 snap_lastimport);
4780 4780 switch (r) {
4781 4781 case 0:
4782 4782 break;
4783 4783
4784 4784 case ECANCELED:
4785 4785 case ECONNABORTED:
4786 4786 case ENOMEM:
4787 4787 case EBADF:
4788 4788 return (r);
4789 4789
4790 4790 case EACCES:
4791 4791 default:
4792 4792 bad_error("load_pg", r);
4793 4793 }
4794 4794 }
4795 4795 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4796 4796 switch (serr) {
4797 4797 case SCF_ERROR_NONE:
4798 4798 break;
4799 4799
4800 4800 case SCF_ERROR_NOT_FOUND:
4801 4801 warn(cf_missing, ient->sc_fmri, ud_name);
4802 4802 r = 0;
4803 4803 goto out;
4804 4804
4805 4805 case SCF_ERROR_NO_MEMORY:
4806 4806 r = ENOMEM;
4807 4807 goto out;
4808 4808
4809 4809 case SCF_ERROR_CONSTRAINT_VIOLATED:
4810 4810 case SCF_ERROR_INVALID_ARGUMENT:
4811 4811 default:
4812 4812 bad_error("fmri_to_entity", serr);
4813 4813 }
4814 4814
4815 4815 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4816 4816 ud_iter2, ud_inst, imp_snap, ud_snpl);
4817 4817 switch (r) {
4818 4818 case 0:
4819 4819 break;
4820 4820
4821 4821 case ECONNABORTED:
4822 4822 goto out;
4823 4823
4824 4824 case ECANCELED:
4825 4825 case ENOENT:
4826 4826 warn(cf_missing, ient->sc_fmri, ud_name);
4827 4827 r = 0;
4828 4828 goto out;
4829 4829
4830 4830 case EBADF:
4831 4831 warn(r_no_lvl, ud_ctarg);
4832 4832 goto out;
4833 4833
4834 4834 case EINVAL:
4835 4835 default:
4836 4836 bad_error("entity_get_running_pg", r);
4837 4837 }
4838 4838
4839 4839 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4840 4840 switch (r) {
4841 4841 case 0:
4842 4842 break;
4843 4843
4844 4844 case ECANCELED:
4845 4845 warn(cf_missing, ient->sc_fmri, ud_name);
4846 4846 goto out;
4847 4847
4848 4848 case ECONNABORTED:
4849 4849 case ENOMEM:
4850 4850 case EBADF:
4851 4851 goto out;
4852 4852
4853 4853 case EACCES:
4854 4854 default:
4855 4855 bad_error("load_pg", r);
4856 4856 }
4857 4857
4858 4858 if (!pg_equal(current_pg, old_dpt_pgroup)) {
4859 4859 if (!pg_equal(current_pg, new_dpt_pgroup))
4860 4860 warn(cf_newdpg, ient->sc_fmri, ud_name);
4861 4861 internal_pgroup_free(current_pg);
4862 4862 r = 0;
4863 4863 goto out;
4864 4864 }
4865 4865
4866 4866 /* Uncustomized. Upgrade. */
4867 4867
4868 4868 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4869 4869 switch (r) {
4870 4870 case 1:
4871 4871 if (pg_equal(current_pg, new_dpt_pgroup)) {
4872 4872 /* Already upgraded. */
4873 4873 internal_pgroup_free(current_pg);
4874 4874 r = 0;
4875 4875 goto out;
4876 4876 }
4877 4877
4878 4878 internal_pgroup_free(current_pg);
4879 4879
4880 4880 /* upgrade current_pg */
4881 4881 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4882 4882 switch (scf_error()) {
4883 4883 case SCF_ERROR_CONNECTION_BROKEN:
4884 4884 r = scferror2errno(scf_error());
4885 4885 goto out;
4886 4886
4887 4887 case SCF_ERROR_DELETED:
4888 4888 warn(cf_missing, ient->sc_fmri, ud_name);
4889 4889 r = 0;
4890 4890 goto out;
4891 4891
4892 4892 case SCF_ERROR_NOT_FOUND:
4893 4893 break;
4894 4894
4895 4895 case SCF_ERROR_INVALID_ARGUMENT:
4896 4896 case SCF_ERROR_NOT_BOUND:
4897 4897 case SCF_ERROR_NOT_SET:
4898 4898 case SCF_ERROR_HANDLE_MISMATCH:
4899 4899 default:
4900 4900 bad_error("entity_get_pg", scf_error());
4901 4901 }
4902 4902
4903 4903 if (tissvc)
4904 4904 r = scf_service_add_pg(target_ent, ud_name,
4905 4905 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4906 4906 else
4907 4907 r = scf_instance_add_pg(target_ent, ud_name,
4908 4908 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4909 4909 if (r != 0) {
4910 4910 switch (scf_error()) {
4911 4911 case SCF_ERROR_CONNECTION_BROKEN:
4912 4912 case SCF_ERROR_NO_RESOURCES:
4913 4913 case SCF_ERROR_BACKEND_READONLY:
4914 4914 case SCF_ERROR_BACKEND_ACCESS:
4915 4915 r = scferror2errno(scf_error());
4916 4916 goto out;
4917 4917
4918 4918 case SCF_ERROR_DELETED:
4919 4919 warn(cf_missing, ient->sc_fmri,
4920 4920 ud_name);
4921 4921 r = 0;
4922 4922 goto out;
4923 4923
4924 4924 case SCF_ERROR_PERMISSION_DENIED:
4925 4925 warn(emsg_pg_deleted, ud_ctarg,
4926 4926 ud_name);
4927 4927 r = EPERM;
4928 4928 goto out;
4929 4929
4930 4930 case SCF_ERROR_EXISTS:
4931 4931 warn(emsg_pg_added, ud_ctarg, ud_name);
4932 4932 r = EBUSY;
4933 4933 goto out;
4934 4934
4935 4935 case SCF_ERROR_NOT_BOUND:
4936 4936 case SCF_ERROR_HANDLE_MISMATCH:
4937 4937 case SCF_ERROR_INVALID_ARGUMENT:
4938 4938 case SCF_ERROR_NOT_SET:
4939 4939 default:
4940 4940 bad_error("entity_add_pg", scf_error());
4941 4941 }
4942 4942 }
4943 4943 }
4944 4944
4945 4945 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4946 4946 switch (r) {
4947 4947 case 0:
4948 4948 break;
4949 4949
4950 4950 case ECANCELED:
4951 4951 warn(cf_missing, ient->sc_fmri, ud_name);
4952 4952 goto out;
4953 4953
4954 4954 case ECONNABORTED:
4955 4955 case ENOMEM:
4956 4956 case EBADF:
4957 4957 goto out;
4958 4958
4959 4959 case EACCES:
4960 4960 default:
4961 4961 bad_error("load_pg", r);
4962 4962 }
4963 4963
4964 4964 if (g_verbose)
4965 4965 warn(upgrading, ient->sc_fmri, ud_name);
4966 4966
4967 4967 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4968 4968 new_dpt_pgroup, 0, ient->sc_fmri);
4969 4969 switch (r) {
4970 4970 case 0:
4971 4971 break;
4972 4972
4973 4973 case ECANCELED:
4974 4974 warn(emsg_pg_deleted, ud_ctarg, ud_name);
4975 4975 r = EBUSY;
4976 4976 goto out;
4977 4977
4978 4978 case EPERM:
4979 4979 warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4980 4980 goto out;
4981 4981
4982 4982 case EBUSY:
4983 4983 warn(emsg_pg_changed, ud_ctarg, ud_name);
4984 4984 goto out;
4985 4985
4986 4986 case ECONNABORTED:
4987 4987 case ENOMEM:
4988 4988 case ENOSPC:
4989 4989 case EROFS:
4990 4990 case EACCES:
4991 4991 case EINVAL:
4992 4992 goto out;
4993 4993
4994 4994 default:
4995 4995 bad_error("upgrade_pg", r);
4996 4996 }
4997 4997 break;
4998 4998
4999 4999 case 0: {
5000 5000 scf_transaction_entry_t *ent;
5001 5001 scf_value_t *val;
5002 5002
5003 5003 internal_pgroup_free(current_pg);
5004 5004
5005 5005 /* delete old pg */
5006 5006 if (g_verbose)
5007 5007 warn(upgrading, ient->sc_fmri, ud_name);
5008 5008
5009 5009 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5010 5010 switch (scf_error()) {
5011 5011 case SCF_ERROR_CONNECTION_BROKEN:
5012 5012 r = scferror2errno(scf_error());
5013 5013 goto out;
5014 5014
5015 5015 case SCF_ERROR_DELETED:
5016 5016 warn(cf_missing, ient->sc_fmri, ud_name);
5017 5017 r = 0;
5018 5018 goto out;
5019 5019
5020 5020 case SCF_ERROR_NOT_FOUND:
5021 5021 break;
5022 5022
5023 5023 case SCF_ERROR_INVALID_ARGUMENT:
5024 5024 case SCF_ERROR_NOT_BOUND:
5025 5025 case SCF_ERROR_NOT_SET:
5026 5026 case SCF_ERROR_HANDLE_MISMATCH:
5027 5027 default:
5028 5028 bad_error("entity_get_pg", scf_error());
5029 5029 }
5030 5030 } else if (scf_pg_delete(ud_pg) != 0) {
5031 5031 switch (scf_error()) {
5032 5032 case SCF_ERROR_DELETED:
5033 5033 break;
5034 5034
5035 5035 case SCF_ERROR_CONNECTION_BROKEN:
5036 5036 case SCF_ERROR_BACKEND_READONLY:
5037 5037 case SCF_ERROR_BACKEND_ACCESS:
5038 5038 r = scferror2errno(scf_error());
5039 5039 goto out;
5040 5040
5041 5041 case SCF_ERROR_PERMISSION_DENIED:
5042 5042 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5043 5043 r = scferror2errno(scf_error());
5044 5044 goto out;
5045 5045
5046 5046 case SCF_ERROR_NOT_SET:
5047 5047 default:
5048 5048 bad_error("scf_pg_delete", scf_error());
5049 5049 }
5050 5050 }
5051 5051
5052 5052 /* import new one */
5053 5053 cbdata.sc_handle = g_hndl;
5054 5054 cbdata.sc_trans = NULL; /* handled below */
5055 5055 cbdata.sc_flags = 0;
5056 5056
5057 5057 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5058 5058 if (r != UU_WALK_NEXT) {
5059 5059 if (r != UU_WALK_ERROR)
5060 5060 bad_error("lscf_dependent_import", r);
5061 5061
5062 5062 r = cbdata.sc_err;
5063 5063 goto out;
5064 5064 }
5065 5065
5066 5066 if (tx == NULL)
5067 5067 break;
5068 5068
5069 5069 if ((ent = scf_entry_create(g_hndl)) == NULL ||
5070 5070 (val = scf_value_create(g_hndl)) == NULL) {
5071 5071 if (scf_error() == SCF_ERROR_NO_MEMORY)
5072 5072 return (ENOMEM);
5073 5073
5074 5074 bad_error("scf_entry_create", scf_error());
5075 5075 }
5076 5076
5077 5077 if (scf_transaction_property_change_type(tx, ent, ud_name,
5078 5078 SCF_TYPE_FMRI) != 0) {
5079 5079 switch (scf_error()) {
5080 5080 case SCF_ERROR_CONNECTION_BROKEN:
5081 5081 r = scferror2errno(scf_error());
5082 5082 goto out;
5083 5083
5084 5084 case SCF_ERROR_DELETED:
5085 5085 warn(emsg_pg_deleted, ient->sc_fmri,
5086 5086 "dependents");
5087 5087 r = EBUSY;
5088 5088 goto out;
5089 5089
5090 5090 case SCF_ERROR_NOT_FOUND:
5091 5091 break;
5092 5092
5093 5093 case SCF_ERROR_NOT_BOUND:
5094 5094 case SCF_ERROR_HANDLE_MISMATCH:
5095 5095 case SCF_ERROR_INVALID_ARGUMENT:
5096 5096 case SCF_ERROR_NOT_SET:
5097 5097 default:
5098 5098 bad_error("scf_transaction_property_"
5099 5099 "change_type", scf_error());
5100 5100 }
5101 5101
5102 5102 if (scf_transaction_property_new(tx, ent, ud_name,
5103 5103 SCF_TYPE_FMRI) != 0) {
5104 5104 switch (scf_error()) {
5105 5105 case SCF_ERROR_CONNECTION_BROKEN:
5106 5106 r = scferror2errno(scf_error());
5107 5107 goto out;
5108 5108
5109 5109 case SCF_ERROR_DELETED:
5110 5110 warn(emsg_pg_deleted, ient->sc_fmri,
5111 5111 "dependents");
5112 5112 r = EBUSY;
5113 5113 goto out;
5114 5114
5115 5115 case SCF_ERROR_EXISTS:
5116 5116 warn(emsg_pg_changed, ient->sc_fmri,
5117 5117 "dependents");
5118 5118 r = EBUSY;
5119 5119 goto out;
5120 5120
5121 5121 case SCF_ERROR_INVALID_ARGUMENT:
5122 5122 case SCF_ERROR_HANDLE_MISMATCH:
5123 5123 case SCF_ERROR_NOT_BOUND:
5124 5124 case SCF_ERROR_NOT_SET:
5125 5125 default:
5126 5126 bad_error("scf_transaction_property_"
5127 5127 "new", scf_error());
5128 5128 }
5129 5129 }
5130 5130 }
5131 5131
5132 5132 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5133 5133 new_dpt_pgroup->sc_pgroup_fmri) != 0)
5134 5134 /* invalid sc_pgroup_fmri caught above */
5135 5135 bad_error("scf_value_set_from_string",
5136 5136 scf_error());
5137 5137
5138 5138 if (scf_entry_add_value(ent, val) != 0)
5139 5139 bad_error("scf_entry_add_value", scf_error());
5140 5140 break;
5141 5141 }
5142 5142
5143 5143 case -2:
5144 5144 warn(li_corrupt, ient->sc_fmri);
5145 5145 internal_pgroup_free(current_pg);
5146 5146 r = EBADF;
5147 5147 goto out;
5148 5148
5149 5149 case -1:
5150 5150 default:
5151 5151 /* invalid sc_pgroup_fmri caught above */
5152 5152 bad_error("fmri_equal", r);
5153 5153 }
5154 5154
5155 5155 r = 0;
5156 5156
5157 5157 out:
5158 5158 if (old_dpt_pgroup != NULL)
5159 5159 internal_pgroup_free(old_dpt_pgroup);
5160 5160
5161 5161 return (r);
5162 5162 }
5163 5163
5164 5164 /*
5165 5165 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5166 5166 * would import it, except it seems to exist in the service anyway. Compare
5167 5167 * the existent dependent with the one we would import, and report any
5168 5168 * differences (if there are none, be silent). prop is the property which
5169 5169 * represents the existent dependent (in the dependents property group) in the
5170 5170 * entity corresponding to ient.
5171 5171 *
5172 5172 * Returns
5173 5173 * 0 - success (Sort of. At least, we can continue importing.)
5174 5174 * ECONNABORTED - repository connection broken
5175 5175 * EBUSY - ancestor of prop was deleted (error printed)
5176 5176 * ENOMEM - out of memory
5177 5177 * EBADF - corrupt property group (error printed)
5178 5178 * EINVAL - new_dpt_pgroup has invalid target (error printed)
5179 5179 */
5180 5180 static int
5181 5181 handle_dependent_conflict(const entity_t * const ient,
5182 5182 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5183 5183 {
5184 5184 int r;
5185 5185 scf_type_t ty;
5186 5186 scf_error_t scfe;
5187 5187 void *tptr;
5188 5188 int tissvc;
5189 5189 pgroup_t *pgroup;
5190 5190
5191 5191 if (scf_property_get_value(prop, ud_val) != 0) {
5192 5192 switch (scf_error()) {
5193 5193 case SCF_ERROR_CONNECTION_BROKEN:
5194 5194 return (scferror2errno(scf_error()));
5195 5195
5196 5196 case SCF_ERROR_DELETED:
5197 5197 warn(emsg_pg_deleted, ient->sc_fmri,
5198 5198 new_dpt_pgroup->sc_pgroup_name);
5199 5199 return (EBUSY);
5200 5200
5201 5201 case SCF_ERROR_CONSTRAINT_VIOLATED:
5202 5202 case SCF_ERROR_NOT_FOUND:
5203 5203 warn(gettext("Conflict upgrading %s (not importing "
5204 5204 "dependent \"%s\" because it already exists.) "
5205 5205 "Warning: The \"%s/%2$s\" property has more or "
5206 5206 "fewer than one value)).\n"), ient->sc_fmri,
5207 5207 new_dpt_pgroup->sc_pgroup_name, "dependents");
5208 5208 return (0);
5209 5209
5210 5210 case SCF_ERROR_HANDLE_MISMATCH:
5211 5211 case SCF_ERROR_NOT_BOUND:
5212 5212 case SCF_ERROR_NOT_SET:
5213 5213 case SCF_ERROR_PERMISSION_DENIED:
5214 5214 default:
5215 5215 bad_error("scf_property_get_value",
5216 5216 scf_error());
5217 5217 }
5218 5218 }
5219 5219
5220 5220 ty = scf_value_type(ud_val);
5221 5221 assert(ty != SCF_TYPE_INVALID);
5222 5222 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5223 5223 warn(gettext("Conflict upgrading %s (not importing dependent "
5224 5224 "\"%s\" because it already exists). Warning: The "
5225 5225 "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5226 5226 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5227 5227 scf_type_to_string(ty), "dependents");
5228 5228 return (0);
5229 5229 }
5230 5230
5231 5231 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5232 5232 0)
5233 5233 bad_error("scf_value_get_as_string", scf_error());
5234 5234
5235 5235 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5236 5236 switch (r) {
5237 5237 case 0:
5238 5238 warn(gettext("Conflict upgrading %s (not importing dependent "
5239 5239 "\"%s\" (target \"%s\") because it already exists with "
5240 5240 "target \"%s\").\n"), ient->sc_fmri,
5241 5241 new_dpt_pgroup->sc_pgroup_name,
5242 5242 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5243 5243 return (0);
5244 5244
5245 5245 case 1:
5246 5246 break;
5247 5247
5248 5248 case -1:
5249 5249 warn(gettext("Conflict upgrading %s (not importing dependent "
5250 5250 "\"%s\" because it already exists). Warning: The current "
5251 5251 "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5252 5252 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5253 5253 return (0);
5254 5254
5255 5255 case -2:
5256 5256 warn(gettext("Dependent \"%s\" of %s has invalid target "
5257 5257 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5258 5258 new_dpt_pgroup->sc_pgroup_fmri);
5259 5259 return (EINVAL);
5260 5260
5261 5261 default:
5262 5262 bad_error("fmri_equal", r);
5263 5263 }
5264 5264
5265 5265 /* compare dependency pgs in target */
5266 5266 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5267 5267 switch (scfe) {
5268 5268 case SCF_ERROR_NONE:
5269 5269 break;
5270 5270
5271 5271 case SCF_ERROR_NO_MEMORY:
5272 5272 return (ENOMEM);
5273 5273
5274 5274 case SCF_ERROR_NOT_FOUND:
5275 5275 warn(emsg_dpt_dangling, ient->sc_fmri,
5276 5276 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5277 5277 return (0);
5278 5278
5279 5279 case SCF_ERROR_CONSTRAINT_VIOLATED:
5280 5280 case SCF_ERROR_INVALID_ARGUMENT:
5281 5281 default:
5282 5282 bad_error("fmri_to_entity", scfe);
5283 5283 }
5284 5284
5285 5285 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5286 5286 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5287 5287 switch (r) {
5288 5288 case 0:
5289 5289 break;
5290 5290
5291 5291 case ECONNABORTED:
5292 5292 return (r);
5293 5293
5294 5294 case ECANCELED:
5295 5295 warn(emsg_dpt_dangling, ient->sc_fmri,
5296 5296 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5297 5297 return (0);
5298 5298
5299 5299 case EBADF:
5300 5300 if (tissvc)
5301 5301 warn(gettext("%s has an instance with a \"%s\" "
5302 5302 "snapshot which is missing a snaplevel.\n"),
5303 5303 ud_ctarg, "running");
5304 5304 else
5305 5305 warn(gettext("%s has a \"%s\" snapshot which is "
5306 5306 "missing a snaplevel.\n"), ud_ctarg, "running");
5307 5307 /* FALLTHROUGH */
5308 5308
5309 5309 case ENOENT:
5310 5310 warn(emsg_dpt_no_dep, ient->sc_fmri,
5311 5311 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5312 5312 new_dpt_pgroup->sc_pgroup_name);
5313 5313 return (0);
5314 5314
5315 5315 case EINVAL:
5316 5316 default:
5317 5317 bad_error("entity_get_running_pg", r);
5318 5318 }
5319 5319
5320 5320 pgroup = internal_pgroup_new();
5321 5321 if (pgroup == NULL)
5322 5322 return (ENOMEM);
5323 5323
5324 5324 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5325 5325 switch (r) {
5326 5326 case 0:
5327 5327 break;
5328 5328
5329 5329 case ECONNABORTED:
5330 5330 case EBADF:
5331 5331 case ENOMEM:
5332 5332 internal_pgroup_free(pgroup);
5333 5333 return (r);
5334 5334
5335 5335 case ECANCELED:
5336 5336 warn(emsg_dpt_no_dep, ient->sc_fmri,
5337 5337 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5338 5338 new_dpt_pgroup->sc_pgroup_name);
5339 5339 internal_pgroup_free(pgroup);
5340 5340 return (0);
5341 5341
5342 5342 case EACCES:
5343 5343 default:
5344 5344 bad_error("load_pg", r);
5345 5345 }
5346 5346
5347 5347 /* report differences */
5348 5348 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5349 5349 internal_pgroup_free(pgroup);
5350 5350 return (0);
5351 5351 }
5352 5352
5353 5353 /*
5354 5354 * lipg is a property group in the last-import snapshot of ent, which is an
5355 5355 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in
5356 5356 * ient's pgroups, delete it from ent if it hasn't been customized. If it is
5357 5357 * in ents's property groups, compare and upgrade ent appropriately.
5358 5358 *
5359 5359 * Returns
5360 5360 * 0 - success
5361 5361 * ECONNABORTED - repository connection broken
5362 5362 * ENOMEM - out of memory
5363 5363 * ENOSPC - configd is out of resources
5364 5364 * EINVAL - ient has invalid dependent (error printed)
5365 5365 * - ient has invalid pgroup_t (error printed)
5366 5366 * ECANCELED - ent has been deleted
5367 5367 * ENODEV - entity containing lipg has been deleted
5368 5368 * - entity containing running has been deleted
5369 5369 * EPERM - could not delete pg (permission denied) (error printed)
5370 5370 * - couldn't upgrade dependents (permission denied) (error printed)
5371 5371 * - couldn't import pg (permission denied) (error printed)
5372 5372 * - couldn't upgrade pg (permission denied) (error printed)
5373 5373 * EROFS - could not delete pg (repository read-only)
5374 5374 * - couldn't upgrade dependents (repository read-only)
5375 5375 * - couldn't import pg (repository read-only)
5376 5376 * - couldn't upgrade pg (repository read-only)
5377 5377 * EACCES - could not delete pg (backend access denied)
5378 5378 * - couldn't upgrade dependents (backend access denied)
5379 5379 * - couldn't import pg (backend access denied)
5380 5380 * - couldn't upgrade pg (backend access denied)
5381 5381 * - couldn't read property (backend access denied)
5382 5382 * EBUSY - property group was added (error printed)
5383 5383 * - property group was deleted (error printed)
5384 5384 * - property group changed (error printed)
5385 5385 * - "dependents" pg was added, changed, or deleted (error printed)
5386 5386 * - dependent target deleted (error printed)
5387 5387 * - dependent pg changed (error printed)
5388 5388 * EBADF - imp_snpl is corrupt (error printed)
5389 5389 * - ent has bad pg (error printed)
5390 5390 * EEXIST - dependent collision in target service (error printed)
5391 5391 */
5392 5392 static int
5393 5393 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5394 5394 const scf_snaplevel_t *running)
5395 5395 {
5396 5396 int r;
5397 5397 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5398 5398 scf_callback_t cbdata;
5399 5399
5400 5400 const char * const cf_pg_missing =
5401 5401 gettext("Conflict upgrading %s (property group %s is missing)\n");
5402 5402 const char * const deleting =
5403 5403 gettext("%s: Deleting property group \"%s\".\n");
5404 5404
5405 5405 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5406 5406
5407 5407 /* Skip dependent property groups. */
5408 5408 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5409 5409 switch (scf_error()) {
5410 5410 case SCF_ERROR_DELETED:
5411 5411 return (ENODEV);
5412 5412
5413 5413 case SCF_ERROR_CONNECTION_BROKEN:
5414 5414 return (ECONNABORTED);
5415 5415
5416 5416 case SCF_ERROR_NOT_SET:
5417 5417 case SCF_ERROR_NOT_BOUND:
5418 5418 default:
5419 5419 bad_error("scf_pg_get_type", scf_error());
5420 5420 }
5421 5421 }
5422 5422
5423 5423 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5424 5424 if (scf_pg_get_property(lipg, "external", NULL) == 0)
5425 5425 return (0);
5426 5426
5427 5427 switch (scf_error()) {
5428 5428 case SCF_ERROR_NOT_FOUND:
5429 5429 break;
5430 5430
5431 5431 case SCF_ERROR_CONNECTION_BROKEN:
5432 5432 return (ECONNABORTED);
5433 5433
5434 5434 case SCF_ERROR_DELETED:
5435 5435 return (ENODEV);
5436 5436
5437 5437 case SCF_ERROR_INVALID_ARGUMENT:
5438 5438 case SCF_ERROR_NOT_BOUND:
5439 5439 case SCF_ERROR_HANDLE_MISMATCH:
5440 5440 case SCF_ERROR_NOT_SET:
5441 5441 default:
5442 5442 bad_error("scf_pg_get_property", scf_error());
5443 5443 }
5444 5444 }
5445 5445
5446 5446 /* lookup pg in new properties */
5447 5447 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5448 5448 switch (scf_error()) {
5449 5449 case SCF_ERROR_DELETED:
5450 5450 return (ENODEV);
5451 5451
5452 5452 case SCF_ERROR_CONNECTION_BROKEN:
5453 5453 return (ECONNABORTED);
5454 5454
5455 5455 case SCF_ERROR_NOT_SET:
5456 5456 case SCF_ERROR_NOT_BOUND:
5457 5457 default:
5458 5458 bad_error("scf_pg_get_name", scf_error());
5459 5459 }
5460 5460 }
5461 5461
5462 5462 pgrp.sc_pgroup_name = imp_str;
5463 5463 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5464 5464
5465 5465 if (mpg != NULL)
5466 5466 mpg->sc_pgroup_seen = 1;
5467 5467
5468 5468 /* Special handling for dependents */
5469 5469 if (strcmp(imp_str, "dependents") == 0)
5470 5470 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5471 5471
5472 5472 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5473 5473 return (upgrade_manifestfiles(NULL, ient, running, ent));
5474 5474
5475 5475 if (mpg == NULL || mpg->sc_pgroup_delete) {
5476 5476 /* property group was deleted from manifest */
5477 5477 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5478 5478 switch (scf_error()) {
5479 5479 case SCF_ERROR_NOT_FOUND:
5480 5480 return (0);
5481 5481
5482 5482 case SCF_ERROR_DELETED:
5483 5483 case SCF_ERROR_CONNECTION_BROKEN:
5484 5484 return (scferror2errno(scf_error()));
5485 5485
5486 5486 case SCF_ERROR_INVALID_ARGUMENT:
5487 5487 case SCF_ERROR_HANDLE_MISMATCH:
5488 5488 case SCF_ERROR_NOT_BOUND:
5489 5489 case SCF_ERROR_NOT_SET:
5490 5490 default:
5491 5491 bad_error("entity_get_pg", scf_error());
5492 5492 }
5493 5493 }
5494 5494
5495 5495 if (mpg != NULL && mpg->sc_pgroup_delete) {
5496 5496 if (g_verbose)
5497 5497 warn(deleting, ient->sc_fmri, imp_str);
5498 5498 if (scf_pg_delete(imp_pg2) == 0)
5499 5499 return (0);
5500 5500
5501 5501 switch (scf_error()) {
5502 5502 case SCF_ERROR_DELETED:
5503 5503 return (0);
5504 5504
5505 5505 case SCF_ERROR_CONNECTION_BROKEN:
5506 5506 case SCF_ERROR_BACKEND_READONLY:
5507 5507 case SCF_ERROR_BACKEND_ACCESS:
5508 5508 return (scferror2errno(scf_error()));
5509 5509
5510 5510 case SCF_ERROR_PERMISSION_DENIED:
5511 5511 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5512 5512 return (scferror2errno(scf_error()));
5513 5513
5514 5514 case SCF_ERROR_NOT_SET:
5515 5515 default:
5516 5516 bad_error("scf_pg_delete", scf_error());
5517 5517 }
5518 5518 }
5519 5519
5520 5520 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5521 5521 switch (r) {
5522 5522 case 0:
5523 5523 break;
5524 5524
5525 5525 case ECANCELED:
5526 5526 return (ENODEV);
5527 5527
5528 5528 case ECONNABORTED:
5529 5529 case ENOMEM:
5530 5530 case EBADF:
5531 5531 case EACCES:
5532 5532 return (r);
5533 5533
5534 5534 default:
5535 5535 bad_error("load_pg", r);
5536 5536 }
5537 5537
5538 5538 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5539 5539 switch (r) {
5540 5540 case 0:
5541 5541 break;
5542 5542
5543 5543 case ECANCELED:
5544 5544 case ECONNABORTED:
5545 5545 case ENOMEM:
5546 5546 case EBADF:
5547 5547 case EACCES:
5548 5548 internal_pgroup_free(lipg_i);
5549 5549 return (r);
5550 5550
5551 5551 default:
5552 5552 bad_error("load_pg", r);
5553 5553 }
5554 5554
5555 5555 if (pg_equal(lipg_i, curpg_i)) {
5556 5556 if (g_verbose)
5557 5557 warn(deleting, ient->sc_fmri, imp_str);
5558 5558 if (scf_pg_delete(imp_pg2) != 0) {
5559 5559 switch (scf_error()) {
5560 5560 case SCF_ERROR_DELETED:
5561 5561 break;
5562 5562
5563 5563 case SCF_ERROR_CONNECTION_BROKEN:
5564 5564 internal_pgroup_free(lipg_i);
5565 5565 internal_pgroup_free(curpg_i);
5566 5566 return (ECONNABORTED);
5567 5567
5568 5568 case SCF_ERROR_NOT_SET:
5569 5569 case SCF_ERROR_NOT_BOUND:
5570 5570 default:
5571 5571 bad_error("scf_pg_delete", scf_error());
5572 5572 }
5573 5573 }
5574 5574 } else {
5575 5575 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5576 5576 }
5577 5577
5578 5578 internal_pgroup_free(lipg_i);
5579 5579 internal_pgroup_free(curpg_i);
5580 5580
5581 5581 return (0);
5582 5582 }
5583 5583
5584 5584 /*
5585 5585 * Only dependent pgs can have override set, and we skipped those
5586 5586 * above.
5587 5587 */
5588 5588 assert(!mpg->sc_pgroup_override);
5589 5589
5590 5590 /* compare */
5591 5591 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5592 5592 switch (r) {
5593 5593 case 0:
5594 5594 break;
5595 5595
5596 5596 case ECANCELED:
5597 5597 return (ENODEV);
5598 5598
5599 5599 case ECONNABORTED:
5600 5600 case EBADF:
5601 5601 case ENOMEM:
5602 5602 case EACCES:
5603 5603 return (r);
5604 5604
5605 5605 default:
5606 5606 bad_error("load_pg", r);
5607 5607 }
5608 5608
5609 5609 if (pg_equal(mpg, lipg_i)) {
5610 5610 /* The manifest pg has not changed. Move on. */
5611 5611 r = 0;
5612 5612 goto out;
5613 5613 }
5614 5614
5615 5615 /* upgrade current properties according to lipg & mpg */
5616 5616 if (running != NULL)
5617 5617 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5618 5618 else
5619 5619 r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5620 5620 if (r != 0) {
5621 5621 switch (scf_error()) {
5622 5622 case SCF_ERROR_CONNECTION_BROKEN:
5623 5623 r = scferror2errno(scf_error());
5624 5624 goto out;
5625 5625
5626 5626 case SCF_ERROR_DELETED:
5627 5627 if (running != NULL)
5628 5628 r = ENODEV;
5629 5629 else
5630 5630 r = ECANCELED;
5631 5631 goto out;
5632 5632
5633 5633 case SCF_ERROR_NOT_FOUND:
5634 5634 break;
5635 5635
5636 5636 case SCF_ERROR_INVALID_ARGUMENT:
5637 5637 case SCF_ERROR_HANDLE_MISMATCH:
5638 5638 case SCF_ERROR_NOT_BOUND:
5639 5639 case SCF_ERROR_NOT_SET:
5640 5640 default:
5641 5641 bad_error("entity_get_pg", scf_error());
5642 5642 }
5643 5643
5644 5644 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5645 5645
5646 5646 r = 0;
5647 5647 goto out;
5648 5648 }
5649 5649
5650 5650 r = load_pg_attrs(imp_pg2, &curpg_i);
5651 5651 switch (r) {
5652 5652 case 0:
5653 5653 break;
5654 5654
5655 5655 case ECANCELED:
5656 5656 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5657 5657 r = 0;
5658 5658 goto out;
5659 5659
5660 5660 case ECONNABORTED:
5661 5661 case ENOMEM:
5662 5662 goto out;
5663 5663
5664 5664 default:
5665 5665 bad_error("load_pg_attrs", r);
5666 5666 }
5667 5667
5668 5668 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5669 5669 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5670 5670 internal_pgroup_free(curpg_i);
5671 5671 r = 0;
5672 5672 goto out;
5673 5673 }
5674 5674
5675 5675 internal_pgroup_free(curpg_i);
5676 5676
5677 5677 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5678 5678 switch (r) {
5679 5679 case 0:
5680 5680 break;
5681 5681
5682 5682 case ECANCELED:
5683 5683 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5684 5684 r = 0;
5685 5685 goto out;
5686 5686
5687 5687 case ECONNABORTED:
5688 5688 case EBADF:
5689 5689 case ENOMEM:
5690 5690 case EACCES:
5691 5691 goto out;
5692 5692
5693 5693 default:
5694 5694 bad_error("load_pg", r);
5695 5695 }
5696 5696
5697 5697 if (pg_equal(lipg_i, curpg_i) &&
5698 5698 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5699 5699 int do_delete = 1;
5700 5700
5701 5701 if (g_verbose)
5702 5702 warn(gettext("%s: Upgrading property group \"%s\".\n"),
5703 5703 ient->sc_fmri, mpg->sc_pgroup_name);
5704 5704
5705 5705 internal_pgroup_free(curpg_i);
5706 5706
5707 5707 if (running != NULL &&
5708 5708 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5709 5709 switch (scf_error()) {
5710 5710 case SCF_ERROR_DELETED:
5711 5711 r = ECANCELED;
5712 5712 goto out;
5713 5713
5714 5714 case SCF_ERROR_NOT_FOUND:
5715 5715 do_delete = 0;
5716 5716 break;
5717 5717
5718 5718 case SCF_ERROR_CONNECTION_BROKEN:
5719 5719 r = scferror2errno(scf_error());
5720 5720 goto out;
5721 5721
5722 5722 case SCF_ERROR_HANDLE_MISMATCH:
5723 5723 case SCF_ERROR_INVALID_ARGUMENT:
5724 5724 case SCF_ERROR_NOT_SET:
5725 5725 case SCF_ERROR_NOT_BOUND:
5726 5726 default:
5727 5727 bad_error("entity_get_pg", scf_error());
5728 5728 }
5729 5729 }
5730 5730
5731 5731 if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5732 5732 switch (scf_error()) {
5733 5733 case SCF_ERROR_DELETED:
5734 5734 break;
5735 5735
5736 5736 case SCF_ERROR_CONNECTION_BROKEN:
5737 5737 case SCF_ERROR_BACKEND_READONLY:
5738 5738 case SCF_ERROR_BACKEND_ACCESS:
5739 5739 r = scferror2errno(scf_error());
5740 5740 goto out;
5741 5741
5742 5742 case SCF_ERROR_PERMISSION_DENIED:
5743 5743 warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5744 5744 ient->sc_fmri);
5745 5745 r = scferror2errno(scf_error());
5746 5746 goto out;
5747 5747
5748 5748 case SCF_ERROR_NOT_SET:
5749 5749 case SCF_ERROR_NOT_BOUND:
5750 5750 default:
5751 5751 bad_error("scf_pg_delete", scf_error());
5752 5752 }
5753 5753 }
5754 5754
5755 5755 cbdata.sc_handle = g_hndl;
5756 5756 cbdata.sc_parent = ent;
5757 5757 cbdata.sc_service = issvc;
5758 5758 cbdata.sc_flags = 0;
5759 5759 cbdata.sc_source_fmri = ient->sc_fmri;
5760 5760 cbdata.sc_target_fmri = ient->sc_fmri;
5761 5761
5762 5762 r = entity_pgroup_import(mpg, &cbdata);
5763 5763 switch (r) {
5764 5764 case UU_WALK_NEXT:
5765 5765 r = 0;
5766 5766 goto out;
5767 5767
5768 5768 case UU_WALK_ERROR:
5769 5769 if (cbdata.sc_err == EEXIST) {
5770 5770 warn(emsg_pg_added, ient->sc_fmri,
5771 5771 mpg->sc_pgroup_name);
5772 5772 r = EBUSY;
5773 5773 } else {
5774 5774 r = cbdata.sc_err;
5775 5775 }
5776 5776 goto out;
5777 5777
5778 5778 default:
5779 5779 bad_error("entity_pgroup_import", r);
5780 5780 }
5781 5781 }
5782 5782
5783 5783 if (running != NULL &&
5784 5784 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5785 5785 switch (scf_error()) {
5786 5786 case SCF_ERROR_CONNECTION_BROKEN:
5787 5787 case SCF_ERROR_DELETED:
5788 5788 r = scferror2errno(scf_error());
5789 5789 goto out;
5790 5790
5791 5791 case SCF_ERROR_NOT_FOUND:
5792 5792 break;
5793 5793
5794 5794 case SCF_ERROR_HANDLE_MISMATCH:
5795 5795 case SCF_ERROR_INVALID_ARGUMENT:
5796 5796 case SCF_ERROR_NOT_SET:
5797 5797 case SCF_ERROR_NOT_BOUND:
5798 5798 default:
5799 5799 bad_error("entity_get_pg", scf_error());
5800 5800 }
5801 5801
5802 5802 cbdata.sc_handle = g_hndl;
5803 5803 cbdata.sc_parent = ent;
5804 5804 cbdata.sc_service = issvc;
5805 5805 cbdata.sc_flags = SCI_FORCE;
5806 5806 cbdata.sc_source_fmri = ient->sc_fmri;
5807 5807 cbdata.sc_target_fmri = ient->sc_fmri;
5808 5808
5809 5809 r = entity_pgroup_import(mpg, &cbdata);
5810 5810 switch (r) {
5811 5811 case UU_WALK_NEXT:
5812 5812 r = 0;
5813 5813 goto out;
5814 5814
5815 5815 case UU_WALK_ERROR:
5816 5816 if (cbdata.sc_err == EEXIST) {
5817 5817 warn(emsg_pg_added, ient->sc_fmri,
5818 5818 mpg->sc_pgroup_name);
5819 5819 r = EBUSY;
5820 5820 } else {
5821 5821 r = cbdata.sc_err;
5822 5822 }
5823 5823 goto out;
5824 5824
5825 5825 default:
5826 5826 bad_error("entity_pgroup_import", r);
5827 5827 }
5828 5828 }
5829 5829
5830 5830 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5831 5831 internal_pgroup_free(curpg_i);
5832 5832 switch (r) {
5833 5833 case 0:
5834 5834 ient->sc_import_state = IMPORT_PROP_BEGUN;
5835 5835 break;
5836 5836
5837 5837 case ECANCELED:
5838 5838 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5839 5839 r = EBUSY;
5840 5840 break;
5841 5841
5842 5842 case EPERM:
5843 5843 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5844 5844 break;
5845 5845
5846 5846 case EBUSY:
5847 5847 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5848 5848 break;
5849 5849
5850 5850 case ECONNABORTED:
5851 5851 case ENOMEM:
5852 5852 case ENOSPC:
5853 5853 case EROFS:
5854 5854 case EACCES:
5855 5855 case EINVAL:
5856 5856 break;
5857 5857
5858 5858 default:
5859 5859 bad_error("upgrade_pg", r);
5860 5860 }
5861 5861
5862 5862 out:
5863 5863 internal_pgroup_free(lipg_i);
5864 5864 return (r);
5865 5865 }
5866 5866
5867 5867 /*
5868 5868 * Upgrade the properties of ent according to snpl & ient.
5869 5869 *
5870 5870 * Returns
5871 5871 * 0 - success
5872 5872 * ECONNABORTED - repository connection broken
5873 5873 * ENOMEM - out of memory
5874 5874 * ENOSPC - configd is out of resources
5875 5875 * ECANCELED - ent was deleted
5876 5876 * ENODEV - entity containing snpl was deleted
5877 5877 * - entity containing running was deleted
5878 5878 * EBADF - imp_snpl is corrupt (error printed)
5879 5879 * - ent has corrupt pg (error printed)
5880 5880 * - dependent has corrupt pg (error printed)
5881 5881 * - dependent target has a corrupt snapshot (error printed)
5882 5882 * EBUSY - pg was added, changed, or deleted (error printed)
5883 5883 * - dependent target was deleted (error printed)
5884 5884 * - dependent pg changed (error printed)
5885 5885 * EINVAL - invalid property group name (error printed)
5886 5886 * - invalid property name (error printed)
5887 5887 * - invalid value (error printed)
5888 5888 * - ient has invalid pgroup or dependent (error printed)
5889 5889 * EPERM - could not create property group (permission denied) (error printed)
5890 5890 * - could not modify property group (permission denied) (error printed)
5891 5891 * - couldn't delete, upgrade, or import pg or dependent (error printed)
5892 5892 * EROFS - could not create property group (repository read-only)
5893 5893 * - couldn't delete, upgrade, or import pg or dependent
5894 5894 * EACCES - could not create property group (backend access denied)
5895 5895 * - couldn't delete, upgrade, or import pg or dependent
5896 5896 * EEXIST - dependent collision in target service (error printed)
5897 5897 */
5898 5898 static int
5899 5899 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5900 5900 entity_t *ient)
5901 5901 {
5902 5902 pgroup_t *pg, *rpg;
5903 5903 int r;
5904 5904 uu_list_t *pgs = ient->sc_pgroups;
5905 5905
5906 5906 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5907 5907
5908 5908 /* clear sc_sceen for pgs */
5909 5909 if (uu_list_walk(pgs, clear_int,
5910 5910 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5911 5911 bad_error("uu_list_walk", uu_error());
5912 5912
5913 5913 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5914 5914 switch (scf_error()) {
5915 5915 case SCF_ERROR_DELETED:
5916 5916 return (ENODEV);
5917 5917
5918 5918 case SCF_ERROR_CONNECTION_BROKEN:
5919 5919 return (ECONNABORTED);
5920 5920
5921 5921 case SCF_ERROR_NOT_SET:
5922 5922 case SCF_ERROR_NOT_BOUND:
5923 5923 case SCF_ERROR_HANDLE_MISMATCH:
5924 5924 default:
5925 5925 bad_error("scf_iter_snaplevel_pgs", scf_error());
5926 5926 }
5927 5927 }
5928 5928
5929 5929 for (;;) {
5930 5930 r = scf_iter_next_pg(imp_up_iter, imp_pg);
5931 5931 if (r == 0)
5932 5932 break;
5933 5933 if (r == 1) {
5934 5934 r = process_old_pg(imp_pg, ient, ent, running);
5935 5935 switch (r) {
5936 5936 case 0:
5937 5937 break;
5938 5938
5939 5939 case ECONNABORTED:
5940 5940 case ENOMEM:
5941 5941 case ENOSPC:
5942 5942 case ECANCELED:
5943 5943 case ENODEV:
5944 5944 case EPERM:
5945 5945 case EROFS:
5946 5946 case EACCES:
5947 5947 case EBADF:
5948 5948 case EBUSY:
5949 5949 case EINVAL:
5950 5950 case EEXIST:
5951 5951 return (r);
5952 5952
5953 5953 default:
5954 5954 bad_error("process_old_pg", r);
5955 5955 }
5956 5956 continue;
5957 5957 }
5958 5958 if (r != -1)
5959 5959 bad_error("scf_iter_next_pg", r);
5960 5960
5961 5961 switch (scf_error()) {
5962 5962 case SCF_ERROR_DELETED:
5963 5963 return (ENODEV);
5964 5964
5965 5965 case SCF_ERROR_CONNECTION_BROKEN:
5966 5966 return (ECONNABORTED);
5967 5967
5968 5968 case SCF_ERROR_HANDLE_MISMATCH:
5969 5969 case SCF_ERROR_NOT_BOUND:
5970 5970 case SCF_ERROR_NOT_SET:
5971 5971 case SCF_ERROR_INVALID_ARGUMENT:
5972 5972 default:
5973 5973 bad_error("scf_iter_next_pg", scf_error());
5974 5974 }
5975 5975 }
5976 5976
5977 5977 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5978 5978 if (pg->sc_pgroup_seen)
5979 5979 continue;
5980 5980
5981 5981 /* pg is new */
5982 5982
5983 5983 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5984 5984 r = upgrade_dependents(NULL, imp_snpl, ient, running,
5985 5985 ent);
5986 5986 switch (r) {
5987 5987 case 0:
5988 5988 break;
5989 5989
5990 5990 case ECONNABORTED:
5991 5991 case ENOMEM:
5992 5992 case ENOSPC:
5993 5993 case ECANCELED:
5994 5994 case ENODEV:
5995 5995 case EBADF:
5996 5996 case EBUSY:
5997 5997 case EINVAL:
5998 5998 case EPERM:
5999 5999 case EROFS:
6000 6000 case EACCES:
6001 6001 case EEXIST:
6002 6002 return (r);
6003 6003
6004 6004 default:
6005 6005 bad_error("upgrade_dependents", r);
6006 6006 }
6007 6007 continue;
6008 6008 }
6009 6009
6010 6010 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6011 6011 r = upgrade_manifestfiles(pg, ient, running, ent);
6012 6012 switch (r) {
6013 6013 case 0:
6014 6014 break;
6015 6015
6016 6016 case ECONNABORTED:
6017 6017 case ENOMEM:
6018 6018 case ENOSPC:
6019 6019 case ECANCELED:
6020 6020 case ENODEV:
6021 6021 case EBADF:
6022 6022 case EBUSY:
6023 6023 case EINVAL:
6024 6024 case EPERM:
6025 6025 case EROFS:
6026 6026 case EACCES:
6027 6027 case EEXIST:
6028 6028 return (r);
6029 6029
6030 6030 default:
6031 6031 bad_error("upgrade_manifestfiles", r);
6032 6032 }
6033 6033 continue;
6034 6034 }
6035 6035
6036 6036 if (running != NULL) {
6037 6037 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6038 6038 imp_pg);
6039 6039 } else {
6040 6040 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6041 6041 imp_pg);
6042 6042 }
6043 6043 if (r != 0) {
6044 6044 scf_callback_t cbdata;
6045 6045
6046 6046 switch (scf_error()) {
6047 6047 case SCF_ERROR_NOT_FOUND:
6048 6048 break;
6049 6049
6050 6050 case SCF_ERROR_CONNECTION_BROKEN:
6051 6051 return (scferror2errno(scf_error()));
6052 6052
6053 6053 case SCF_ERROR_DELETED:
6054 6054 if (running != NULL)
6055 6055 return (ENODEV);
6056 6056 else
6057 6057 return (scferror2errno(scf_error()));
6058 6058
6059 6059 case SCF_ERROR_INVALID_ARGUMENT:
6060 6060 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6061 6061 pg->sc_pgroup_name);
6062 6062 return (EINVAL);
6063 6063
6064 6064 case SCF_ERROR_NOT_SET:
6065 6065 case SCF_ERROR_HANDLE_MISMATCH:
6066 6066 case SCF_ERROR_NOT_BOUND:
6067 6067 default:
6068 6068 bad_error("entity_get_pg", scf_error());
6069 6069 }
6070 6070
6071 6071 /* User doesn't have pg, so import it. */
6072 6072
6073 6073 cbdata.sc_handle = g_hndl;
6074 6074 cbdata.sc_parent = ent;
6075 6075 cbdata.sc_service = issvc;
6076 6076 cbdata.sc_flags = SCI_FORCE;
6077 6077 cbdata.sc_source_fmri = ient->sc_fmri;
6078 6078 cbdata.sc_target_fmri = ient->sc_fmri;
6079 6079
6080 6080 r = entity_pgroup_import(pg, &cbdata);
6081 6081 switch (r) {
6082 6082 case UU_WALK_NEXT:
6083 6083 ient->sc_import_state = IMPORT_PROP_BEGUN;
6084 6084 continue;
6085 6085
6086 6086 case UU_WALK_ERROR:
6087 6087 if (cbdata.sc_err == EEXIST) {
6088 6088 warn(emsg_pg_added, ient->sc_fmri,
6089 6089 pg->sc_pgroup_name);
6090 6090 return (EBUSY);
6091 6091 }
6092 6092 return (cbdata.sc_err);
6093 6093
6094 6094 default:
6095 6095 bad_error("entity_pgroup_import", r);
6096 6096 }
6097 6097 }
6098 6098
6099 6099 /* report differences between pg & current */
6100 6100 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6101 6101 switch (r) {
6102 6102 case 0:
6103 6103 break;
6104 6104
6105 6105 case ECANCELED:
6106 6106 warn(emsg_pg_deleted, ient->sc_fmri,
6107 6107 pg->sc_pgroup_name);
6108 6108 return (EBUSY);
6109 6109
6110 6110 case ECONNABORTED:
6111 6111 case EBADF:
6112 6112 case ENOMEM:
6113 6113 case EACCES:
6114 6114 return (r);
6115 6115
6116 6116 default:
6117 6117 bad_error("load_pg", r);
6118 6118 }
6119 6119 report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6120 6120 internal_pgroup_free(rpg);
6121 6121 rpg = NULL;
6122 6122 }
6123 6123
6124 6124 return (0);
6125 6125 }
6126 6126
6127 6127 /*
6128 6128 * Import an instance. If it doesn't exist, create it. If it has
6129 6129 * a last-import snapshot, upgrade its properties. Finish by updating its
6130 6130 * last-import snapshot. If it doesn't have a last-import snapshot then it
6131 6131 * could have been created for a dependent tag in another manifest. Import the
6132 6132 * new properties. If there's a conflict, don't override, like now?
6133 6133 *
6134 6134 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
6135 6135 * lcbdata->sc_err to
6136 6136 * ECONNABORTED - repository connection broken
6137 6137 * ENOMEM - out of memory
6138 6138 * ENOSPC - svc.configd is out of resources
6139 6139 * EEXIST - dependency collision in dependent service (error printed)
6140 6140 * EPERM - couldn't create temporary instance (permission denied)
6141 6141 * - couldn't import into temporary instance (permission denied)
6142 6142 * - couldn't take snapshot (permission denied)
6143 6143 * - couldn't upgrade properties (permission denied)
6144 6144 * - couldn't import properties (permission denied)
6145 6145 * - couldn't import dependents (permission denied)
6146 6146 * EROFS - couldn't create temporary instance (repository read-only)
6147 6147 * - couldn't import into temporary instance (repository read-only)
6148 6148 * - couldn't upgrade properties (repository read-only)
6149 6149 * - couldn't import properties (repository read-only)
6150 6150 * - couldn't import dependents (repository read-only)
6151 6151 * EACCES - couldn't create temporary instance (backend access denied)
6152 6152 * - couldn't import into temporary instance (backend access denied)
6153 6153 * - couldn't upgrade properties (backend access denied)
6154 6154 * - couldn't import properties (backend access denied)
6155 6155 * - couldn't import dependents (backend access denied)
6156 6156 * EINVAL - invalid instance name (error printed)
6157 6157 * - invalid pgroup_t's (error printed)
6158 6158 * - invalid dependents (error printed)
6159 6159 * EBUSY - temporary service deleted (error printed)
6160 6160 * - temporary instance deleted (error printed)
6161 6161 * - temporary instance changed (error printed)
6162 6162 * - temporary instance already exists (error printed)
6163 6163 * - instance deleted (error printed)
6164 6164 * EBADF - instance has corrupt last-import snapshot (error printed)
6165 6165 * - instance is corrupt (error printed)
6166 6166 * - dependent has corrupt pg (error printed)
6167 6167 * - dependent target has a corrupt snapshot (error printed)
6168 6168 * -1 - unknown libscf error (error printed)
6169 6169 */
6170 6170 static int
6171 6171 lscf_instance_import(void *v, void *pvt)
6172 6172 {
6173 6173 entity_t *inst = v;
6174 6174 scf_callback_t ctx;
6175 6175 scf_callback_t *lcbdata = pvt;
6176 6176 scf_service_t *rsvc = lcbdata->sc_parent;
6177 6177 int r;
6178 6178 scf_snaplevel_t *running;
6179 6179 int flags = lcbdata->sc_flags;
6180 6180
6181 6181 const char * const emsg_tdel =
6182 6182 gettext("Temporary instance svc:/%s:%s was deleted.\n");
6183 6183 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6184 6184 "changed unexpectedly.\n");
6185 6185 const char * const emsg_del = gettext("%s changed unexpectedly "
6186 6186 "(instance \"%s\" was deleted.)\n");
6187 6187 const char * const emsg_badsnap = gettext(
6188 6188 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6189 6189
6190 6190 /*
6191 6191 * prepare last-import snapshot:
6192 6192 * create temporary instance (service was precreated)
6193 6193 * populate with properties from bundle
6194 6194 * take snapshot
6195 6195 */
6196 6196 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6197 6197 switch (scf_error()) {
6198 6198 case SCF_ERROR_CONNECTION_BROKEN:
6199 6199 case SCF_ERROR_NO_RESOURCES:
6200 6200 case SCF_ERROR_BACKEND_READONLY:
6201 6201 case SCF_ERROR_BACKEND_ACCESS:
6202 6202 return (stash_scferror(lcbdata));
6203 6203
6204 6204 case SCF_ERROR_EXISTS:
6205 6205 warn(gettext("Temporary service svc:/%s "
6206 6206 "changed unexpectedly (instance \"%s\" added).\n"),
6207 6207 imp_tsname, inst->sc_name);
6208 6208 lcbdata->sc_err = EBUSY;
6209 6209 return (UU_WALK_ERROR);
6210 6210
6211 6211 case SCF_ERROR_DELETED:
6212 6212 warn(gettext("Temporary service svc:/%s "
6213 6213 "was deleted unexpectedly.\n"), imp_tsname);
6214 6214 lcbdata->sc_err = EBUSY;
6215 6215 return (UU_WALK_ERROR);
6216 6216
6217 6217 case SCF_ERROR_INVALID_ARGUMENT:
6218 6218 warn(gettext("Invalid instance name \"%s\".\n"),
6219 6219 inst->sc_name);
6220 6220 return (stash_scferror(lcbdata));
6221 6221
6222 6222 case SCF_ERROR_PERMISSION_DENIED:
6223 6223 warn(gettext("Could not create temporary instance "
6224 6224 "\"%s\" in svc:/%s (permission denied).\n"),
6225 6225 inst->sc_name, imp_tsname);
6226 6226 return (stash_scferror(lcbdata));
6227 6227
6228 6228 case SCF_ERROR_HANDLE_MISMATCH:
6229 6229 case SCF_ERROR_NOT_BOUND:
6230 6230 case SCF_ERROR_NOT_SET:
6231 6231 default:
6232 6232 bad_error("scf_service_add_instance", scf_error());
6233 6233 }
6234 6234 }
6235 6235
6236 6236 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6237 6237 inst->sc_name);
6238 6238 if (r < 0)
6239 6239 bad_error("snprintf", errno);
6240 6240
6241 6241 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6242 6242 lcbdata->sc_flags | SCI_NOENABLED);
6243 6243 switch (r) {
6244 6244 case 0:
6245 6245 break;
6246 6246
6247 6247 case ECANCELED:
6248 6248 warn(emsg_tdel, imp_tsname, inst->sc_name);
6249 6249 lcbdata->sc_err = EBUSY;
6250 6250 r = UU_WALK_ERROR;
6251 6251 goto deltemp;
6252 6252
6253 6253 case EEXIST:
6254 6254 warn(emsg_tchg, imp_tsname, inst->sc_name);
6255 6255 lcbdata->sc_err = EBUSY;
6256 6256 r = UU_WALK_ERROR;
6257 6257 goto deltemp;
6258 6258
6259 6259 case ECONNABORTED:
6260 6260 goto connaborted;
6261 6261
6262 6262 case ENOMEM:
6263 6263 case ENOSPC:
6264 6264 case EPERM:
6265 6265 case EROFS:
6266 6266 case EACCES:
6267 6267 case EINVAL:
6268 6268 case EBUSY:
6269 6269 lcbdata->sc_err = r;
6270 6270 r = UU_WALK_ERROR;
6271 6271 goto deltemp;
6272 6272
6273 6273 default:
6274 6274 bad_error("lscf_import_instance_pgs", r);
6275 6275 }
6276 6276
6277 6277 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6278 6278 inst->sc_name);
6279 6279 if (r < 0)
6280 6280 bad_error("snprintf", errno);
6281 6281
6282 6282 ctx.sc_handle = lcbdata->sc_handle;
6283 6283 ctx.sc_parent = imp_tinst;
6284 6284 ctx.sc_service = 0;
6285 6285 ctx.sc_source_fmri = inst->sc_fmri;
6286 6286 ctx.sc_target_fmri = imp_str;
6287 6287 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6288 6288 UU_DEFAULT) != 0) {
6289 6289 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6290 6290 bad_error("uu_list_walk", uu_error());
6291 6291
6292 6292 switch (ctx.sc_err) {
6293 6293 case ECONNABORTED:
6294 6294 goto connaborted;
6295 6295
6296 6296 case ECANCELED:
6297 6297 warn(emsg_tdel, imp_tsname, inst->sc_name);
6298 6298 lcbdata->sc_err = EBUSY;
6299 6299 break;
6300 6300
6301 6301 case EEXIST:
6302 6302 warn(emsg_tchg, imp_tsname, inst->sc_name);
6303 6303 lcbdata->sc_err = EBUSY;
6304 6304 break;
6305 6305
6306 6306 default:
6307 6307 lcbdata->sc_err = ctx.sc_err;
6308 6308 }
6309 6309 r = UU_WALK_ERROR;
6310 6310 goto deltemp;
6311 6311 }
6312 6312
6313 6313 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6314 6314 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6315 6315 switch (scf_error()) {
6316 6316 case SCF_ERROR_CONNECTION_BROKEN:
6317 6317 goto connaborted;
6318 6318
6319 6319 case SCF_ERROR_NO_RESOURCES:
6320 6320 r = stash_scferror(lcbdata);
6321 6321 goto deltemp;
6322 6322
6323 6323 case SCF_ERROR_EXISTS:
6324 6324 warn(emsg_tchg, imp_tsname, inst->sc_name);
6325 6325 lcbdata->sc_err = EBUSY;
6326 6326 r = UU_WALK_ERROR;
6327 6327 goto deltemp;
6328 6328
6329 6329 case SCF_ERROR_PERMISSION_DENIED:
6330 6330 warn(gettext("Could not take \"%s\" snapshot of %s "
6331 6331 "(permission denied).\n"), snap_lastimport,
6332 6332 imp_str);
6333 6333 r = stash_scferror(lcbdata);
6334 6334 goto deltemp;
6335 6335
6336 6336 default:
6337 6337 scfwarn();
6338 6338 lcbdata->sc_err = -1;
6339 6339 r = UU_WALK_ERROR;
6340 6340 goto deltemp;
6341 6341
6342 6342 case SCF_ERROR_HANDLE_MISMATCH:
6343 6343 case SCF_ERROR_INVALID_ARGUMENT:
6344 6344 case SCF_ERROR_NOT_SET:
6345 6345 bad_error("_scf_snapshot_take_new_named", scf_error());
6346 6346 }
6347 6347 }
6348 6348
6349 6349 if (lcbdata->sc_flags & SCI_FRESH)
6350 6350 goto fresh;
6351 6351
6352 6352 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6353 6353 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6354 6354 imp_lisnap) != 0) {
6355 6355 switch (scf_error()) {
6356 6356 case SCF_ERROR_DELETED:
6357 6357 warn(emsg_del, inst->sc_parent->sc_fmri,
6358 6358 inst->sc_name);
6359 6359 lcbdata->sc_err = EBUSY;
6360 6360 r = UU_WALK_ERROR;
6361 6361 goto deltemp;
6362 6362
6363 6363 case SCF_ERROR_NOT_FOUND:
6364 6364 flags |= SCI_FORCE;
6365 6365 goto nosnap;
6366 6366
6367 6367 case SCF_ERROR_CONNECTION_BROKEN:
6368 6368 goto connaborted;
6369 6369
6370 6370 case SCF_ERROR_INVALID_ARGUMENT:
6371 6371 case SCF_ERROR_HANDLE_MISMATCH:
6372 6372 case SCF_ERROR_NOT_BOUND:
6373 6373 case SCF_ERROR_NOT_SET:
6374 6374 default:
6375 6375 bad_error("scf_instance_get_snapshot",
6376 6376 scf_error());
6377 6377 }
6378 6378 }
6379 6379
6380 6380 /* upgrade */
6381 6381
6382 6382 /*
6383 6383 * compare new properties with last-import properties
6384 6384 * upgrade current properties
6385 6385 */
6386 6386 /* clear sc_sceen for pgs */
6387 6387 if (uu_list_walk(inst->sc_pgroups, clear_int,
6388 6388 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6389 6389 0)
6390 6390 bad_error("uu_list_walk", uu_error());
6391 6391
6392 6392 r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6393 6393 switch (r) {
6394 6394 case 0:
6395 6395 break;
6396 6396
6397 6397 case ECONNABORTED:
6398 6398 goto connaborted;
6399 6399
6400 6400 case ECANCELED:
6401 6401 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6402 6402 lcbdata->sc_err = EBUSY;
6403 6403 r = UU_WALK_ERROR;
6404 6404 goto deltemp;
6405 6405
6406 6406 case ENOENT:
6407 6407 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6408 6408 lcbdata->sc_err = EBADF;
6409 6409 r = UU_WALK_ERROR;
6410 6410 goto deltemp;
6411 6411
6412 6412 default:
6413 6413 bad_error("get_snaplevel", r);
6414 6414 }
6415 6415
6416 6416 if (scf_instance_get_snapshot(imp_inst, snap_running,
6417 6417 imp_rsnap) != 0) {
6418 6418 switch (scf_error()) {
6419 6419 case SCF_ERROR_DELETED:
6420 6420 warn(emsg_del, inst->sc_parent->sc_fmri,
6421 6421 inst->sc_name);
6422 6422 lcbdata->sc_err = EBUSY;
6423 6423 r = UU_WALK_ERROR;
6424 6424 goto deltemp;
6425 6425
6426 6426 case SCF_ERROR_NOT_FOUND:
6427 6427 break;
6428 6428
6429 6429 case SCF_ERROR_CONNECTION_BROKEN:
6430 6430 goto connaborted;
6431 6431
6432 6432 case SCF_ERROR_INVALID_ARGUMENT:
6433 6433 case SCF_ERROR_HANDLE_MISMATCH:
6434 6434 case SCF_ERROR_NOT_BOUND:
6435 6435 case SCF_ERROR_NOT_SET:
6436 6436 default:
6437 6437 bad_error("scf_instance_get_snapshot",
6438 6438 scf_error());
6439 6439 }
6440 6440
6441 6441 running = NULL;
6442 6442 } else {
6443 6443 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6444 6444 switch (r) {
6445 6445 case 0:
6446 6446 running = imp_rsnpl;
6447 6447 break;
6448 6448
6449 6449 case ECONNABORTED:
6450 6450 goto connaborted;
6451 6451
6452 6452 case ECANCELED:
6453 6453 warn(emsg_del, inst->sc_parent->sc_fmri,
6454 6454 inst->sc_name);
6455 6455 lcbdata->sc_err = EBUSY;
6456 6456 r = UU_WALK_ERROR;
6457 6457 goto deltemp;
6458 6458
6459 6459 case ENOENT:
6460 6460 warn(emsg_badsnap, snap_running, inst->sc_fmri);
6461 6461 lcbdata->sc_err = EBADF;
6462 6462 r = UU_WALK_ERROR;
6463 6463 goto deltemp;
6464 6464
6465 6465 default:
6466 6466 bad_error("get_snaplevel", r);
6467 6467 }
6468 6468 }
6469 6469
6470 6470 r = upgrade_props(imp_inst, running, imp_snpl, inst);
6471 6471 switch (r) {
6472 6472 case 0:
6473 6473 break;
6474 6474
6475 6475 case ECANCELED:
6476 6476 case ENODEV:
6477 6477 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6478 6478 lcbdata->sc_err = EBUSY;
6479 6479 r = UU_WALK_ERROR;
6480 6480 goto deltemp;
6481 6481
6482 6482 case ECONNABORTED:
6483 6483 goto connaborted;
6484 6484
6485 6485 case ENOMEM:
6486 6486 case ENOSPC:
6487 6487 case EBADF:
6488 6488 case EBUSY:
6489 6489 case EINVAL:
6490 6490 case EPERM:
6491 6491 case EROFS:
6492 6492 case EACCES:
6493 6493 case EEXIST:
6494 6494 lcbdata->sc_err = r;
6495 6495 r = UU_WALK_ERROR;
6496 6496 goto deltemp;
6497 6497
6498 6498 default:
6499 6499 bad_error("upgrade_props", r);
6500 6500 }
6501 6501
6502 6502 inst->sc_import_state = IMPORT_PROP_DONE;
6503 6503 } else {
6504 6504 switch (scf_error()) {
6505 6505 case SCF_ERROR_CONNECTION_BROKEN:
6506 6506 goto connaborted;
6507 6507
6508 6508 case SCF_ERROR_NOT_FOUND:
6509 6509 break;
6510 6510
6511 6511 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6512 6512 case SCF_ERROR_HANDLE_MISMATCH:
6513 6513 case SCF_ERROR_NOT_BOUND:
6514 6514 case SCF_ERROR_NOT_SET:
6515 6515 default:
6516 6516 bad_error("scf_service_get_instance", scf_error());
6517 6517 }
6518 6518
6519 6519 fresh:
6520 6520 /* create instance */
6521 6521 if (scf_service_add_instance(rsvc, inst->sc_name,
6522 6522 imp_inst) != 0) {
6523 6523 switch (scf_error()) {
6524 6524 case SCF_ERROR_CONNECTION_BROKEN:
6525 6525 goto connaborted;
6526 6526
6527 6527 case SCF_ERROR_NO_RESOURCES:
6528 6528 case SCF_ERROR_BACKEND_READONLY:
6529 6529 case SCF_ERROR_BACKEND_ACCESS:
6530 6530 r = stash_scferror(lcbdata);
6531 6531 goto deltemp;
6532 6532
6533 6533 case SCF_ERROR_EXISTS:
6534 6534 warn(gettext("%s changed unexpectedly "
6535 6535 "(instance \"%s\" added).\n"),
6536 6536 inst->sc_parent->sc_fmri, inst->sc_name);
6537 6537 lcbdata->sc_err = EBUSY;
6538 6538 r = UU_WALK_ERROR;
6539 6539 goto deltemp;
6540 6540
6541 6541 case SCF_ERROR_PERMISSION_DENIED:
6542 6542 warn(gettext("Could not create \"%s\" instance "
6543 6543 "in %s (permission denied).\n"),
6544 6544 inst->sc_name, inst->sc_parent->sc_fmri);
6545 6545 r = stash_scferror(lcbdata);
6546 6546 goto deltemp;
6547 6547
6548 6548 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6549 6549 case SCF_ERROR_HANDLE_MISMATCH:
6550 6550 case SCF_ERROR_NOT_BOUND:
6551 6551 case SCF_ERROR_NOT_SET:
6552 6552 default:
6553 6553 bad_error("scf_service_add_instance",
6554 6554 scf_error());
6555 6555 }
6556 6556 }
6557 6557
6558 6558 nosnap:
6559 6559 /*
6560 6560 * Create a last-import snapshot to serve as an attachment
6561 6561 * point for the real one from the temporary instance. Since
6562 6562 * the contents is irrelevant, take it now, while the instance
6563 6563 * is empty, to minimize svc.configd's work.
6564 6564 */
6565 6565 if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6566 6566 imp_lisnap) != 0) {
6567 6567 switch (scf_error()) {
6568 6568 case SCF_ERROR_CONNECTION_BROKEN:
6569 6569 goto connaborted;
6570 6570
6571 6571 case SCF_ERROR_NO_RESOURCES:
6572 6572 r = stash_scferror(lcbdata);
6573 6573 goto deltemp;
6574 6574
6575 6575 case SCF_ERROR_EXISTS:
6576 6576 warn(gettext("%s changed unexpectedly "
6577 6577 "(snapshot \"%s\" added).\n"),
6578 6578 inst->sc_fmri, snap_lastimport);
6579 6579 lcbdata->sc_err = EBUSY;
6580 6580 r = UU_WALK_ERROR;
6581 6581 goto deltemp;
6582 6582
6583 6583 case SCF_ERROR_PERMISSION_DENIED:
6584 6584 warn(gettext("Could not take \"%s\" snapshot "
6585 6585 "of %s (permission denied).\n"),
6586 6586 snap_lastimport, inst->sc_fmri);
6587 6587 r = stash_scferror(lcbdata);
6588 6588 goto deltemp;
6589 6589
6590 6590 default:
6591 6591 scfwarn();
6592 6592 lcbdata->sc_err = -1;
6593 6593 r = UU_WALK_ERROR;
6594 6594 goto deltemp;
6595 6595
6596 6596 case SCF_ERROR_NOT_SET:
6597 6597 case SCF_ERROR_INTERNAL:
6598 6598 case SCF_ERROR_INVALID_ARGUMENT:
6599 6599 case SCF_ERROR_HANDLE_MISMATCH:
6600 6600 bad_error("_scf_snapshot_take_new",
6601 6601 scf_error());
6602 6602 }
6603 6603 }
6604 6604
6605 6605 if (li_only)
6606 6606 goto lionly;
6607 6607
6608 6608 inst->sc_import_state = IMPORT_PROP_BEGUN;
6609 6609
6610 6610 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6611 6611 flags);
6612 6612 switch (r) {
6613 6613 case 0:
6614 6614 break;
6615 6615
6616 6616 case ECONNABORTED:
6617 6617 goto connaborted;
6618 6618
6619 6619 case ECANCELED:
6620 6620 warn(gettext("%s changed unexpectedly "
6621 6621 "(instance \"%s\" deleted).\n"),
6622 6622 inst->sc_parent->sc_fmri, inst->sc_name);
6623 6623 lcbdata->sc_err = EBUSY;
6624 6624 r = UU_WALK_ERROR;
6625 6625 goto deltemp;
6626 6626
6627 6627 case EEXIST:
6628 6628 warn(gettext("%s changed unexpectedly "
6629 6629 "(property group added).\n"), inst->sc_fmri);
6630 6630 lcbdata->sc_err = EBUSY;
6631 6631 r = UU_WALK_ERROR;
6632 6632 goto deltemp;
6633 6633
6634 6634 default:
6635 6635 lcbdata->sc_err = r;
6636 6636 r = UU_WALK_ERROR;
6637 6637 goto deltemp;
6638 6638
6639 6639 case EINVAL: /* caught above */
6640 6640 bad_error("lscf_import_instance_pgs", r);
6641 6641 }
6642 6642
6643 6643 ctx.sc_parent = imp_inst;
6644 6644 ctx.sc_service = 0;
6645 6645 ctx.sc_trans = NULL;
6646 6646 ctx.sc_flags = 0;
6647 6647 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6648 6648 &ctx, UU_DEFAULT) != 0) {
6649 6649 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6650 6650 bad_error("uu_list_walk", uu_error());
6651 6651
6652 6652 if (ctx.sc_err == ECONNABORTED)
6653 6653 goto connaborted;
6654 6654 lcbdata->sc_err = ctx.sc_err;
6655 6655 r = UU_WALK_ERROR;
6656 6656 goto deltemp;
6657 6657 }
6658 6658
6659 6659 inst->sc_import_state = IMPORT_PROP_DONE;
6660 6660
6661 6661 if (g_verbose)
6662 6662 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6663 6663 snap_initial, inst->sc_fmri);
6664 6664 r = take_snap(imp_inst, snap_initial, imp_snap);
6665 6665 switch (r) {
6666 6666 case 0:
6667 6667 break;
6668 6668
6669 6669 case ECONNABORTED:
6670 6670 goto connaborted;
6671 6671
6672 6672 case ENOSPC:
6673 6673 case -1:
6674 6674 lcbdata->sc_err = r;
6675 6675 r = UU_WALK_ERROR;
6676 6676 goto deltemp;
6677 6677
6678 6678 case ECANCELED:
6679 6679 warn(gettext("%s changed unexpectedly "
6680 6680 "(instance %s deleted).\n"),
6681 6681 inst->sc_parent->sc_fmri, inst->sc_name);
6682 6682 lcbdata->sc_err = r;
6683 6683 r = UU_WALK_ERROR;
6684 6684 goto deltemp;
6685 6685
6686 6686 case EPERM:
6687 6687 warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6688 6688 lcbdata->sc_err = r;
6689 6689 r = UU_WALK_ERROR;
6690 6690 goto deltemp;
6691 6691
6692 6692 default:
6693 6693 bad_error("take_snap", r);
6694 6694 }
6695 6695 }
6696 6696
6697 6697 lionly:
6698 6698 if (lcbdata->sc_flags & SCI_NOSNAP)
6699 6699 goto deltemp;
6700 6700
6701 6701 /* transfer snapshot from temporary instance */
6702 6702 if (g_verbose)
6703 6703 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6704 6704 snap_lastimport, inst->sc_fmri);
6705 6705 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6706 6706 switch (scf_error()) {
6707 6707 case SCF_ERROR_CONNECTION_BROKEN:
6708 6708 goto connaborted;
6709 6709
6710 6710 case SCF_ERROR_NO_RESOURCES:
6711 6711 r = stash_scferror(lcbdata);
6712 6712 goto deltemp;
6713 6713
6714 6714 case SCF_ERROR_PERMISSION_DENIED:
6715 6715 warn(gettext("Could not take \"%s\" snapshot for %s "
6716 6716 "(permission denied).\n"), snap_lastimport,
6717 6717 inst->sc_fmri);
6718 6718 r = stash_scferror(lcbdata);
6719 6719 goto deltemp;
6720 6720
6721 6721 case SCF_ERROR_NOT_SET:
6722 6722 case SCF_ERROR_HANDLE_MISMATCH:
6723 6723 default:
6724 6724 bad_error("_scf_snapshot_attach", scf_error());
6725 6725 }
6726 6726 }
6727 6727
6728 6728 inst->sc_import_state = IMPORT_COMPLETE;
6729 6729
6730 6730 r = UU_WALK_NEXT;
6731 6731
6732 6732 deltemp:
6733 6733 /* delete temporary instance */
6734 6734 if (scf_instance_delete(imp_tinst) != 0) {
6735 6735 switch (scf_error()) {
6736 6736 case SCF_ERROR_DELETED:
6737 6737 break;
6738 6738
6739 6739 case SCF_ERROR_CONNECTION_BROKEN:
6740 6740 goto connaborted;
6741 6741
6742 6742 case SCF_ERROR_NOT_SET:
6743 6743 case SCF_ERROR_NOT_BOUND:
6744 6744 default:
6745 6745 bad_error("scf_instance_delete", scf_error());
6746 6746 }
6747 6747 }
6748 6748
6749 6749 return (r);
6750 6750
6751 6751 connaborted:
6752 6752 warn(gettext("Could not delete svc:/%s:%s "
6753 6753 "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6754 6754 lcbdata->sc_err = ECONNABORTED;
6755 6755 return (UU_WALK_ERROR);
6756 6756 }
6757 6757
6758 6758 /*
6759 6759 * When an instance is imported we end up telling configd about it. Once we tell
6760 6760 * configd about these changes, startd eventually notices. If this is a new
6761 6761 * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6762 6762 * property group. However, many of the other tools expect that this property
6763 6763 * group exists and has certain values.
6764 6764 *
6765 6765 * These values are added asynchronously by startd. We should not return from
6766 6766 * this routine until we can verify that the property group we need is there.
6767 6767 *
6768 6768 * Before we go ahead and verify this, we have to ask ourselves an important
6769 6769 * question: Is the early manifest service currently running? Because if it is
6770 6770 * running and it has invoked us, then the service will never get a restarter
6771 6771 * property because svc.startd is blocked on EMI finishing before it lets itself
6772 6772 * fully connect to svc.configd. Of course, this means that this race condition
6773 6773 * is in fact impossible to 100% eliminate.
6774 6774 *
6775 6775 * svc.startd makes sure that EMI only runs once and has succeeded by checking
6776 6776 * the state of the EMI instance. If it is online it bails out and makes sure
6777 6777 * that it doesn't run again. In this case, we're going to do something similar,
6778 6778 * only if the state is online, then we're going to actually verify. EMI always
6779 6779 * has to be present, but it can be explicitly disabled to reduce the amount of
6780 6780 * damage it can cause. If EMI has been disabled then we no longer have to worry
6781 6781 * about the implicit race condition and can go ahead and check things. If EMI
6782 6782 * is in some state that isn't online or disabled and isn't runinng, then we
6783 6783 * assume that things are rather bad and we're not going to get in your way,
6784 6784 * even if the rest of SMF does.
6785 6785 *
6786 6786 * Returns 0 on success or returns an errno.
6787 6787 */
6788 6788 #ifndef NATIVE_BUILD
6789 6789 static int
6790 6790 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6791 6791 {
6792 6792 int ret, err;
6793 6793 struct timespec ts;
6794 6794 char *emi_state;
6795 6795
6796 6796 /*
6797 6797 * smf_get_state does not distinguish between its different failure
6798 6798 * modes: memory allocation failures, SMF internal failures, and a lack
6799 6799 * of EMI entirely because it's been removed. In these cases, we're
6800 6800 * going to be conservative and opt to say that if we don't know, better
6801 6801 * to not block import or falsely warn to the user.
6802 6802 */
6803 6803 if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
6804 6804 return (0);
6805 6805 }
6806 6806
6807 6807 /*
6808 6808 * As per the block comment for this function check the state of EMI
6809 6809 */
6810 6810 if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6811 6811 strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6812 6812 warn(gettext("Not validating instance %s:%s because EMI's "
6813 6813 "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6814 6814 free(emi_state);
6815 6815 return (0);
6816 6816 }
6817 6817
6818 6818 free(emi_state);
6819 6819
6820 6820 /*
6821 6821 * First we have to get the property.
6822 6822 */
6823 6823 if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6824 6824 ret = scf_error();
6825 6825 warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6826 6826 return (ret);
6827 6827 }
6828 6828
6829 6829 /*
6830 6830 * We should always be able to get the instance. It should already
6831 6831 * exist because we just created it or got it. There probably is a
6832 6832 * slim chance that someone may have come in and deleted it though from
6833 6833 * under us.
6834 6834 */
6835 6835 if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6836 6836 != 0) {
6837 6837 ret = scf_error();
6838 6838 warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6839 6839 switch (ret) {
6840 6840 case SCF_ERROR_DELETED:
6841 6841 err = ENODEV;
6842 6842 break;
6843 6843 case SCF_ERROR_CONNECTION_BROKEN:
6844 6844 warn(gettext("Lost repository connection\n"));
6845 6845 err = ECONNABORTED;
6846 6846 break;
6847 6847 case SCF_ERROR_NOT_FOUND:
6848 6848 warn(gettext("Instance \"%s\" disappeared out from "
6849 6849 "under us.\n"), inst->sc_name);
6850 6850 err = ENOENT;
6851 6851 break;
6852 6852 default:
6853 6853 bad_error("scf_service_get_instance", ret);
6854 6854 }
6855 6855
6856 6856 return (err);
6857 6857 }
6858 6858
6859 6859 /*
6860 6860 * An astute observer may want to use _scf_wait_pg which would notify us
6861 6861 * of a property group change, unfortunately that does not work if the
6862 6862 * property group in question does not exist. So instead we have to
6863 6863 * manually poll and ask smf the best way to get to it.
6864 6864 */
6865 6865 while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6866 6866 != SCF_SUCCESS) {
6867 6867 ret = scf_error();
6868 6868 if (ret != SCF_ERROR_NOT_FOUND) {
6869 6869 warn(gettext("Failed to get restarter property "
6870 6870 "group for instance: %s\n"), inst->sc_name);
6871 6871 switch (ret) {
6872 6872 case SCF_ERROR_DELETED:
6873 6873 err = ENODEV;
6874 6874 break;
6875 6875 case SCF_ERROR_CONNECTION_BROKEN:
6876 6876 warn(gettext("Lost repository connection\n"));
6877 6877 err = ECONNABORTED;
6878 6878 break;
6879 6879 default:
6880 6880 bad_error("scf_service_get_instance", ret);
6881 6881 }
6882 6882
6883 6883 return (err);
6884 6884 }
6885 6885
6886 6886 ts.tv_sec = pg_timeout / NANOSEC;
6887 6887 ts.tv_nsec = pg_timeout % NANOSEC;
6888 6888
6889 6889 (void) nanosleep(&ts, NULL);
6890 6890 }
6891 6891
6892 6892 /*
6893 6893 * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6894 6894 * So in addition to the property group being present, we need to wait
6895 6895 * for the property to be there in some form.
6896 6896 *
6897 6897 * Note that a property group is a frozen snapshot in time. To properly
6898 6898 * get beyond this, you have to refresh the property group each time.
6899 6899 */
6900 6900 while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6901 6901 imp_prop)) != 0) {
6902 6902
6903 6903 ret = scf_error();
6904 6904 if (ret != SCF_ERROR_NOT_FOUND) {
6905 6905 warn(gettext("Failed to get property %s from the "
6906 6906 "restarter property group of instance %s\n"),
6907 6907 SCF_PROPERTY_STATE, inst->sc_name);
6908 6908 switch (ret) {
6909 6909 case SCF_ERROR_CONNECTION_BROKEN:
6910 6910 warn(gettext("Lost repository connection\n"));
6911 6911 err = ECONNABORTED;
6912 6912 break;
6913 6913 case SCF_ERROR_DELETED:
6914 6914 err = ENODEV;
6915 6915 break;
6916 6916 default:
6917 6917 bad_error("scf_pg_get_property", ret);
6918 6918 }
6919 6919
6920 6920 return (err);
6921 6921 }
6922 6922
6923 6923 ts.tv_sec = pg_timeout / NANOSEC;
6924 6924 ts.tv_nsec = pg_timeout % NANOSEC;
6925 6925
6926 6926 (void) nanosleep(&ts, NULL);
6927 6927
6928 6928 ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6929 6929 if (ret != SCF_SUCCESS) {
6930 6930 warn(gettext("Failed to get restarter property "
6931 6931 "group for instance: %s\n"), inst->sc_name);
6932 6932 switch (ret) {
6933 6933 case SCF_ERROR_DELETED:
6934 6934 err = ENODEV;
6935 6935 break;
6936 6936 case SCF_ERROR_CONNECTION_BROKEN:
6937 6937 warn(gettext("Lost repository connection\n"));
6938 6938 err = ECONNABORTED;
6939 6939 break;
6940 6940 default:
6941 6941 bad_error("scf_service_get_instance", ret);
6942 6942 }
6943 6943
6944 6944 return (err);
6945 6945 }
6946 6946 }
6947 6947
6948 6948 /*
6949 6949 * We don't have to free the property groups or other values that we got
6950 6950 * because we stored them in global variables that are allocated and
6951 6951 * freed by the routines that call into these functions. Unless of
6952 6952 * course the rest of the code here that we are basing this on is
6953 6953 * mistaken.
6954 6954 */
6955 6955 return (0);
6956 6956 }
6957 6957 #endif
6958 6958
6959 6959 /*
6960 6960 * If the service is missing, create it, import its properties, and import the
6961 6961 * instances. Since the service is brand new, it should be empty, and if we
6962 6962 * run into any existing entities (SCF_ERROR_EXISTS), abort.
6963 6963 *
6964 6964 * If the service exists, we want to upgrade its properties and import the
6965 6965 * instances. Upgrade requires a last-import snapshot, though, which are
6966 6966 * children of instances, so first we'll have to go through the instances
6967 6967 * looking for a last-import snapshot. If we don't find one then we'll just
6968 6968 * override-import the service properties (but don't delete existing
6969 6969 * properties: another service might have declared us as a dependent). Before
6970 6970 * we change anything, though, we want to take the previous snapshots. We
6971 6971 * also give lscf_instance_import() a leg up on taking last-import snapshots
6972 6972 * by importing the manifest's service properties into a temporary service.
6973 6973 *
6974 6974 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and
6975 6975 * sets lcbdata->sc_err to
6976 6976 * ECONNABORTED - repository connection broken
6977 6977 * ENOMEM - out of memory
6978 6978 * ENOSPC - svc.configd is out of resources
6979 6979 * EPERM - couldn't create temporary service (error printed)
6980 6980 * - couldn't import into temp service (error printed)
6981 6981 * - couldn't create service (error printed)
6982 6982 * - couldn't import dependent (error printed)
6983 6983 * - couldn't take snapshot (error printed)
6984 6984 * - couldn't create instance (error printed)
6985 6985 * - couldn't create, modify, or delete pg (error printed)
6986 6986 * - couldn't create, modify, or delete dependent (error printed)
6987 6987 * - couldn't import instance (error printed)
6988 6988 * EROFS - couldn't create temporary service (repository read-only)
6989 6989 * - couldn't import into temporary service (repository read-only)
6990 6990 * - couldn't create service (repository read-only)
6991 6991 * - couldn't import dependent (repository read-only)
6992 6992 * - couldn't create instance (repository read-only)
6993 6993 * - couldn't create, modify, or delete pg or dependent
6994 6994 * - couldn't import instance (repository read-only)
6995 6995 * EACCES - couldn't create temporary service (backend access denied)
6996 6996 * - couldn't import into temporary service (backend access denied)
6997 6997 * - couldn't create service (backend access denied)
6998 6998 * - couldn't import dependent (backend access denied)
6999 6999 * - couldn't create instance (backend access denied)
7000 7000 * - couldn't create, modify, or delete pg or dependent
7001 7001 * - couldn't import instance (backend access denied)
7002 7002 * EINVAL - service name is invalid (error printed)
7003 7003 * - service name is too long (error printed)
7004 7004 * - s has invalid pgroup (error printed)
7005 7005 * - s has invalid dependent (error printed)
7006 7006 * - instance name is invalid (error printed)
7007 7007 * - instance entity_t is invalid (error printed)
7008 7008 * EEXIST - couldn't create temporary service (already exists) (error printed)
7009 7009 * - couldn't import dependent (dependency pg already exists) (printed)
7010 7010 * - dependency collision in dependent service (error printed)
7011 7011 * EBUSY - temporary service deleted (error printed)
7012 7012 * - property group added to temporary service (error printed)
7013 7013 * - new property group changed or was deleted (error printed)
7014 7014 * - service was added unexpectedly (error printed)
7015 7015 * - service was deleted unexpectedly (error printed)
7016 7016 * - property group added to new service (error printed)
7017 7017 * - instance added unexpectedly (error printed)
7018 7018 * - instance deleted unexpectedly (error printed)
7019 7019 * - dependent service deleted unexpectedly (error printed)
7020 7020 * - pg was added, changed, or deleted (error printed)
7021 7021 * - dependent pg changed (error printed)
7022 7022 * - temporary instance added, changed, or deleted (error printed)
7023 7023 * EBADF - a last-import snapshot is corrupt (error printed)
7024 7024 * - the service is corrupt (error printed)
7025 7025 * - a dependent is corrupt (error printed)
7026 7026 * - an instance is corrupt (error printed)
7027 7027 * - an instance has a corrupt last-import snapshot (error printed)
7028 7028 * - dependent target has a corrupt snapshot (error printed)
7029 7029 * -1 - unknown libscf error (error printed)
7030 7030 */
7031 7031 static int
7032 7032 lscf_service_import(void *v, void *pvt)
7033 7033 {
7034 7034 entity_t *s = v;
7035 7035 scf_callback_t cbdata;
7036 7036 scf_callback_t *lcbdata = pvt;
7037 7037 scf_scope_t *scope = lcbdata->sc_parent;
7038 7038 entity_t *inst, linst;
7039 7039 int r;
7040 7040 int fresh = 0;
7041 7041 scf_snaplevel_t *running;
7042 7042 int have_ge = 0;
7043 7043 boolean_t retried = B_FALSE;
7044 7044
7045 7045 const char * const ts_deleted = gettext("Temporary service svc:/%s "
7046 7046 "was deleted unexpectedly.\n");
7047 7047 const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7048 7048 "changed unexpectedly (property group added).\n");
7049 7049 const char * const s_deleted =
7050 7050 gettext("%s was deleted unexpectedly.\n");
7051 7051 const char * const i_deleted =
7052 7052 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7053 7053 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7054 7054 "is corrupt (missing service snaplevel).\n");
7055 7055 const char * const s_mfile_upd =
7056 7056 gettext("Unable to update the manifest file connection "
7057 7057 "for %s\n");
7058 7058
7059 7059 li_only = 0;
7060 7060 /* Validate the service name */
7061 7061 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7062 7062 switch (scf_error()) {
7063 7063 case SCF_ERROR_CONNECTION_BROKEN:
7064 7064 return (stash_scferror(lcbdata));
7065 7065
7066 7066 case SCF_ERROR_INVALID_ARGUMENT:
7067 7067 warn(gettext("\"%s\" is an invalid service name. "
7068 7068 "Cannot import.\n"), s->sc_name);
7069 7069 return (stash_scferror(lcbdata));
7070 7070
7071 7071 case SCF_ERROR_NOT_FOUND:
7072 7072 break;
7073 7073
7074 7074 case SCF_ERROR_HANDLE_MISMATCH:
7075 7075 case SCF_ERROR_NOT_BOUND:
7076 7076 case SCF_ERROR_NOT_SET:
7077 7077 default:
7078 7078 bad_error("scf_scope_get_service", scf_error());
7079 7079 }
7080 7080 }
7081 7081
7082 7082 /* create temporary service */
7083 7083 /*
7084 7084 * the size of the buffer was reduced to max_scf_name_len to prevent
7085 7085 * hitting bug 6681151. After the bug fix, the size of the buffer
7086 7086 * should be restored to its original value (max_scf_name_len +1)
7087 7087 */
7088 7088 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7089 7089 if (r < 0)
7090 7090 bad_error("snprintf", errno);
7091 7091 if (r > max_scf_name_len) {
7092 7092 warn(gettext(
7093 7093 "Service name \"%s\" is too long. Cannot import.\n"),
7094 7094 s->sc_name);
7095 7095 lcbdata->sc_err = EINVAL;
7096 7096 return (UU_WALK_ERROR);
7097 7097 }
7098 7098
7099 7099 retry:
7100 7100 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7101 7101 switch (scf_error()) {
7102 7102 case SCF_ERROR_CONNECTION_BROKEN:
7103 7103 case SCF_ERROR_NO_RESOURCES:
7104 7104 case SCF_ERROR_BACKEND_READONLY:
7105 7105 case SCF_ERROR_BACKEND_ACCESS:
7106 7106 return (stash_scferror(lcbdata));
7107 7107
7108 7108 case SCF_ERROR_EXISTS:
7109 7109 if (!retried) {
7110 7110 lscf_delete(imp_tsname, 0);
7111 7111 retried = B_TRUE;
7112 7112 goto retry;
7113 7113 }
7114 7114 warn(gettext(
7115 7115 "Temporary service \"%s\" must be deleted before "
7116 7116 "this manifest can be imported.\n"), imp_tsname);
7117 7117 return (stash_scferror(lcbdata));
7118 7118
7119 7119 case SCF_ERROR_PERMISSION_DENIED:
7120 7120 warn(gettext("Could not create temporary service "
7121 7121 "\"%s\" (permission denied).\n"), imp_tsname);
7122 7122 return (stash_scferror(lcbdata));
7123 7123
7124 7124 case SCF_ERROR_INVALID_ARGUMENT:
7125 7125 case SCF_ERROR_HANDLE_MISMATCH:
7126 7126 case SCF_ERROR_NOT_BOUND:
7127 7127 case SCF_ERROR_NOT_SET:
7128 7128 default:
7129 7129 bad_error("scf_scope_add_service", scf_error());
7130 7130 }
7131 7131 }
7132 7132
7133 7133 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7134 7134 if (r < 0)
7135 7135 bad_error("snprintf", errno);
7136 7136
7137 7137 cbdata.sc_handle = lcbdata->sc_handle;
7138 7138 cbdata.sc_parent = imp_tsvc;
7139 7139 cbdata.sc_service = 1;
7140 7140 cbdata.sc_source_fmri = s->sc_fmri;
7141 7141 cbdata.sc_target_fmri = imp_str;
7142 7142 cbdata.sc_flags = 0;
7143 7143
7144 7144 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7145 7145 UU_DEFAULT) != 0) {
7146 7146 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7147 7147 bad_error("uu_list_walk", uu_error());
7148 7148
7149 7149 lcbdata->sc_err = cbdata.sc_err;
7150 7150 switch (cbdata.sc_err) {
7151 7151 case ECONNABORTED:
7152 7152 goto connaborted;
7153 7153
7154 7154 case ECANCELED:
7155 7155 warn(ts_deleted, imp_tsname);
7156 7156 lcbdata->sc_err = EBUSY;
7157 7157 return (UU_WALK_ERROR);
7158 7158
7159 7159 case EEXIST:
7160 7160 warn(ts_pg_added, imp_tsname);
7161 7161 lcbdata->sc_err = EBUSY;
7162 7162 return (UU_WALK_ERROR);
7163 7163 }
7164 7164
7165 7165 r = UU_WALK_ERROR;
7166 7166 goto deltemp;
7167 7167 }
7168 7168
7169 7169 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7170 7170 UU_DEFAULT) != 0) {
7171 7171 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7172 7172 bad_error("uu_list_walk", uu_error());
7173 7173
7174 7174 lcbdata->sc_err = cbdata.sc_err;
7175 7175 switch (cbdata.sc_err) {
7176 7176 case ECONNABORTED:
7177 7177 goto connaborted;
7178 7178
7179 7179 case ECANCELED:
7180 7180 warn(ts_deleted, imp_tsname);
7181 7181 lcbdata->sc_err = EBUSY;
7182 7182 return (UU_WALK_ERROR);
7183 7183
7184 7184 case EEXIST:
7185 7185 warn(ts_pg_added, imp_tsname);
7186 7186 lcbdata->sc_err = EBUSY;
7187 7187 return (UU_WALK_ERROR);
7188 7188 }
7189 7189
7190 7190 r = UU_WALK_ERROR;
7191 7191 goto deltemp;
7192 7192 }
7193 7193
7194 7194 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7195 7195 switch (scf_error()) {
7196 7196 case SCF_ERROR_NOT_FOUND:
7197 7197 break;
7198 7198
7199 7199 case SCF_ERROR_CONNECTION_BROKEN:
7200 7200 goto connaborted;
7201 7201
7202 7202 case SCF_ERROR_INVALID_ARGUMENT:
7203 7203 case SCF_ERROR_HANDLE_MISMATCH:
7204 7204 case SCF_ERROR_NOT_BOUND:
7205 7205 case SCF_ERROR_NOT_SET:
7206 7206 default:
7207 7207 bad_error("scf_scope_get_service", scf_error());
7208 7208 }
7209 7209
7210 7210 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7211 7211 switch (scf_error()) {
7212 7212 case SCF_ERROR_CONNECTION_BROKEN:
7213 7213 goto connaborted;
7214 7214
7215 7215 case SCF_ERROR_NO_RESOURCES:
7216 7216 case SCF_ERROR_BACKEND_READONLY:
7217 7217 case SCF_ERROR_BACKEND_ACCESS:
7218 7218 r = stash_scferror(lcbdata);
7219 7219 goto deltemp;
7220 7220
7221 7221 case SCF_ERROR_EXISTS:
7222 7222 warn(gettext("Scope \"%s\" changed unexpectedly"
7223 7223 " (service \"%s\" added).\n"),
7224 7224 SCF_SCOPE_LOCAL, s->sc_name);
7225 7225 lcbdata->sc_err = EBUSY;
7226 7226 goto deltemp;
7227 7227
7228 7228 case SCF_ERROR_PERMISSION_DENIED:
7229 7229 warn(gettext("Could not create service \"%s\" "
7230 7230 "(permission denied).\n"), s->sc_name);
7231 7231 goto deltemp;
7232 7232
7233 7233 case SCF_ERROR_INVALID_ARGUMENT:
7234 7234 case SCF_ERROR_HANDLE_MISMATCH:
7235 7235 case SCF_ERROR_NOT_BOUND:
7236 7236 case SCF_ERROR_NOT_SET:
7237 7237 default:
7238 7238 bad_error("scf_scope_add_service", scf_error());
7239 7239 }
7240 7240 }
7241 7241
7242 7242 s->sc_import_state = IMPORT_PROP_BEGUN;
7243 7243
7244 7244 /* import service properties */
7245 7245 cbdata.sc_handle = lcbdata->sc_handle;
7246 7246 cbdata.sc_parent = imp_svc;
7247 7247 cbdata.sc_service = 1;
7248 7248 cbdata.sc_flags = lcbdata->sc_flags;
7249 7249 cbdata.sc_source_fmri = s->sc_fmri;
7250 7250 cbdata.sc_target_fmri = s->sc_fmri;
7251 7251
7252 7252 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7253 7253 &cbdata, UU_DEFAULT) != 0) {
7254 7254 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7255 7255 bad_error("uu_list_walk", uu_error());
7256 7256
7257 7257 lcbdata->sc_err = cbdata.sc_err;
7258 7258 switch (cbdata.sc_err) {
7259 7259 case ECONNABORTED:
7260 7260 goto connaborted;
7261 7261
7262 7262 case ECANCELED:
7263 7263 warn(s_deleted, s->sc_fmri);
7264 7264 lcbdata->sc_err = EBUSY;
7265 7265 return (UU_WALK_ERROR);
7266 7266
7267 7267 case EEXIST:
7268 7268 warn(gettext("%s changed unexpectedly "
7269 7269 "(property group added).\n"), s->sc_fmri);
7270 7270 lcbdata->sc_err = EBUSY;
7271 7271 return (UU_WALK_ERROR);
7272 7272
7273 7273 case EINVAL:
7274 7274 /* caught above */
7275 7275 bad_error("entity_pgroup_import",
7276 7276 cbdata.sc_err);
7277 7277 }
7278 7278
7279 7279 r = UU_WALK_ERROR;
7280 7280 goto deltemp;
7281 7281 }
7282 7282
7283 7283 cbdata.sc_trans = NULL;
7284 7284 cbdata.sc_flags = 0;
7285 7285 if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7286 7286 &cbdata, UU_DEFAULT) != 0) {
7287 7287 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7288 7288 bad_error("uu_list_walk", uu_error());
7289 7289
7290 7290 lcbdata->sc_err = cbdata.sc_err;
7291 7291 if (cbdata.sc_err == ECONNABORTED)
7292 7292 goto connaborted;
7293 7293 r = UU_WALK_ERROR;
7294 7294 goto deltemp;
7295 7295 }
7296 7296
7297 7297 s->sc_import_state = IMPORT_PROP_DONE;
7298 7298
7299 7299 /*
7300 7300 * This is a new service, so we can't take previous snapshots
7301 7301 * or upgrade service properties.
7302 7302 */
7303 7303 fresh = 1;
7304 7304 goto instances;
7305 7305 }
7306 7306
7307 7307 /* Clear sc_seen for the instances. */
7308 7308 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7309 7309 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7310 7310 bad_error("uu_list_walk", uu_error());
7311 7311
7312 7312 /*
7313 7313 * Take previous snapshots for all instances. Even for ones not
7314 7314 * mentioned in the bundle, since we might change their service
7315 7315 * properties.
7316 7316 */
7317 7317 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7318 7318 switch (scf_error()) {
7319 7319 case SCF_ERROR_CONNECTION_BROKEN:
7320 7320 goto connaborted;
7321 7321
7322 7322 case SCF_ERROR_DELETED:
7323 7323 warn(s_deleted, s->sc_fmri);
7324 7324 lcbdata->sc_err = EBUSY;
7325 7325 r = UU_WALK_ERROR;
7326 7326 goto deltemp;
7327 7327
7328 7328 case SCF_ERROR_HANDLE_MISMATCH:
7329 7329 case SCF_ERROR_NOT_BOUND:
7330 7330 case SCF_ERROR_NOT_SET:
7331 7331 default:
7332 7332 bad_error("scf_iter_service_instances", scf_error());
7333 7333 }
7334 7334 }
7335 7335
7336 7336 for (;;) {
7337 7337 r = scf_iter_next_instance(imp_iter, imp_inst);
7338 7338 if (r == 0)
7339 7339 break;
7340 7340 if (r != 1) {
7341 7341 switch (scf_error()) {
7342 7342 case SCF_ERROR_DELETED:
7343 7343 warn(s_deleted, s->sc_fmri);
7344 7344 lcbdata->sc_err = EBUSY;
7345 7345 r = UU_WALK_ERROR;
7346 7346 goto deltemp;
7347 7347
7348 7348 case SCF_ERROR_CONNECTION_BROKEN:
7349 7349 goto connaborted;
7350 7350
7351 7351 case SCF_ERROR_NOT_BOUND:
7352 7352 case SCF_ERROR_HANDLE_MISMATCH:
7353 7353 case SCF_ERROR_INVALID_ARGUMENT:
7354 7354 case SCF_ERROR_NOT_SET:
7355 7355 default:
7356 7356 bad_error("scf_iter_next_instance",
7357 7357 scf_error());
7358 7358 }
7359 7359 }
7360 7360
7361 7361 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7362 7362 switch (scf_error()) {
7363 7363 case SCF_ERROR_DELETED:
7364 7364 continue;
7365 7365
7366 7366 case SCF_ERROR_CONNECTION_BROKEN:
7367 7367 goto connaborted;
7368 7368
7369 7369 case SCF_ERROR_NOT_SET:
7370 7370 case SCF_ERROR_NOT_BOUND:
7371 7371 default:
7372 7372 bad_error("scf_instance_get_name", scf_error());
7373 7373 }
7374 7374 }
7375 7375
7376 7376 if (g_verbose)
7377 7377 warn(gettext(
7378 7378 "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7379 7379 snap_previous, s->sc_name, imp_str);
7380 7380
7381 7381 r = take_snap(imp_inst, snap_previous, imp_snap);
7382 7382 switch (r) {
7383 7383 case 0:
7384 7384 break;
7385 7385
7386 7386 case ECANCELED:
7387 7387 continue;
7388 7388
7389 7389 case ECONNABORTED:
7390 7390 goto connaborted;
7391 7391
7392 7392 case EPERM:
7393 7393 warn(gettext("Could not take \"%s\" snapshot of "
7394 7394 "svc:/%s:%s (permission denied).\n"),
7395 7395 snap_previous, s->sc_name, imp_str);
7396 7396 lcbdata->sc_err = r;
7397 7397 return (UU_WALK_ERROR);
7398 7398
7399 7399 case ENOSPC:
7400 7400 case -1:
7401 7401 lcbdata->sc_err = r;
7402 7402 r = UU_WALK_ERROR;
7403 7403 goto deltemp;
7404 7404
7405 7405 default:
7406 7406 bad_error("take_snap", r);
7407 7407 }
7408 7408
7409 7409 linst.sc_name = imp_str;
7410 7410 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7411 7411 &linst, NULL, NULL);
7412 7412 if (inst != NULL) {
7413 7413 inst->sc_import_state = IMPORT_PREVIOUS;
7414 7414 inst->sc_seen = 1;
7415 7415 }
7416 7416 }
7417 7417
7418 7418 /*
7419 7419 * Create the new instances and take previous snapshots of
7420 7420 * them. This is not necessary, but it maximizes data preservation.
7421 7421 */
7422 7422 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7423 7423 inst != NULL;
7424 7424 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7425 7425 inst)) {
7426 7426 if (inst->sc_seen)
7427 7427 continue;
7428 7428
7429 7429 if (scf_service_add_instance(imp_svc, inst->sc_name,
7430 7430 imp_inst) != 0) {
7431 7431 switch (scf_error()) {
7432 7432 case SCF_ERROR_CONNECTION_BROKEN:
7433 7433 goto connaborted;
7434 7434
7435 7435 case SCF_ERROR_BACKEND_READONLY:
7436 7436 case SCF_ERROR_BACKEND_ACCESS:
7437 7437 case SCF_ERROR_NO_RESOURCES:
7438 7438 r = stash_scferror(lcbdata);
7439 7439 goto deltemp;
7440 7440
7441 7441 case SCF_ERROR_EXISTS:
7442 7442 warn(gettext("%s changed unexpectedly "
7443 7443 "(instance \"%s\" added).\n"), s->sc_fmri,
7444 7444 inst->sc_name);
7445 7445 lcbdata->sc_err = EBUSY;
7446 7446 r = UU_WALK_ERROR;
7447 7447 goto deltemp;
7448 7448
7449 7449 case SCF_ERROR_INVALID_ARGUMENT:
7450 7450 warn(gettext("Service \"%s\" has instance with "
7451 7451 "invalid name \"%s\".\n"), s->sc_name,
7452 7452 inst->sc_name);
7453 7453 r = stash_scferror(lcbdata);
7454 7454 goto deltemp;
7455 7455
7456 7456 case SCF_ERROR_PERMISSION_DENIED:
7457 7457 warn(gettext("Could not create instance \"%s\" "
7458 7458 "in %s (permission denied).\n"),
7459 7459 inst->sc_name, s->sc_fmri);
7460 7460 r = stash_scferror(lcbdata);
7461 7461 goto deltemp;
7462 7462
7463 7463 case SCF_ERROR_HANDLE_MISMATCH:
7464 7464 case SCF_ERROR_NOT_BOUND:
7465 7465 case SCF_ERROR_NOT_SET:
7466 7466 default:
7467 7467 bad_error("scf_service_add_instance",
7468 7468 scf_error());
7469 7469 }
7470 7470 }
7471 7471
7472 7472 if (g_verbose)
7473 7473 warn(gettext("Taking \"%s\" snapshot for "
7474 7474 "new service %s.\n"), snap_previous, inst->sc_fmri);
7475 7475 r = take_snap(imp_inst, snap_previous, imp_snap);
7476 7476 switch (r) {
7477 7477 case 0:
7478 7478 break;
7479 7479
7480 7480 case ECANCELED:
7481 7481 warn(i_deleted, s->sc_fmri, inst->sc_name);
7482 7482 lcbdata->sc_err = EBUSY;
7483 7483 r = UU_WALK_ERROR;
7484 7484 goto deltemp;
7485 7485
7486 7486 case ECONNABORTED:
7487 7487 goto connaborted;
7488 7488
7489 7489 case EPERM:
7490 7490 warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7491 7491 lcbdata->sc_err = r;
7492 7492 r = UU_WALK_ERROR;
7493 7493 goto deltemp;
7494 7494
7495 7495 case ENOSPC:
7496 7496 case -1:
7497 7497 r = UU_WALK_ERROR;
7498 7498 goto deltemp;
7499 7499
7500 7500 default:
7501 7501 bad_error("take_snap", r);
7502 7502 }
7503 7503 }
7504 7504
7505 7505 s->sc_import_state = IMPORT_PREVIOUS;
7506 7506
7507 7507 /*
7508 7508 * Upgrade service properties, if we can find a last-import snapshot.
7509 7509 * Any will do because we don't support different service properties
7510 7510 * in different manifests, so all snaplevels of the service in all of
7511 7511 * the last-import snapshots of the instances should be the same.
7512 7512 */
7513 7513 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7514 7514 switch (scf_error()) {
7515 7515 case SCF_ERROR_CONNECTION_BROKEN:
7516 7516 goto connaborted;
7517 7517
7518 7518 case SCF_ERROR_DELETED:
7519 7519 warn(s_deleted, s->sc_fmri);
7520 7520 lcbdata->sc_err = EBUSY;
7521 7521 r = UU_WALK_ERROR;
7522 7522 goto deltemp;
7523 7523
7524 7524 case SCF_ERROR_HANDLE_MISMATCH:
7525 7525 case SCF_ERROR_NOT_BOUND:
7526 7526 case SCF_ERROR_NOT_SET:
7527 7527 default:
7528 7528 bad_error("scf_iter_service_instances", scf_error());
7529 7529 }
7530 7530 }
7531 7531
7532 7532 for (;;) {
7533 7533 r = scf_iter_next_instance(imp_iter, imp_inst);
7534 7534 if (r == -1) {
7535 7535 switch (scf_error()) {
7536 7536 case SCF_ERROR_DELETED:
7537 7537 warn(s_deleted, s->sc_fmri);
7538 7538 lcbdata->sc_err = EBUSY;
7539 7539 r = UU_WALK_ERROR;
7540 7540 goto deltemp;
7541 7541
7542 7542 case SCF_ERROR_CONNECTION_BROKEN:
7543 7543 goto connaborted;
7544 7544
7545 7545 case SCF_ERROR_NOT_BOUND:
7546 7546 case SCF_ERROR_HANDLE_MISMATCH:
7547 7547 case SCF_ERROR_INVALID_ARGUMENT:
7548 7548 case SCF_ERROR_NOT_SET:
7549 7549 default:
7550 7550 bad_error("scf_iter_next_instance",
7551 7551 scf_error());
7552 7552 }
7553 7553 }
7554 7554
7555 7555 if (r == 0) {
7556 7556 /*
7557 7557 * Didn't find any last-import snapshots. Override-
7558 7558 * import the properties. Unless one of the instances
7559 7559 * has a general/enabled property, in which case we're
7560 7560 * probably running a last-import-capable svccfg for
7561 7561 * the first time, and we should only take the
7562 7562 * last-import snapshot.
7563 7563 */
7564 7564 if (have_ge) {
7565 7565 pgroup_t *mfpg;
7566 7566 scf_callback_t mfcbdata;
7567 7567
7568 7568 li_only = 1;
7569 7569 no_refresh = 1;
7570 7570 /*
7571 7571 * Need to go ahead and import the manifestfiles
7572 7572 * pg if it exists. If the last-import snapshot
7573 7573 * upgrade code is ever removed this code can
7574 7574 * be removed as well.
7575 7575 */
7576 7576 mfpg = internal_pgroup_find(s,
7577 7577 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7578 7578
7579 7579 if (mfpg) {
7580 7580 mfcbdata.sc_handle = g_hndl;
7581 7581 mfcbdata.sc_parent = imp_svc;
7582 7582 mfcbdata.sc_service = 1;
7583 7583 mfcbdata.sc_flags = SCI_FORCE;
7584 7584 mfcbdata.sc_source_fmri = s->sc_fmri;
7585 7585 mfcbdata.sc_target_fmri = s->sc_fmri;
7586 7586 if (entity_pgroup_import(mfpg,
7587 7587 &mfcbdata) != UU_WALK_NEXT) {
7588 7588 warn(s_mfile_upd, s->sc_fmri);
7589 7589 r = UU_WALK_ERROR;
7590 7590 goto deltemp;
7591 7591 }
7592 7592 }
7593 7593 break;
7594 7594 }
7595 7595
7596 7596 s->sc_import_state = IMPORT_PROP_BEGUN;
7597 7597
7598 7598 cbdata.sc_handle = g_hndl;
7599 7599 cbdata.sc_parent = imp_svc;
7600 7600 cbdata.sc_service = 1;
7601 7601 cbdata.sc_flags = SCI_FORCE;
7602 7602 cbdata.sc_source_fmri = s->sc_fmri;
7603 7603 cbdata.sc_target_fmri = s->sc_fmri;
7604 7604 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7605 7605 &cbdata, UU_DEFAULT) != 0) {
7606 7606 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7607 7607 bad_error("uu_list_walk", uu_error());
7608 7608 lcbdata->sc_err = cbdata.sc_err;
7609 7609 switch (cbdata.sc_err) {
7610 7610 case ECONNABORTED:
7611 7611 goto connaborted;
7612 7612
7613 7613 case ECANCELED:
7614 7614 warn(s_deleted, s->sc_fmri);
7615 7615 lcbdata->sc_err = EBUSY;
7616 7616 break;
7617 7617
7618 7618 case EINVAL: /* caught above */
7619 7619 case EEXIST:
7620 7620 bad_error("entity_pgroup_import",
7621 7621 cbdata.sc_err);
7622 7622 }
7623 7623
7624 7624 r = UU_WALK_ERROR;
7625 7625 goto deltemp;
7626 7626 }
7627 7627
7628 7628 cbdata.sc_trans = NULL;
7629 7629 cbdata.sc_flags = 0;
7630 7630 if (uu_list_walk(s->sc_dependents,
7631 7631 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7632 7632 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7633 7633 bad_error("uu_list_walk", uu_error());
7634 7634 lcbdata->sc_err = cbdata.sc_err;
7635 7635 if (cbdata.sc_err == ECONNABORTED)
7636 7636 goto connaborted;
7637 7637 r = UU_WALK_ERROR;
7638 7638 goto deltemp;
7639 7639 }
7640 7640 break;
7641 7641 }
7642 7642
7643 7643 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7644 7644 imp_snap) != 0) {
7645 7645 switch (scf_error()) {
7646 7646 case SCF_ERROR_DELETED:
7647 7647 continue;
7648 7648
7649 7649 case SCF_ERROR_NOT_FOUND:
7650 7650 break;
7651 7651
7652 7652 case SCF_ERROR_CONNECTION_BROKEN:
7653 7653 goto connaborted;
7654 7654
7655 7655 case SCF_ERROR_HANDLE_MISMATCH:
7656 7656 case SCF_ERROR_NOT_BOUND:
7657 7657 case SCF_ERROR_INVALID_ARGUMENT:
7658 7658 case SCF_ERROR_NOT_SET:
7659 7659 default:
7660 7660 bad_error("scf_instance_get_snapshot",
7661 7661 scf_error());
7662 7662 }
7663 7663
7664 7664 if (have_ge)
7665 7665 continue;
7666 7666
7667 7667 /*
7668 7668 * Check for a general/enabled property. This is how
7669 7669 * we tell whether to import if there turn out to be
7670 7670 * no last-import snapshots.
7671 7671 */
7672 7672 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7673 7673 imp_pg) == 0) {
7674 7674 if (scf_pg_get_property(imp_pg,
7675 7675 SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7676 7676 have_ge = 1;
7677 7677 } else {
7678 7678 switch (scf_error()) {
7679 7679 case SCF_ERROR_DELETED:
7680 7680 case SCF_ERROR_NOT_FOUND:
7681 7681 continue;
7682 7682
7683 7683 case SCF_ERROR_INVALID_ARGUMENT:
7684 7684 case SCF_ERROR_HANDLE_MISMATCH:
7685 7685 case SCF_ERROR_CONNECTION_BROKEN:
7686 7686 case SCF_ERROR_NOT_BOUND:
7687 7687 case SCF_ERROR_NOT_SET:
7688 7688 default:
7689 7689 bad_error("scf_pg_get_property",
7690 7690 scf_error());
7691 7691 }
7692 7692 }
7693 7693 } else {
7694 7694 switch (scf_error()) {
7695 7695 case SCF_ERROR_DELETED:
7696 7696 case SCF_ERROR_NOT_FOUND:
7697 7697 continue;
7698 7698
7699 7699 case SCF_ERROR_CONNECTION_BROKEN:
7700 7700 goto connaborted;
7701 7701
7702 7702 case SCF_ERROR_NOT_BOUND:
7703 7703 case SCF_ERROR_NOT_SET:
7704 7704 case SCF_ERROR_INVALID_ARGUMENT:
7705 7705 case SCF_ERROR_HANDLE_MISMATCH:
7706 7706 default:
7707 7707 bad_error("scf_instance_get_pg",
7708 7708 scf_error());
7709 7709 }
7710 7710 }
7711 7711 continue;
7712 7712 }
7713 7713
7714 7714 /* find service snaplevel */
7715 7715 r = get_snaplevel(imp_snap, 1, imp_snpl);
7716 7716 switch (r) {
7717 7717 case 0:
7718 7718 break;
7719 7719
7720 7720 case ECONNABORTED:
7721 7721 goto connaborted;
7722 7722
7723 7723 case ECANCELED:
7724 7724 continue;
7725 7725
7726 7726 case ENOENT:
7727 7727 if (scf_instance_get_name(imp_inst, imp_str,
7728 7728 imp_str_sz) < 0)
7729 7729 (void) strcpy(imp_str, "?");
7730 7730 warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7731 7731 lcbdata->sc_err = EBADF;
7732 7732 r = UU_WALK_ERROR;
7733 7733 goto deltemp;
7734 7734
7735 7735 default:
7736 7736 bad_error("get_snaplevel", r);
7737 7737 }
7738 7738
7739 7739 if (scf_instance_get_snapshot(imp_inst, snap_running,
7740 7740 imp_rsnap) != 0) {
7741 7741 switch (scf_error()) {
7742 7742 case SCF_ERROR_DELETED:
7743 7743 continue;
7744 7744
7745 7745 case SCF_ERROR_NOT_FOUND:
7746 7746 break;
7747 7747
7748 7748 case SCF_ERROR_CONNECTION_BROKEN:
7749 7749 goto connaborted;
7750 7750
7751 7751 case SCF_ERROR_INVALID_ARGUMENT:
7752 7752 case SCF_ERROR_HANDLE_MISMATCH:
7753 7753 case SCF_ERROR_NOT_BOUND:
7754 7754 case SCF_ERROR_NOT_SET:
7755 7755 default:
7756 7756 bad_error("scf_instance_get_snapshot",
7757 7757 scf_error());
7758 7758 }
7759 7759 running = NULL;
7760 7760 } else {
7761 7761 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7762 7762 switch (r) {
7763 7763 case 0:
7764 7764 running = imp_rsnpl;
7765 7765 break;
7766 7766
7767 7767 case ECONNABORTED:
7768 7768 goto connaborted;
7769 7769
7770 7770 case ECANCELED:
7771 7771 continue;
7772 7772
7773 7773 case ENOENT:
7774 7774 if (scf_instance_get_name(imp_inst, imp_str,
7775 7775 imp_str_sz) < 0)
7776 7776 (void) strcpy(imp_str, "?");
7777 7777 warn(badsnap, snap_running, s->sc_name,
7778 7778 imp_str);
7779 7779 lcbdata->sc_err = EBADF;
7780 7780 r = UU_WALK_ERROR;
7781 7781 goto deltemp;
7782 7782
7783 7783 default:
7784 7784 bad_error("get_snaplevel", r);
7785 7785 }
7786 7786 }
7787 7787
7788 7788 if (g_verbose) {
7789 7789 if (scf_instance_get_name(imp_inst, imp_str,
7790 7790 imp_str_sz) < 0)
7791 7791 (void) strcpy(imp_str, "?");
7792 7792 warn(gettext("Upgrading properties of %s according to "
7793 7793 "instance \"%s\".\n"), s->sc_fmri, imp_str);
7794 7794 }
7795 7795
7796 7796 /* upgrade service properties */
7797 7797 r = upgrade_props(imp_svc, running, imp_snpl, s);
7798 7798 if (r == 0)
7799 7799 break;
7800 7800
7801 7801 switch (r) {
7802 7802 case ECONNABORTED:
7803 7803 goto connaborted;
7804 7804
7805 7805 case ECANCELED:
7806 7806 warn(s_deleted, s->sc_fmri);
7807 7807 lcbdata->sc_err = EBUSY;
7808 7808 break;
7809 7809
7810 7810 case ENODEV:
7811 7811 if (scf_instance_get_name(imp_inst, imp_str,
7812 7812 imp_str_sz) < 0)
7813 7813 (void) strcpy(imp_str, "?");
7814 7814 warn(i_deleted, s->sc_fmri, imp_str);
7815 7815 lcbdata->sc_err = EBUSY;
7816 7816 break;
7817 7817
7818 7818 default:
7819 7819 lcbdata->sc_err = r;
7820 7820 }
7821 7821
7822 7822 r = UU_WALK_ERROR;
7823 7823 goto deltemp;
7824 7824 }
7825 7825
7826 7826 s->sc_import_state = IMPORT_PROP_DONE;
7827 7827
7828 7828 instances:
7829 7829 /* import instances */
7830 7830 cbdata.sc_handle = lcbdata->sc_handle;
7831 7831 cbdata.sc_parent = imp_svc;
7832 7832 cbdata.sc_service = 1;
7833 7833 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7834 7834 cbdata.sc_general = NULL;
7835 7835
7836 7836 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7837 7837 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7838 7838 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7839 7839 bad_error("uu_list_walk", uu_error());
7840 7840
7841 7841 lcbdata->sc_err = cbdata.sc_err;
7842 7842 if (cbdata.sc_err == ECONNABORTED)
7843 7843 goto connaborted;
7844 7844 r = UU_WALK_ERROR;
7845 7845 goto deltemp;
7846 7846 }
7847 7847
7848 7848 s->sc_import_state = IMPORT_COMPLETE;
7849 7849 r = UU_WALK_NEXT;
7850 7850
7851 7851 deltemp:
7852 7852 /* delete temporary service */
7853 7853 if (scf_service_delete(imp_tsvc) != 0) {
7854 7854 switch (scf_error()) {
7855 7855 case SCF_ERROR_DELETED:
7856 7856 break;
7857 7857
7858 7858 case SCF_ERROR_CONNECTION_BROKEN:
7859 7859 goto connaborted;
7860 7860
7861 7861 case SCF_ERROR_EXISTS:
7862 7862 warn(gettext(
7863 7863 "Could not delete svc:/%s (instances exist).\n"),
7864 7864 imp_tsname);
7865 7865 break;
7866 7866
7867 7867 case SCF_ERROR_NOT_SET:
7868 7868 case SCF_ERROR_NOT_BOUND:
7869 7869 default:
7870 7870 bad_error("scf_service_delete", scf_error());
7871 7871 }
7872 7872 }
7873 7873
7874 7874 return (r);
7875 7875
7876 7876 connaborted:
7877 7877 warn(gettext("Could not delete svc:/%s "
7878 7878 "(repository connection broken).\n"), imp_tsname);
7879 7879 lcbdata->sc_err = ECONNABORTED;
7880 7880 return (UU_WALK_ERROR);
7881 7881 }
7882 7882
7883 7883 static const char *
7884 7884 import_progress(int st)
7885 7885 {
7886 7886 switch (st) {
7887 7887 case 0:
7888 7888 return (gettext("not reached."));
7889 7889
7890 7890 case IMPORT_PREVIOUS:
7891 7891 return (gettext("previous snapshot taken."));
7892 7892
7893 7893 case IMPORT_PROP_BEGUN:
7894 7894 return (gettext("some properties imported."));
7895 7895
7896 7896 case IMPORT_PROP_DONE:
7897 7897 return (gettext("properties imported."));
7898 7898
7899 7899 case IMPORT_COMPLETE:
7900 7900 return (gettext("imported."));
7901 7901
7902 7902 case IMPORT_REFRESHED:
7903 7903 return (gettext("refresh requested."));
7904 7904
7905 7905 default:
7906 7906 #ifndef NDEBUG
7907 7907 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7908 7908 __FILE__, __LINE__, st);
7909 7909 #endif
7910 7910 abort();
7911 7911 /* NOTREACHED */
7912 7912 }
7913 7913 }
7914 7914
7915 7915 /*
7916 7916 * Returns
7917 7917 * 0 - success
7918 7918 * - fmri wasn't found (error printed)
7919 7919 * - entity was deleted (error printed)
7920 7920 * - backend denied access (error printed)
7921 7921 * ENOMEM - out of memory (error printed)
7922 7922 * ECONNABORTED - repository connection broken (error printed)
7923 7923 * EPERM - permission denied (error printed)
7924 7924 * -1 - unknown libscf error (error printed)
7925 7925 */
7926 7926 static int
7927 7927 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7928 7928 {
7929 7929 scf_error_t serr;
7930 7930 void *ent;
7931 7931 int issvc;
7932 7932 int r;
7933 7933
7934 7934 const char *deleted = gettext("Could not refresh %s (deleted).\n");
7935 7935 const char *dpt_deleted = gettext("Could not refresh %s "
7936 7936 "(dependent \"%s\" of %s) (deleted).\n");
7937 7937
7938 7938 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7939 7939 switch (serr) {
7940 7940 case SCF_ERROR_NONE:
7941 7941 break;
7942 7942
7943 7943 case SCF_ERROR_NO_MEMORY:
7944 7944 if (name == NULL)
7945 7945 warn(gettext("Could not refresh %s (out of memory).\n"),
7946 7946 fmri);
7947 7947 else
7948 7948 warn(gettext("Could not refresh %s "
7949 7949 "(dependent \"%s\" of %s) (out of memory).\n"),
7950 7950 fmri, name, d_fmri);
7951 7951 return (ENOMEM);
7952 7952
7953 7953 case SCF_ERROR_NOT_FOUND:
7954 7954 if (name == NULL)
7955 7955 warn(deleted, fmri);
7956 7956 else
7957 7957 warn(dpt_deleted, fmri, name, d_fmri);
7958 7958 return (0);
7959 7959
7960 7960 case SCF_ERROR_INVALID_ARGUMENT:
7961 7961 case SCF_ERROR_CONSTRAINT_VIOLATED:
7962 7962 default:
7963 7963 bad_error("fmri_to_entity", serr);
7964 7964 }
7965 7965
7966 7966 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7967 7967 switch (r) {
7968 7968 case 0:
7969 7969 break;
7970 7970
7971 7971 case ECONNABORTED:
7972 7972 if (name != NULL)
7973 7973 warn(gettext("Could not refresh %s "
7974 7974 "(dependent \"%s\" of %s) "
7975 7975 "(repository connection broken).\n"), fmri, name,
7976 7976 d_fmri);
7977 7977 return (r);
7978 7978
7979 7979 case ECANCELED:
7980 7980 if (name == NULL)
7981 7981 warn(deleted, fmri);
7982 7982 else
7983 7983 warn(dpt_deleted, fmri, name, d_fmri);
7984 7984 return (0);
7985 7985
7986 7986 case EACCES:
7987 7987 if (!g_verbose)
7988 7988 return (0);
7989 7989 if (name == NULL)
7990 7990 warn(gettext("Could not refresh %s "
7991 7991 "(backend access denied).\n"), fmri);
7992 7992 else
7993 7993 warn(gettext("Could not refresh %s "
7994 7994 "(dependent \"%s\" of %s) "
7995 7995 "(backend access denied).\n"), fmri, name, d_fmri);
7996 7996 return (0);
7997 7997
7998 7998 case EPERM:
7999 7999 if (name == NULL)
8000 8000 warn(gettext("Could not refresh %s "
8001 8001 "(permission denied).\n"), fmri);
8002 8002 else
8003 8003 warn(gettext("Could not refresh %s "
8004 8004 "(dependent \"%s\" of %s) "
8005 8005 "(permission denied).\n"), fmri, name, d_fmri);
8006 8006 return (r);
8007 8007
8008 8008 case ENOSPC:
8009 8009 if (name == NULL)
8010 8010 warn(gettext("Could not refresh %s "
8011 8011 "(repository server out of resources).\n"),
8012 8012 fmri);
8013 8013 else
8014 8014 warn(gettext("Could not refresh %s "
8015 8015 "(dependent \"%s\" of %s) "
8016 8016 "(repository server out of resources).\n"),
8017 8017 fmri, name, d_fmri);
8018 8018 return (r);
8019 8019
8020 8020 case -1:
8021 8021 scfwarn();
8022 8022 return (r);
8023 8023
8024 8024 default:
8025 8025 bad_error("refresh_entity", r);
8026 8026 }
8027 8027
8028 8028 if (issvc)
8029 8029 scf_service_destroy(ent);
8030 8030 else
8031 8031 scf_instance_destroy(ent);
8032 8032
8033 8033 return (0);
8034 8034 }
8035 8035
8036 8036 static int
8037 8037 alloc_imp_globals()
8038 8038 {
8039 8039 int r;
8040 8040
8041 8041 const char * const emsg_nomem = gettext("Out of memory.\n");
8042 8042 const char * const emsg_nores =
8043 8043 gettext("svc.configd is out of resources.\n");
8044 8044
8045 8045 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8046 8046 max_scf_name_len : max_scf_fmri_len) + 1;
8047 8047
8048 8048 if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8049 8049 (imp_svc = scf_service_create(g_hndl)) == NULL ||
8050 8050 (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8051 8051 (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8052 8052 (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8053 8053 (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8054 8054 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8055 8055 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8056 8056 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8057 8057 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8058 8058 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8059 8059 (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8060 8060 (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8061 8061 (imp_prop = scf_property_create(g_hndl)) == NULL ||
8062 8062 (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8063 8063 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8064 8064 (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8065 8065 (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8066 8066 (imp_str = malloc(imp_str_sz)) == NULL ||
8067 8067 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8068 8068 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8069 8069 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8070 8070 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8071 8071 (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8072 8072 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8073 8073 (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8074 8074 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8075 8075 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8076 8076 (ud_prop = scf_property_create(g_hndl)) == NULL ||
8077 8077 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8078 8078 (ud_val = scf_value_create(g_hndl)) == NULL ||
8079 8079 (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8080 8080 (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8081 8081 (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8082 8082 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8083 8083 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8084 8084 (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8085 8085 if (scf_error() == SCF_ERROR_NO_RESOURCES)
8086 8086 warn(emsg_nores);
8087 8087 else
8088 8088 warn(emsg_nomem);
8089 8089
8090 8090 return (-1);
8091 8091 }
8092 8092
8093 8093 r = load_init();
8094 8094 switch (r) {
8095 8095 case 0:
8096 8096 break;
8097 8097
8098 8098 case ENOMEM:
8099 8099 warn(emsg_nomem);
8100 8100 return (-1);
8101 8101
8102 8102 default:
8103 8103 bad_error("load_init", r);
8104 8104 }
8105 8105
8106 8106 return (0);
8107 8107 }
8108 8108
8109 8109 static void
8110 8110 free_imp_globals()
8111 8111 {
8112 8112 pgroup_t *old_dpt;
8113 8113 void *cookie;
8114 8114
8115 8115 load_fini();
8116 8116
8117 8117 free(ud_ctarg);
8118 8118 free(ud_oldtarg);
8119 8119 free(ud_name);
8120 8120 ud_ctarg = ud_oldtarg = ud_name = NULL;
8121 8121
8122 8122 scf_transaction_destroy(ud_tx);
8123 8123 ud_tx = NULL;
8124 8124 scf_iter_destroy(ud_iter);
8125 8125 scf_iter_destroy(ud_iter2);
8126 8126 ud_iter = ud_iter2 = NULL;
8127 8127 scf_value_destroy(ud_val);
8128 8128 ud_val = NULL;
8129 8129 scf_property_destroy(ud_prop);
8130 8130 scf_property_destroy(ud_dpt_prop);
8131 8131 ud_prop = ud_dpt_prop = NULL;
8132 8132 scf_pg_destroy(ud_pg);
8133 8133 scf_pg_destroy(ud_cur_depts_pg);
8134 8134 scf_pg_destroy(ud_run_dpts_pg);
8135 8135 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8136 8136 scf_snaplevel_destroy(ud_snpl);
8137 8137 ud_snpl = NULL;
8138 8138 scf_instance_destroy(ud_inst);
8139 8139 ud_inst = NULL;
8140 8140
8141 8141 free(imp_str);
8142 8142 free(imp_tsname);
8143 8143 free(imp_fe1);
8144 8144 free(imp_fe2);
8145 8145 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8146 8146
8147 8147 cookie = NULL;
8148 8148 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8149 8149 NULL) {
8150 8150 free((char *)old_dpt->sc_pgroup_name);
8151 8151 free((char *)old_dpt->sc_pgroup_fmri);
8152 8152 internal_pgroup_free(old_dpt);
8153 8153 }
8154 8154 uu_list_destroy(imp_deleted_dpts);
8155 8155
8156 8156 scf_transaction_destroy(imp_tx);
8157 8157 imp_tx = NULL;
8158 8158 scf_iter_destroy(imp_iter);
8159 8159 scf_iter_destroy(imp_rpg_iter);
8160 8160 scf_iter_destroy(imp_up_iter);
8161 8161 imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8162 8162 scf_property_destroy(imp_prop);
8163 8163 imp_prop = NULL;
8164 8164 scf_pg_destroy(imp_pg);
8165 8165 scf_pg_destroy(imp_pg2);
8166 8166 imp_pg = imp_pg2 = NULL;
8167 8167 scf_snaplevel_destroy(imp_snpl);
8168 8168 scf_snaplevel_destroy(imp_rsnpl);
8169 8169 imp_snpl = imp_rsnpl = NULL;
8170 8170 scf_snapshot_destroy(imp_snap);
8171 8171 scf_snapshot_destroy(imp_lisnap);
8172 8172 scf_snapshot_destroy(imp_tlisnap);
8173 8173 scf_snapshot_destroy(imp_rsnap);
8174 8174 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8175 8175 scf_instance_destroy(imp_inst);
8176 8176 scf_instance_destroy(imp_tinst);
8177 8177 imp_inst = imp_tinst = NULL;
8178 8178 scf_service_destroy(imp_svc);
8179 8179 scf_service_destroy(imp_tsvc);
8180 8180 imp_svc = imp_tsvc = NULL;
8181 8181 scf_scope_destroy(imp_scope);
8182 8182 imp_scope = NULL;
8183 8183
8184 8184 load_fini();
8185 8185 }
8186 8186
8187 8187 int
8188 8188 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8189 8189 {
8190 8190 scf_callback_t cbdata;
8191 8191 int result = 0;
8192 8192 entity_t *svc, *inst;
8193 8193 uu_list_t *insts;
8194 8194 int r;
8195 8195 pgroup_t *old_dpt;
8196 8196 int annotation_set = 0;
8197 8197
8198 8198 const char * const emsg_nomem = gettext("Out of memory.\n");
8199 8199 const char * const emsg_nores =
8200 8200 gettext("svc.configd is out of resources.\n");
8201 8201
8202 8202 lscf_prep_hndl();
8203 8203
8204 8204 if (alloc_imp_globals())
8205 8205 goto out;
8206 8206
8207 8207 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8208 8208 switch (scf_error()) {
8209 8209 case SCF_ERROR_CONNECTION_BROKEN:
8210 8210 warn(gettext("Repository connection broken.\n"));
8211 8211 repository_teardown();
8212 8212 result = -1;
8213 8213 goto out;
8214 8214
8215 8215 case SCF_ERROR_NOT_FOUND:
8216 8216 case SCF_ERROR_INVALID_ARGUMENT:
8217 8217 case SCF_ERROR_NOT_BOUND:
8218 8218 case SCF_ERROR_HANDLE_MISMATCH:
8219 8219 default:
8220 8220 bad_error("scf_handle_get_scope", scf_error());
8221 8221 }
8222 8222 }
8223 8223
8224 8224 /* Set up the auditing annotation. */
8225 8225 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8226 8226 annotation_set = 1;
8227 8227 } else {
8228 8228 switch (scf_error()) {
8229 8229 case SCF_ERROR_CONNECTION_BROKEN:
8230 8230 warn(gettext("Repository connection broken.\n"));
8231 8231 repository_teardown();
8232 8232 result = -1;
8233 8233 goto out;
8234 8234
8235 8235 case SCF_ERROR_INVALID_ARGUMENT:
8236 8236 case SCF_ERROR_NOT_BOUND:
8237 8237 case SCF_ERROR_NO_RESOURCES:
8238 8238 case SCF_ERROR_INTERNAL:
8239 8239 bad_error("_scf_set_annotation", scf_error());
8240 8240 /* NOTREACHED */
8241 8241
8242 8242 default:
8243 8243 /*
8244 8244 * Do not terminate import because of inability to
8245 8245 * generate annotation audit event.
8246 8246 */
8247 8247 warn(gettext("_scf_set_annotation() unexpectedly "
8248 8248 "failed with return code of %d\n"), scf_error());
8249 8249 break;
8250 8250 }
8251 8251 }
8252 8252
8253 8253 /*
8254 8254 * Clear the sc_import_state's of all services & instances so we can
8255 8255 * report how far we got if we fail.
8256 8256 */
8257 8257 for (svc = uu_list_first(bndl->sc_bundle_services);
8258 8258 svc != NULL;
8259 8259 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8260 8260 svc->sc_import_state = 0;
8261 8261
8262 8262 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8263 8263 clear_int, (void *)offsetof(entity_t, sc_import_state),
8264 8264 UU_DEFAULT) != 0)
8265 8265 bad_error("uu_list_walk", uu_error());
8266 8266 }
8267 8267
8268 8268 cbdata.sc_handle = g_hndl;
8269 8269 cbdata.sc_parent = imp_scope;
8270 8270 cbdata.sc_flags = flags;
8271 8271 cbdata.sc_general = NULL;
8272 8272
8273 8273 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8274 8274 &cbdata, UU_DEFAULT) == 0) {
8275 8275 char *eptr;
8276 8276 /* Success. Refresh everything. */
8277 8277
8278 8278 if (flags & SCI_NOREFRESH || no_refresh) {
8279 8279 no_refresh = 0;
8280 8280 result = 0;
8281 8281 goto out;
8282 8282 }
8283 8283
8284 8284 for (svc = uu_list_first(bndl->sc_bundle_services);
8285 8285 svc != NULL;
8286 8286 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8287 8287 pgroup_t *dpt;
8288 8288
8289 8289 insts = svc->sc_u.sc_service.sc_service_instances;
8290 8290
8291 8291 for (inst = uu_list_first(insts);
8292 8292 inst != NULL;
8293 8293 inst = uu_list_next(insts, inst)) {
8294 8294 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8295 8295 switch (r) {
8296 8296 case 0:
8297 8297 break;
8298 8298
8299 8299 case ENOMEM:
8300 8300 case ECONNABORTED:
8301 8301 case EPERM:
8302 8302 case -1:
8303 8303 goto progress;
8304 8304
8305 8305 default:
8306 8306 bad_error("imp_refresh_fmri", r);
8307 8307 }
8308 8308
8309 8309 inst->sc_import_state = IMPORT_REFRESHED;
8310 8310
8311 8311 for (dpt = uu_list_first(inst->sc_dependents);
8312 8312 dpt != NULL;
8313 8313 dpt = uu_list_next(inst->sc_dependents,
8314 8314 dpt))
8315 8315 if (imp_refresh_fmri(
8316 8316 dpt->sc_pgroup_fmri,
8317 8317 dpt->sc_pgroup_name,
8318 8318 inst->sc_fmri) != 0)
8319 8319 goto progress;
8320 8320 }
8321 8321
8322 8322 for (dpt = uu_list_first(svc->sc_dependents);
8323 8323 dpt != NULL;
8324 8324 dpt = uu_list_next(svc->sc_dependents, dpt))
8325 8325 if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8326 8326 dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8327 8327 goto progress;
8328 8328 }
8329 8329
8330 8330 for (old_dpt = uu_list_first(imp_deleted_dpts);
8331 8331 old_dpt != NULL;
8332 8332 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8333 8333 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8334 8334 old_dpt->sc_pgroup_name,
8335 8335 old_dpt->sc_parent->sc_fmri) != 0)
8336 8336 goto progress;
8337 8337
8338 8338 result = 0;
8339 8339
8340 8340 /*
8341 8341 * This snippet of code assumes that we are running svccfg as we
8342 8342 * normally do -- witih svc.startd running. Of course, that is
8343 8343 * not actually the case all the time because we also use a
8344 8344 * varient of svc.configd and svccfg which are only meant to
8345 8345 * run during the build process. During this time we have no
8346 8346 * svc.startd, so this check would hang the build process.
8347 8347 *
8348 8348 * However, we've also given other consolidations, a bit of a
8349 8349 * means to tie themselves into a knot. They're not properly
8350 8350 * using the native build equivalents, but they've been getting
8351 8351 * away with it anyways. Therefore, if we've found that
8352 8352 * SVCCFG_REPOSITORY is set indicating that a separate configd
8353 8353 * should be spun up, then we have to assume it's not using a
8354 8354 * startd and we should not do this check.
8355 8355 */
8356 8356 #ifndef NATIVE_BUILD
8357 8357 /*
8358 8358 * Verify that the restarter group is preset
8359 8359 */
8360 8360 eptr = getenv("SVCCFG_REPOSITORY");
8361 8361 for (svc = uu_list_first(bndl->sc_bundle_services);
8362 8362 svc != NULL && eptr == NULL;
8363 8363 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8364 8364
8365 8365 insts = svc->sc_u.sc_service.sc_service_instances;
8366 8366
8367 8367 for (inst = uu_list_first(insts);
8368 8368 inst != NULL;
8369 8369 inst = uu_list_next(insts, inst)) {
8370 8370 if (lscf_instance_verify(imp_scope, svc,
8371 8371 inst) != 0)
8372 8372 goto progress;
8373 8373 }
8374 8374 }
8375 8375 #endif
8376 8376 goto out;
8377 8377
8378 8378 }
8379 8379
8380 8380 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8381 8381 bad_error("uu_list_walk", uu_error());
8382 8382
8383 8383 printerr:
8384 8384 /* If the error hasn't been printed yet, do so here. */
8385 8385 switch (cbdata.sc_err) {
8386 8386 case ECONNABORTED:
8387 8387 warn(gettext("Repository connection broken.\n"));
8388 8388 break;
8389 8389
8390 8390 case ENOMEM:
8391 8391 warn(emsg_nomem);
8392 8392 break;
8393 8393
8394 8394 case ENOSPC:
8395 8395 warn(emsg_nores);
8396 8396 break;
8397 8397
8398 8398 case EROFS:
8399 8399 warn(gettext("Repository is read-only.\n"));
8400 8400 break;
8401 8401
8402 8402 case EACCES:
8403 8403 warn(gettext("Repository backend denied access.\n"));
8404 8404 break;
8405 8405
8406 8406 case EPERM:
8407 8407 case EINVAL:
8408 8408 case EEXIST:
8409 8409 case EBUSY:
8410 8410 case EBADF:
8411 8411 case -1:
8412 8412 break;
8413 8413
8414 8414 default:
8415 8415 bad_error("lscf_service_import", cbdata.sc_err);
8416 8416 }
8417 8417
8418 8418 progress:
8419 8419 warn(gettext("Import of %s failed. Progress:\n"), filename);
8420 8420
8421 8421 for (svc = uu_list_first(bndl->sc_bundle_services);
8422 8422 svc != NULL;
8423 8423 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8424 8424 insts = svc->sc_u.sc_service.sc_service_instances;
8425 8425
8426 8426 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name,
8427 8427 import_progress(svc->sc_import_state));
8428 8428
8429 8429 for (inst = uu_list_first(insts);
8430 8430 inst != NULL;
8431 8431 inst = uu_list_next(insts, inst))
8432 8432 warn(gettext(" Instance \"%s\": %s\n"),
8433 8433 inst->sc_name,
8434 8434 import_progress(inst->sc_import_state));
8435 8435 }
8436 8436
8437 8437 if (cbdata.sc_err == ECONNABORTED)
8438 8438 repository_teardown();
8439 8439
8440 8440
8441 8441 result = -1;
8442 8442
8443 8443 out:
8444 8444 if (annotation_set != 0) {
8445 8445 /* Turn off annotation. It is no longer needed. */
8446 8446 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8447 8447 }
8448 8448
8449 8449 free_imp_globals();
8450 8450
8451 8451 return (result);
8452 8452 }
8453 8453
8454 8454 /*
8455 8455 * _lscf_import_err() summarize the error handling returned by
8456 8456 * lscf_import_{instance | service}_pgs
8457 8457 * Return values are:
8458 8458 * IMPORT_NEXT
8459 8459 * IMPORT_OUT
8460 8460 * IMPORT_BAD
8461 8461 */
8462 8462
8463 8463 #define IMPORT_BAD -1
8464 8464 #define IMPORT_NEXT 0
8465 8465 #define IMPORT_OUT 1
8466 8466
8467 8467 static int
8468 8468 _lscf_import_err(int err, const char *fmri)
8469 8469 {
8470 8470 switch (err) {
8471 8471 case 0:
8472 8472 if (g_verbose)
8473 8473 warn(gettext("%s updated.\n"), fmri);
8474 8474 return (IMPORT_NEXT);
8475 8475
8476 8476 case ECONNABORTED:
8477 8477 warn(gettext("Could not update %s "
8478 8478 "(repository connection broken).\n"), fmri);
8479 8479 return (IMPORT_OUT);
8480 8480
8481 8481 case ENOMEM:
8482 8482 warn(gettext("Could not update %s (out of memory).\n"), fmri);
8483 8483 return (IMPORT_OUT);
8484 8484
8485 8485 case ENOSPC:
8486 8486 warn(gettext("Could not update %s "
8487 8487 "(repository server out of resources).\n"), fmri);
8488 8488 return (IMPORT_OUT);
8489 8489
8490 8490 case ECANCELED:
8491 8491 warn(gettext(
8492 8492 "Could not update %s (deleted).\n"), fmri);
8493 8493 return (IMPORT_NEXT);
8494 8494
8495 8495 case EPERM:
8496 8496 case EINVAL:
8497 8497 case EBUSY:
8498 8498 return (IMPORT_NEXT);
8499 8499
8500 8500 case EROFS:
8501 8501 warn(gettext("Could not update %s (repository read-only).\n"),
8502 8502 fmri);
8503 8503 return (IMPORT_OUT);
8504 8504
8505 8505 case EACCES:
8506 8506 warn(gettext("Could not update %s "
8507 8507 "(backend access denied).\n"), fmri);
8508 8508 return (IMPORT_NEXT);
8509 8509
8510 8510 case EEXIST:
8511 8511 default:
8512 8512 return (IMPORT_BAD);
8513 8513 }
8514 8514
8515 8515 /*NOTREACHED*/
8516 8516 }
8517 8517
8518 8518 /*
8519 8519 * The global imp_svc and imp_inst should be set by the caller in the
8520 8520 * check to make sure the service and instance exist that the apply is
8521 8521 * working on.
8522 8522 */
8523 8523 static int
8524 8524 lscf_dependent_apply(void *dpg, void *e)
8525 8525 {
8526 8526 scf_callback_t cb;
8527 8527 pgroup_t *dpt_pgroup = dpg;
8528 8528 pgroup_t *deldpt;
8529 8529 entity_t *ent = e;
8530 8530 int tissvc;
8531 8531 void *sc_ent, *tent;
8532 8532 scf_error_t serr;
8533 8533 int r;
8534 8534
8535 8535 const char * const dependents = "dependents";
8536 8536 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8537 8537
8538 8538 if (issvc)
8539 8539 sc_ent = imp_svc;
8540 8540 else
8541 8541 sc_ent = imp_inst;
8542 8542
8543 8543 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8544 8544 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8545 8545 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8546 8546 imp_prop) != 0) {
8547 8547 switch (scf_error()) {
8548 8548 case SCF_ERROR_NOT_FOUND:
8549 8549 case SCF_ERROR_DELETED:
8550 8550 break;
8551 8551
8552 8552 case SCF_ERROR_CONNECTION_BROKEN:
8553 8553 case SCF_ERROR_NOT_SET:
8554 8554 case SCF_ERROR_INVALID_ARGUMENT:
8555 8555 case SCF_ERROR_HANDLE_MISMATCH:
8556 8556 case SCF_ERROR_NOT_BOUND:
8557 8557 default:
8558 8558 bad_error("entity_get_pg", scf_error());
8559 8559 }
8560 8560 } else {
8561 8561 /*
8562 8562 * Found the dependents/<wip dep> so check to
8563 8563 * see if the service is different. If so
8564 8564 * store the service for later refresh, and
8565 8565 * delete the wip dependency from the service
8566 8566 */
8567 8567 if (scf_property_get_value(imp_prop, ud_val) != 0) {
8568 8568 switch (scf_error()) {
8569 8569 case SCF_ERROR_DELETED:
8570 8570 break;
8571 8571
8572 8572 case SCF_ERROR_CONNECTION_BROKEN:
8573 8573 case SCF_ERROR_NOT_SET:
8574 8574 case SCF_ERROR_INVALID_ARGUMENT:
8575 8575 case SCF_ERROR_HANDLE_MISMATCH:
8576 8576 case SCF_ERROR_NOT_BOUND:
8577 8577 default:
8578 8578 bad_error("scf_property_get_value",
8579 8579 scf_error());
8580 8580 }
8581 8581 }
8582 8582
8583 8583 if (scf_value_get_as_string(ud_val, ud_oldtarg,
8584 8584 max_scf_value_len + 1) < 0)
8585 8585 bad_error("scf_value_get_as_string", scf_error());
8586 8586
8587 8587 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8588 8588 switch (r) {
8589 8589 case 1:
8590 8590 break;
8591 8591 case 0:
8592 8592 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8593 8593 &tissvc)) != SCF_ERROR_NONE) {
8594 8594 if (serr == SCF_ERROR_NOT_FOUND) {
8595 8595 break;
8596 8596 } else {
8597 8597 bad_error("fmri_to_entity", serr);
8598 8598 }
8599 8599 }
8600 8600
8601 8601 if (entity_get_pg(tent, tissvc,
8602 8602 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8603 8603 serr = scf_error();
8604 8604 if (serr == SCF_ERROR_NOT_FOUND ||
8605 8605 serr == SCF_ERROR_DELETED) {
8606 8606 break;
8607 8607 } else {
8608 8608 bad_error("entity_get_pg", scf_error());
8609 8609 }
8610 8610 }
8611 8611
8612 8612 if (scf_pg_delete(imp_pg) != 0) {
8613 8613 serr = scf_error();
8614 8614 if (serr == SCF_ERROR_NOT_FOUND ||
8615 8615 serr == SCF_ERROR_DELETED) {
8616 8616 break;
8617 8617 } else {
8618 8618 bad_error("scf_pg_delete", scf_error());
8619 8619 }
8620 8620 }
8621 8621
8622 8622 deldpt = internal_pgroup_new();
8623 8623 if (deldpt == NULL)
8624 8624 return (ENOMEM);
8625 8625 deldpt->sc_pgroup_name =
8626 8626 strdup(dpt_pgroup->sc_pgroup_name);
8627 8627 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8628 8628 if (deldpt->sc_pgroup_name == NULL ||
8629 8629 deldpt->sc_pgroup_fmri == NULL)
8630 8630 return (ENOMEM);
8631 8631 deldpt->sc_parent = (entity_t *)ent;
8632 8632 if (uu_list_insert_after(imp_deleted_dpts, NULL,
8633 8633 deldpt) != 0)
8634 8634 uu_die(gettext("libuutil error: %s\n"),
8635 8635 uu_strerror(uu_error()));
8636 8636
8637 8637 break;
8638 8638 default:
8639 8639 bad_error("fmri_equal", r);
8640 8640 }
8641 8641 }
8642 8642
8643 8643 cb.sc_handle = g_hndl;
8644 8644 cb.sc_parent = ent;
8645 8645 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8646 8646 cb.sc_source_fmri = ent->sc_fmri;
8647 8647 cb.sc_target_fmri = ent->sc_fmri;
8648 8648 cb.sc_trans = NULL;
8649 8649 cb.sc_flags = SCI_FORCE;
8650 8650
8651 8651 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8652 8652 return (UU_WALK_ERROR);
8653 8653
8654 8654 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8655 8655 switch (r) {
8656 8656 case 0:
8657 8657 break;
8658 8658
8659 8659 case ENOMEM:
8660 8660 case ECONNABORTED:
8661 8661 case EPERM:
8662 8662 case -1:
8663 8663 warn(gettext("Unable to refresh \"%s\"\n"),
8664 8664 dpt_pgroup->sc_pgroup_fmri);
8665 8665 return (UU_WALK_ERROR);
8666 8666
8667 8667 default:
8668 8668 bad_error("imp_refresh_fmri", r);
8669 8669 }
8670 8670
8671 8671 return (UU_WALK_NEXT);
8672 8672 }
8673 8673
8674 8674 /*
8675 8675 * Returns
8676 8676 * 0 - success
8677 8677 * -1 - lscf_import_instance_pgs() failed.
8678 8678 */
8679 8679 int
8680 8680 lscf_bundle_apply(bundle_t *bndl, const char *file)
8681 8681 {
8682 8682 pgroup_t *old_dpt;
8683 8683 entity_t *svc, *inst;
8684 8684 int annotation_set = 0;
8685 8685 int ret = 0;
8686 8686 int r = 0;
8687 8687
8688 8688 lscf_prep_hndl();
8689 8689
8690 8690 if ((ret = alloc_imp_globals()))
8691 8691 goto out;
8692 8692
8693 8693 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8694 8694 scfdie();
8695 8695
8696 8696 /*
8697 8697 * Set the strings to be used for the security audit annotation
8698 8698 * event.
8699 8699 */
8700 8700 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8701 8701 annotation_set = 1;
8702 8702 } else {
8703 8703 switch (scf_error()) {
8704 8704 case SCF_ERROR_CONNECTION_BROKEN:
8705 8705 warn(gettext("Repository connection broken.\n"));
8706 8706 goto out;
8707 8707
8708 8708 case SCF_ERROR_INVALID_ARGUMENT:
8709 8709 case SCF_ERROR_NOT_BOUND:
8710 8710 case SCF_ERROR_NO_RESOURCES:
8711 8711 case SCF_ERROR_INTERNAL:
8712 8712 bad_error("_scf_set_annotation", scf_error());
8713 8713 /* NOTREACHED */
8714 8714
8715 8715 default:
8716 8716 /*
8717 8717 * Do not abort apply operation because of
8718 8718 * inability to create annotation audit event.
8719 8719 */
8720 8720 warn(gettext("_scf_set_annotation() unexpectedly "
8721 8721 "failed with return code of %d\n"), scf_error());
8722 8722 break;
8723 8723 }
8724 8724 }
8725 8725
8726 8726 for (svc = uu_list_first(bndl->sc_bundle_services);
8727 8727 svc != NULL;
8728 8728 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8729 8729 int refresh = 0;
8730 8730
8731 8731 if (scf_scope_get_service(imp_scope, svc->sc_name,
8732 8732 imp_svc) != 0) {
8733 8733 switch (scf_error()) {
8734 8734 case SCF_ERROR_NOT_FOUND:
8735 8735 if (g_verbose)
8736 8736 warn(gettext("Ignoring nonexistent "
8737 8737 "service %s.\n"), svc->sc_name);
8738 8738 continue;
8739 8739
8740 8740 default:
8741 8741 scfdie();
8742 8742 }
8743 8743 }
8744 8744
8745 8745 /*
8746 8746 * If there were missing types in the profile, then need to
8747 8747 * attempt to find the types.
8748 8748 */
8749 8749 if (svc->sc_miss_type) {
8750 8750 if (uu_list_numnodes(svc->sc_pgroups) &&
8751 8751 uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8752 8752 svc, UU_DEFAULT) != 0) {
8753 8753 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8754 8754 bad_error("uu_list_walk", uu_error());
8755 8755
8756 8756 ret = -1;
8757 8757 continue;
8758 8758 }
8759 8759
8760 8760 for (inst = uu_list_first(
8761 8761 svc->sc_u.sc_service.sc_service_instances);
8762 8762 inst != NULL;
8763 8763 inst = uu_list_next(
8764 8764 svc->sc_u.sc_service.sc_service_instances, inst)) {
8765 8765 /*
8766 8766 * If the instance doesn't exist just
8767 8767 * skip to the next instance and let the
8768 8768 * import note the missing instance.
8769 8769 */
8770 8770 if (scf_service_get_instance(imp_svc,
8771 8771 inst->sc_name, imp_inst) != 0)
8772 8772 continue;
8773 8773
8774 8774 if (uu_list_walk(inst->sc_pgroups,
8775 8775 find_current_pg_type, inst,
8776 8776 UU_DEFAULT) != 0) {
8777 8777 if (uu_error() !=
8778 8778 UU_ERROR_CALLBACK_FAILED)
8779 8779 bad_error("uu_list_walk",
8780 8780 uu_error());
8781 8781
8782 8782 ret = -1;
8783 8783 inst->sc_miss_type = B_TRUE;
8784 8784 }
8785 8785 }
8786 8786 }
8787 8787
8788 8788 /*
8789 8789 * if we have pgs in the profile, we need to refresh ALL
8790 8790 * instances of the service
8791 8791 */
8792 8792 if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8793 8793 refresh = 1;
8794 8794 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8795 8795 SCI_FORCE | SCI_KEEP);
8796 8796 switch (_lscf_import_err(r, svc->sc_fmri)) {
8797 8797 case IMPORT_NEXT:
8798 8798 break;
8799 8799
8800 8800 case IMPORT_OUT:
8801 8801 goto out;
8802 8802
8803 8803 case IMPORT_BAD:
8804 8804 default:
8805 8805 bad_error("lscf_import_service_pgs", r);
8806 8806 }
8807 8807 }
8808 8808
8809 8809 if (uu_list_numnodes(svc->sc_dependents) != 0) {
8810 8810 uu_list_walk(svc->sc_dependents,
8811 8811 lscf_dependent_apply, svc, UU_DEFAULT);
8812 8812 }
8813 8813
8814 8814 for (inst = uu_list_first(
8815 8815 svc->sc_u.sc_service.sc_service_instances);
8816 8816 inst != NULL;
8817 8817 inst = uu_list_next(
8818 8818 svc->sc_u.sc_service.sc_service_instances, inst)) {
8819 8819 /*
8820 8820 * This instance still has missing types
8821 8821 * so skip it.
8822 8822 */
8823 8823 if (inst->sc_miss_type) {
8824 8824 if (g_verbose)
8825 8825 warn(gettext("Ignoring instance "
8826 8826 "%s:%s with missing types\n"),
8827 8827 inst->sc_parent->sc_name,
8828 8828 inst->sc_name);
8829 8829
8830 8830 continue;
8831 8831 }
8832 8832
8833 8833 if (scf_service_get_instance(imp_svc, inst->sc_name,
8834 8834 imp_inst) != 0) {
8835 8835 switch (scf_error()) {
8836 8836 case SCF_ERROR_NOT_FOUND:
8837 8837 if (g_verbose)
8838 8838 warn(gettext("Ignoring "
8839 8839 "nonexistant instance "
8840 8840 "%s:%s.\n"),
8841 8841 inst->sc_parent->sc_name,
8842 8842 inst->sc_name);
8843 8843 continue;
8844 8844
8845 8845 default:
8846 8846 scfdie();
8847 8847 }
8848 8848 }
8849 8849
8850 8850 /*
8851 8851 * If the instance does not have a general/enabled
8852 8852 * property and no last-import snapshot then the
8853 8853 * instance is not a fully installed instance and
8854 8854 * should not have a profile applied to it.
8855 8855 *
8856 8856 * This could happen if a service/instance declares
8857 8857 * a dependent on behalf of another service/instance.
8858 8858 *
8859 8859 */
8860 8860 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8861 8861 imp_snap) != 0) {
8862 8862 if (scf_instance_get_pg(imp_inst,
8863 8863 SCF_PG_GENERAL, imp_pg) != 0 ||
8864 8864 scf_pg_get_property(imp_pg,
8865 8865 SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8866 8866 if (g_verbose)
8867 8867 warn(gettext("Ignoreing "
8868 8868 "partial instance "
8869 8869 "%s:%s.\n"),
8870 8870 inst->sc_parent->sc_name,
8871 8871 inst->sc_name);
8872 8872 continue;
8873 8873 }
8874 8874 }
8875 8875
8876 8876 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8877 8877 inst, SCI_FORCE | SCI_KEEP);
8878 8878 switch (_lscf_import_err(r, inst->sc_fmri)) {
8879 8879 case IMPORT_NEXT:
8880 8880 break;
8881 8881
8882 8882 case IMPORT_OUT:
8883 8883 goto out;
8884 8884
8885 8885 case IMPORT_BAD:
8886 8886 default:
8887 8887 bad_error("lscf_import_instance_pgs", r);
8888 8888 }
8889 8889
8890 8890 if (uu_list_numnodes(inst->sc_dependents) != 0) {
8891 8891 uu_list_walk(inst->sc_dependents,
8892 8892 lscf_dependent_apply, inst, UU_DEFAULT);
8893 8893 }
8894 8894
8895 8895 /* refresh only if there is no pgs in the service */
8896 8896 if (refresh == 0)
8897 8897 (void) refresh_entity(0, imp_inst,
8898 8898 inst->sc_fmri, NULL, NULL, NULL);
8899 8899 }
8900 8900
8901 8901 if (refresh == 1) {
8902 8902 char *name_buf = safe_malloc(max_scf_name_len + 1);
8903 8903
8904 8904 (void) refresh_entity(1, imp_svc, svc->sc_name,
8905 8905 imp_inst, imp_iter, name_buf);
8906 8906 free(name_buf);
8907 8907 }
8908 8908
8909 8909 for (old_dpt = uu_list_first(imp_deleted_dpts);
8910 8910 old_dpt != NULL;
8911 8911 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8912 8912 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8913 8913 old_dpt->sc_pgroup_name,
8914 8914 old_dpt->sc_parent->sc_fmri) != 0) {
8915 8915 warn(gettext("Unable to refresh \"%s\"\n"),
8916 8916 old_dpt->sc_pgroup_fmri);
8917 8917 }
8918 8918 }
8919 8919 }
8920 8920
8921 8921 out:
8922 8922 if (annotation_set) {
8923 8923 /* Remove security audit annotation strings. */
8924 8924 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8925 8925 }
8926 8926
8927 8927 free_imp_globals();
8928 8928 return (ret);
8929 8929 }
8930 8930
8931 8931
8932 8932 /*
8933 8933 * Export. These functions create and output an XML tree of a service
8934 8934 * description from the repository. This is largely the inverse of
8935 8935 * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8936 8936 *
8937 8937 * - We must include any properties which are not represented specifically by
8938 8938 * a service manifest, e.g., properties created by an admin post-import. To
8939 8939 * do so we'll iterate through all properties and deal with each
8940 8940 * apropriately.
8941 8941 *
8942 8942 * - Children of services and instances must must be in the order set by the
8943 8943 * DTD, but we iterate over the properties in undefined order. The elements
8944 8944 * are not easily (or efficiently) sortable by name. Since there's a fixed
8945 8945 * number of classes of them, however, we'll keep the classes separate and
8946 8946 * assemble them in order.
8947 8947 */
8948 8948
8949 8949 /*
8950 8950 * Convenience function to handle xmlSetProp errors (and type casting).
8951 8951 */
8952 8952 static void
8953 8953 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8954 8954 {
8955 8955 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8956 8956 uu_die(gettext("Could not set XML property.\n"));
8957 8957 }
8958 8958
8959 8959 /*
8960 8960 * Convenience function to set an XML attribute to the single value of an
8961 8961 * astring property. If the value happens to be the default, don't set the
8962 8962 * attribute. "dval" should be the default value supplied by the DTD, or
8963 8963 * NULL for no default.
8964 8964 */
8965 8965 static int
8966 8966 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8967 8967 const char *name, const char *dval)
8968 8968 {
8969 8969 scf_value_t *val;
8970 8970 ssize_t len;
8971 8971 char *str;
8972 8972
8973 8973 val = scf_value_create(g_hndl);
8974 8974 if (val == NULL)
8975 8975 scfdie();
8976 8976
8977 8977 if (prop_get_val(prop, val) != 0) {
8978 8978 scf_value_destroy(val);
8979 8979 return (-1);
8980 8980 }
8981 8981
8982 8982 len = scf_value_get_as_string(val, NULL, 0);
8983 8983 if (len < 0)
8984 8984 scfdie();
8985 8985
8986 8986 str = safe_malloc(len + 1);
8987 8987
8988 8988 if (scf_value_get_as_string(val, str, len + 1) < 0)
8989 8989 scfdie();
8990 8990
8991 8991 scf_value_destroy(val);
8992 8992
8993 8993 if (dval == NULL || strcmp(str, dval) != 0)
8994 8994 safe_setprop(n, name, str);
8995 8995
8996 8996 free(str);
8997 8997
8998 8998 return (0);
8999 8999 }
9000 9000
9001 9001 /*
9002 9002 * As above, but the attribute is always set.
9003 9003 */
9004 9004 static int
9005 9005 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
9006 9006 {
9007 9007 return (set_attr_from_prop_default(prop, n, name, NULL));
9008 9008 }
9009 9009
9010 9010 /*
9011 9011 * Dump the given document onto f, with "'s replaced by ''s.
9012 9012 */
9013 9013 static int
9014 9014 write_service_bundle(xmlDocPtr doc, FILE *f)
9015 9015 {
9016 9016 xmlChar *mem;
9017 9017 int sz, i;
9018 9018
9019 9019 mem = NULL;
9020 9020 xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9021 9021
9022 9022 if (mem == NULL) {
9023 9023 semerr(gettext("Could not dump XML tree.\n"));
9024 9024 return (-1);
9025 9025 }
9026 9026
9027 9027 /*
9028 9028 * Fortunately libxml produces " instead of ", so we can blindly
9029 9029 * replace all " with '. Cursed libxml2! Why must you #ifdef out the
9030 9030 * ' code?!
9031 9031 */
9032 9032 for (i = 0; i < sz; ++i) {
9033 9033 char c = (char)mem[i];
9034 9034
9035 9035 if (c == '"')
9036 9036 (void) fputc('\'', f);
9037 9037 else if (c == '\'')
9038 9038 (void) fwrite("'", sizeof ("'") - 1, 1, f);
9039 9039 else
9040 9040 (void) fputc(c, f);
9041 9041 }
9042 9042
9043 9043 return (0);
9044 9044 }
9045 9045
9046 9046 /*
9047 9047 * Create the DOM elements in elts necessary to (generically) represent prop
9048 9048 * (i.e., a property or propval element). If the name of the property is
9049 9049 * known, it should be passed as name_arg. Otherwise, pass NULL.
9050 9050 */
9051 9051 static void
9052 9052 export_property(scf_property_t *prop, const char *name_arg,
9053 9053 struct pg_elts *elts, int flags)
9054 9054 {
9055 9055 const char *type;
9056 9056 scf_error_t err = 0;
9057 9057 xmlNodePtr pnode, lnode;
9058 9058 char *lnname;
9059 9059 int ret;
9060 9060
9061 9061 /* name */
9062 9062 if (name_arg != NULL) {
9063 9063 (void) strcpy(exp_str, name_arg);
9064 9064 } else {
9065 9065 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9066 9066 scfdie();
9067 9067 }
9068 9068
9069 9069 /* type */
9070 9070 type = prop_to_typestr(prop);
9071 9071 if (type == NULL)
9072 9072 uu_die(gettext("Can't export property %s: unknown type.\n"),
9073 9073 exp_str);
9074 9074
9075 9075 /* If we're exporting values, and there's just one, export it here. */
9076 9076 if (!(flags & SCE_ALL_VALUES))
9077 9077 goto empty;
9078 9078
9079 9079 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9080 9080 xmlNodePtr n;
9081 9081
9082 9082 /* Single value, so use propval */
9083 9083 n = xmlNewNode(NULL, (xmlChar *)"propval");
9084 9084 if (n == NULL)
9085 9085 uu_die(emsg_create_xml);
9086 9086
9087 9087 safe_setprop(n, name_attr, exp_str);
9088 9088 safe_setprop(n, type_attr, type);
9089 9089
9090 9090 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9091 9091 scfdie();
9092 9092 safe_setprop(n, value_attr, exp_str);
9093 9093
9094 9094 if (elts->propvals == NULL)
9095 9095 elts->propvals = n;
9096 9096 else
9097 9097 (void) xmlAddSibling(elts->propvals, n);
9098 9098
9099 9099 return;
9100 9100 }
9101 9101
9102 9102 err = scf_error();
9103 9103
9104 9104 if (err == SCF_ERROR_PERMISSION_DENIED) {
9105 9105 semerr(emsg_permission_denied);
9106 9106 return;
9107 9107 }
9108 9108
9109 9109 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9110 9110 err != SCF_ERROR_NOT_FOUND &&
9111 9111 err != SCF_ERROR_PERMISSION_DENIED)
9112 9112 scfdie();
9113 9113
9114 9114 empty:
9115 9115 /* Multiple (or no) values, so use property */
9116 9116 pnode = xmlNewNode(NULL, (xmlChar *)"property");
9117 9117 if (pnode == NULL)
9118 9118 uu_die(emsg_create_xml);
9119 9119
9120 9120 safe_setprop(pnode, name_attr, exp_str);
9121 9121 safe_setprop(pnode, type_attr, type);
9122 9122
9123 9123 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9124 9124 lnname = uu_msprintf("%s_list", type);
9125 9125 if (lnname == NULL)
9126 9126 uu_die(gettext("Could not create string"));
9127 9127
9128 9128 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9129 9129 if (lnode == NULL)
9130 9130 uu_die(emsg_create_xml);
9131 9131
9132 9132 uu_free(lnname);
9133 9133
9134 9134 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9135 9135 scfdie();
9136 9136
9137 9137 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9138 9138 1) {
9139 9139 xmlNodePtr vn;
9140 9140
9141 9141 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9142 9142 NULL);
9143 9143 if (vn == NULL)
9144 9144 uu_die(emsg_create_xml);
9145 9145
9146 9146 if (scf_value_get_as_string(exp_val, exp_str,
9147 9147 exp_str_sz) < 0)
9148 9148 scfdie();
9149 9149 safe_setprop(vn, value_attr, exp_str);
9150 9150 }
9151 9151 if (ret != 0)
9152 9152 scfdie();
9153 9153 }
9154 9154
9155 9155 if (elts->properties == NULL)
9156 9156 elts->properties = pnode;
9157 9157 else
9158 9158 (void) xmlAddSibling(elts->properties, pnode);
9159 9159 }
9160 9160
9161 9161 /*
9162 9162 * Add a property_group element for this property group to elts.
9163 9163 */
9164 9164 static void
9165 9165 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9166 9166 {
9167 9167 xmlNodePtr n;
9168 9168 struct pg_elts elts;
9169 9169 int ret;
9170 9170 boolean_t read_protected;
9171 9171
9172 9172 n = xmlNewNode(NULL, (xmlChar *)"property_group");
9173 9173
9174 9174 /* name */
9175 9175 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9176 9176 scfdie();
9177 9177 safe_setprop(n, name_attr, exp_str);
9178 9178
9179 9179 /* type */
9180 9180 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9181 9181 scfdie();
9182 9182 safe_setprop(n, type_attr, exp_str);
9183 9183
9184 9184 /* properties */
9185 9185 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9186 9186 scfdie();
9187 9187
9188 9188 (void) memset(&elts, 0, sizeof (elts));
9189 9189
9190 9190 /*
9191 9191 * If this property group is not read protected, we always want to
9192 9192 * output all the values. Otherwise, we only output the values if the
9193 9193 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9194 9194 */
9195 9195 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9196 9196 scfdie();
9197 9197
9198 9198 if (!read_protected)
9199 9199 flags |= SCE_ALL_VALUES;
9200 9200
9201 9201 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9202 9202 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9203 9203 scfdie();
9204 9204
9205 9205 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9206 9206 xmlNodePtr m;
9207 9207
9208 9208 m = xmlNewNode(NULL, (xmlChar *)"stability");
9209 9209 if (m == NULL)
9210 9210 uu_die(emsg_create_xml);
9211 9211
9212 9212 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9213 9213 elts.stability = m;
9214 9214 continue;
9215 9215 }
9216 9216
9217 9217 xmlFreeNode(m);
9218 9218 }
9219 9219
9220 9220 export_property(exp_prop, NULL, &elts, flags);
9221 9221 }
9222 9222 if (ret == -1)
9223 9223 scfdie();
9224 9224
9225 9225 (void) xmlAddChild(n, elts.stability);
9226 9226 (void) xmlAddChildList(n, elts.propvals);
9227 9227 (void) xmlAddChildList(n, elts.properties);
9228 9228
9229 9229 if (eelts->property_groups == NULL)
9230 9230 eelts->property_groups = n;
9231 9231 else
9232 9232 (void) xmlAddSibling(eelts->property_groups, n);
9233 9233 }
9234 9234
9235 9235 /*
9236 9236 * Create an XML node representing the dependency described by the given
9237 9237 * property group and put it in eelts. Unless the dependency is not valid, in
9238 9238 * which case create a generic property_group element which represents it and
9239 9239 * put it in eelts.
9240 9240 */
9241 9241 static void
9242 9242 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9243 9243 {
9244 9244 xmlNodePtr n;
9245 9245 int err = 0, ret;
9246 9246 struct pg_elts elts;
9247 9247
9248 9248 n = xmlNewNode(NULL, (xmlChar *)"dependency");
9249 9249 if (n == NULL)
9250 9250 uu_die(emsg_create_xml);
9251 9251
9252 9252 /*
9253 9253 * If the external flag is present, skip this dependency because it
9254 9254 * should have been created by another manifest.
9255 9255 */
9256 9256 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9257 9257 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9258 9258 prop_get_val(exp_prop, exp_val) == 0) {
9259 9259 uint8_t b;
9260 9260
9261 9261 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9262 9262 scfdie();
9263 9263
9264 9264 if (b)
9265 9265 return;
9266 9266 }
9267 9267 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
9268 9268 scfdie();
9269 9269
9270 9270 /* Get the required attributes. */
9271 9271
9272 9272 /* name */
9273 9273 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9274 9274 scfdie();
9275 9275 safe_setprop(n, name_attr, exp_str);
9276 9276
9277 9277 /* grouping */
9278 9278 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9279 9279 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9280 9280 err = 1;
9281 9281
9282 9282 /* restart_on */
9283 9283 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9284 9284 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9285 9285 err = 1;
9286 9286
9287 9287 /* type */
9288 9288 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9289 9289 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9290 9290 err = 1;
9291 9291
9292 9292 /*
9293 9293 * entities: Not required, but if we create no children, it will be
9294 9294 * created as empty on import, so fail if it's missing.
9295 9295 */
9296 9296 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9297 9297 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9298 9298 scf_iter_t *eiter;
9299 9299 int ret2;
9300 9300
9301 9301 eiter = scf_iter_create(g_hndl);
9302 9302 if (eiter == NULL)
9303 9303 scfdie();
9304 9304
9305 9305 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9306 9306 scfdie();
9307 9307
9308 9308 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9309 9309 xmlNodePtr ch;
9310 9310
9311 9311 if (scf_value_get_astring(exp_val, exp_str,
9312 9312 exp_str_sz) < 0)
9313 9313 scfdie();
9314 9314
9315 9315 /*
9316 9316 * service_fmri's must be first, so we can add them
9317 9317 * here.
9318 9318 */
9319 9319 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9320 9320 NULL);
9321 9321 if (ch == NULL)
9322 9322 uu_die(emsg_create_xml);
9323 9323
9324 9324 safe_setprop(ch, value_attr, exp_str);
9325 9325 }
9326 9326 if (ret2 == -1)
9327 9327 scfdie();
9328 9328
9329 9329 scf_iter_destroy(eiter);
9330 9330 } else
9331 9331 err = 1;
9332 9332
9333 9333 if (err) {
9334 9334 xmlFreeNode(n);
9335 9335
9336 9336 export_pg(pg, eelts, SCE_ALL_VALUES);
9337 9337
9338 9338 return;
9339 9339 }
9340 9340
9341 9341 /* Iterate through the properties & handle each. */
9342 9342 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9343 9343 scfdie();
9344 9344
9345 9345 (void) memset(&elts, 0, sizeof (elts));
9346 9346
9347 9347 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9348 9348 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9349 9349 scfdie();
9350 9350
9351 9351 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9352 9352 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9353 9353 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9354 9354 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9355 9355 continue;
9356 9356 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9357 9357 xmlNodePtr m;
9358 9358
9359 9359 m = xmlNewNode(NULL, (xmlChar *)"stability");
9360 9360 if (m == NULL)
9361 9361 uu_die(emsg_create_xml);
9362 9362
9363 9363 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9364 9364 elts.stability = m;
9365 9365 continue;
9366 9366 }
9367 9367
9368 9368 xmlFreeNode(m);
9369 9369 }
9370 9370
9371 9371 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9372 9372 }
9373 9373 if (ret == -1)
9374 9374 scfdie();
9375 9375
9376 9376 (void) xmlAddChild(n, elts.stability);
9377 9377 (void) xmlAddChildList(n, elts.propvals);
9378 9378 (void) xmlAddChildList(n, elts.properties);
9379 9379
9380 9380 if (eelts->dependencies == NULL)
9381 9381 eelts->dependencies = n;
9382 9382 else
9383 9383 (void) xmlAddSibling(eelts->dependencies, n);
9384 9384 }
9385 9385
9386 9386 static xmlNodePtr
9387 9387 export_method_environment(scf_propertygroup_t *pg)
9388 9388 {
9389 9389 xmlNodePtr env;
9390 9390 int ret;
9391 9391 int children = 0;
9392 9392
9393 9393 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9394 9394 return (NULL);
9395 9395
9396 9396 env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9397 9397 if (env == NULL)
9398 9398 uu_die(emsg_create_xml);
9399 9399
9400 9400 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9401 9401 scfdie();
9402 9402
9403 9403 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9404 9404 scfdie();
9405 9405
9406 9406 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9407 9407 xmlNodePtr ev;
9408 9408 char *cp;
9409 9409
9410 9410 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9411 9411 scfdie();
9412 9412
9413 9413 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9414 9414 warn(gettext("Invalid environment variable \"%s\".\n"),
9415 9415 exp_str);
9416 9416 continue;
9417 9417 } else if (strncmp(exp_str, "SMF_", 4) == 0) {
9418 9418 warn(gettext("Invalid environment variable \"%s\"; "
9419 9419 "\"SMF_\" prefix is reserved.\n"), exp_str);
9420 9420 continue;
9421 9421 }
9422 9422
9423 9423 *cp = '\0';
9424 9424 cp++;
9425 9425
9426 9426 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9427 9427 if (ev == NULL)
9428 9428 uu_die(emsg_create_xml);
9429 9429
9430 9430 safe_setprop(ev, name_attr, exp_str);
9431 9431 safe_setprop(ev, value_attr, cp);
9432 9432 children++;
9433 9433 }
9434 9434
9435 9435 if (ret != 0)
9436 9436 scfdie();
9437 9437
9438 9438 if (children == 0) {
9439 9439 xmlFreeNode(env);
9440 9440 return (NULL);
9441 9441 }
9442 9442
9443 9443 return (env);
9444 9444 }
9445 9445
9446 9446 /*
9447 9447 * As above, but for a method property group.
9448 9448 */
9449 9449 static void
9450 9450 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9451 9451 {
9452 9452 xmlNodePtr n, env;
9453 9453 char *str;
9454 9454 int err = 0, nonenv, ret;
9455 9455 uint8_t use_profile;
9456 9456 struct pg_elts elts;
9457 9457 xmlNodePtr ctxt = NULL;
9458 9458
9459 9459 n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9460 9460
9461 9461 /* Get the required attributes. */
9462 9462
9463 9463 /* name */
9464 9464 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9465 9465 scfdie();
9466 9466 safe_setprop(n, name_attr, exp_str);
9467 9467
9468 9468 /* type */
9469 9469 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9470 9470 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9471 9471 err = 1;
9472 9472
9473 9473 /* exec */
9474 9474 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9475 9475 set_attr_from_prop(exp_prop, n, "exec") != 0)
9476 9476 err = 1;
9477 9477
9478 9478 /* timeout */
9479 9479 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9480 9480 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9481 9481 prop_get_val(exp_prop, exp_val) == 0) {
9482 9482 uint64_t c;
9483 9483
9484 9484 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9485 9485 scfdie();
9486 9486
9487 9487 str = uu_msprintf("%llu", c);
9488 9488 if (str == NULL)
9489 9489 uu_die(gettext("Could not create string"));
9490 9490
9491 9491 safe_setprop(n, "timeout_seconds", str);
9492 9492 free(str);
9493 9493 } else
9494 9494 err = 1;
9495 9495
9496 9496 if (err) {
9497 9497 xmlFreeNode(n);
9498 9498
9499 9499 export_pg(pg, eelts, SCE_ALL_VALUES);
9500 9500
9501 9501 return;
9502 9502 }
9503 9503
9504 9504
9505 9505 /*
9506 9506 * If we're going to have a method_context child, we need to know
9507 9507 * before we iterate through the properties. Since method_context's
9508 9508 * are optional, we don't want to complain about any properties
↓ open down ↓ |
9508 lines elided |
↑ open up ↑ |
9509 9509 * missing if none of them are there. Thus we can't use the
9510 9510 * convenience functions.
9511 9511 */
9512 9512 nonenv =
9513 9513 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9514 9514 SCF_SUCCESS ||
9515 9515 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9516 9516 SCF_SUCCESS ||
9517 9517 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9518 9518 SCF_SUCCESS ||
9519 + scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) ==
9520 + SCF_SUCCESS ||
9519 9521 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9520 9522 SCF_SUCCESS;
9521 9523
9522 9524 if (nonenv) {
9523 9525 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9524 9526 if (ctxt == NULL)
9525 9527 uu_die(emsg_create_xml);
9526 9528
9527 9529 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9528 9530 0 &&
9529 9531 set_attr_from_prop_default(exp_prop, ctxt,
9530 9532 "working_directory", ":default") != 0)
9531 9533 err = 1;
9532 9534
↓ open down ↓ |
4 lines elided |
↑ open up ↑ |
9533 9535 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9534 9536 set_attr_from_prop_default(exp_prop, ctxt, "project",
9535 9537 ":default") != 0)
9536 9538 err = 1;
9537 9539
9538 9540 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9539 9541 0 &&
9540 9542 set_attr_from_prop_default(exp_prop, ctxt,
9541 9543 "resource_pool", ":default") != 0)
9542 9544 err = 1;
9545 +
9546 + if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 &&
9547 + set_attr_from_prop_default(exp_prop, ctxt,
9548 + "security_flags", ":default") != 0)
9549 + err = 1;
9550 +
9543 9551 /*
9544 9552 * We only want to complain about profile or credential
9545 9553 * properties if we will use them. To determine that we must
9546 9554 * examine USE_PROFILE.
9547 9555 */
9548 9556 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9549 9557 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9550 9558 prop_get_val(exp_prop, exp_val) == 0) {
9551 9559 if (scf_value_get_boolean(exp_val, &use_profile) !=
9552 9560 SCF_SUCCESS) {
9553 9561 scfdie();
9554 9562 }
9555 9563
9556 9564 if (use_profile) {
9557 9565 xmlNodePtr prof;
9558 9566
9559 9567 prof = xmlNewChild(ctxt, NULL,
9560 9568 (xmlChar *)"method_profile", NULL);
9561 9569 if (prof == NULL)
9562 9570 uu_die(emsg_create_xml);
9563 9571
9564 9572 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9565 9573 exp_prop) != 0 ||
9566 9574 set_attr_from_prop(exp_prop, prof,
9567 9575 name_attr) != 0)
9568 9576 err = 1;
9569 9577 } else {
9570 9578 xmlNodePtr cred;
9571 9579
9572 9580 cred = xmlNewChild(ctxt, NULL,
9573 9581 (xmlChar *)"method_credential", NULL);
9574 9582 if (cred == NULL)
9575 9583 uu_die(emsg_create_xml);
9576 9584
9577 9585 if (pg_get_prop(pg, SCF_PROPERTY_USER,
9578 9586 exp_prop) != 0 ||
9579 9587 set_attr_from_prop(exp_prop, cred,
9580 9588 "user") != 0) {
9581 9589 err = 1;
9582 9590 }
9583 9591
9584 9592 if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9585 9593 exp_prop) == 0 &&
9586 9594 set_attr_from_prop_default(exp_prop, cred,
9587 9595 "group", ":default") != 0)
9588 9596 err = 1;
9589 9597
9590 9598 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9591 9599 exp_prop) == 0 &&
9592 9600 set_attr_from_prop_default(exp_prop, cred,
9593 9601 "supp_groups", ":default") != 0)
9594 9602 err = 1;
9595 9603
9596 9604 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9597 9605 exp_prop) == 0 &&
9598 9606 set_attr_from_prop_default(exp_prop, cred,
9599 9607 "privileges", ":default") != 0)
9600 9608 err = 1;
9601 9609
9602 9610 if (pg_get_prop(pg,
9603 9611 SCF_PROPERTY_LIMIT_PRIVILEGES,
9604 9612 exp_prop) == 0 &&
9605 9613 set_attr_from_prop_default(exp_prop, cred,
9606 9614 "limit_privileges", ":default") != 0)
9607 9615 err = 1;
9608 9616 }
9609 9617 }
9610 9618 }
9611 9619
9612 9620 if ((env = export_method_environment(pg)) != NULL) {
9613 9621 if (ctxt == NULL) {
9614 9622 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9615 9623 if (ctxt == NULL)
9616 9624 uu_die(emsg_create_xml);
9617 9625 }
9618 9626 (void) xmlAddChild(ctxt, env);
9619 9627 }
9620 9628
9621 9629 if (env != NULL || (nonenv && err == 0))
9622 9630 (void) xmlAddChild(n, ctxt);
9623 9631 else
9624 9632 xmlFreeNode(ctxt);
9625 9633
9626 9634 nonenv = (err == 0);
9627 9635
9628 9636 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9629 9637 scfdie();
9630 9638
9631 9639 (void) memset(&elts, 0, sizeof (elts));
9632 9640
9633 9641 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9634 9642 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9635 9643 scfdie();
9636 9644
9637 9645 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9638 9646 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9639 9647 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9640 9648 continue;
9641 9649 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9642 9650 xmlNodePtr m;
9643 9651
9644 9652 m = xmlNewNode(NULL, (xmlChar *)"stability");
9645 9653 if (m == NULL)
9646 9654 uu_die(emsg_create_xml);
9647 9655
9648 9656 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9649 9657 elts.stability = m;
9650 9658 continue;
9651 9659 }
9652 9660
9653 9661 xmlFreeNode(m);
9654 9662 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
↓ open down ↓ |
102 lines elided |
↑ open up ↑ |
9655 9663 0 ||
9656 9664 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9657 9665 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9658 9666 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9659 9667 if (nonenv)
9660 9668 continue;
9661 9669 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9662 9670 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9663 9671 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9664 9672 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9665 - strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
9673 + strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 ||
9674 + strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9666 9675 if (nonenv && !use_profile)
9667 9676 continue;
9668 9677 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9669 9678 if (nonenv && use_profile)
9670 9679 continue;
9671 9680 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9672 9681 if (env != NULL)
9673 9682 continue;
9674 9683 }
9675 9684
9676 9685 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9677 9686 }
9678 9687 if (ret == -1)
9679 9688 scfdie();
9680 9689
9681 9690 (void) xmlAddChild(n, elts.stability);
9682 9691 (void) xmlAddChildList(n, elts.propvals);
9683 9692 (void) xmlAddChildList(n, elts.properties);
9684 9693
9685 9694 if (eelts->exec_methods == NULL)
9686 9695 eelts->exec_methods = n;
9687 9696 else
9688 9697 (void) xmlAddSibling(eelts->exec_methods, n);
9689 9698 }
9690 9699
9691 9700 static void
9692 9701 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9693 9702 struct entity_elts *eelts)
9694 9703 {
9695 9704 xmlNodePtr pgnode;
9696 9705
9697 9706 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9698 9707 if (pgnode == NULL)
9699 9708 uu_die(emsg_create_xml);
9700 9709
9701 9710 safe_setprop(pgnode, name_attr, name);
9702 9711 safe_setprop(pgnode, type_attr, type);
9703 9712
9704 9713 (void) xmlAddChildList(pgnode, elts->propvals);
9705 9714 (void) xmlAddChildList(pgnode, elts->properties);
9706 9715
9707 9716 if (eelts->property_groups == NULL)
9708 9717 eelts->property_groups = pgnode;
9709 9718 else
9710 9719 (void) xmlAddSibling(eelts->property_groups, pgnode);
9711 9720 }
9712 9721
9713 9722 /*
9714 9723 * Process the general property group for a service. This is the one with the
9715 9724 * goodies.
9716 9725 */
9717 9726 static void
9718 9727 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9719 9728 {
9720 9729 struct pg_elts elts;
9721 9730 int ret;
9722 9731
9723 9732 /*
9724 9733 * In case there are properties which don't correspond to child
9725 9734 * entities of the service entity, we'll set up a pg_elts structure to
9726 9735 * put them in.
9727 9736 */
9728 9737 (void) memset(&elts, 0, sizeof (elts));
9729 9738
9730 9739 /* Walk the properties, looking for special ones. */
9731 9740 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9732 9741 scfdie();
9733 9742
9734 9743 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9735 9744 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9736 9745 scfdie();
9737 9746
9738 9747 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9739 9748 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9740 9749 prop_get_val(exp_prop, exp_val) == 0) {
9741 9750 uint8_t b;
9742 9751
9743 9752 if (scf_value_get_boolean(exp_val, &b) !=
9744 9753 SCF_SUCCESS)
9745 9754 scfdie();
9746 9755
9747 9756 if (b) {
9748 9757 selts->single_instance =
9749 9758 xmlNewNode(NULL,
9750 9759 (xmlChar *)"single_instance");
9751 9760 if (selts->single_instance == NULL)
9752 9761 uu_die(emsg_create_xml);
9753 9762 }
9754 9763
9755 9764 continue;
9756 9765 }
9757 9766 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9758 9767 xmlNodePtr rnode, sfnode;
9759 9768
9760 9769 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9761 9770 if (rnode == NULL)
9762 9771 uu_die(emsg_create_xml);
9763 9772
9764 9773 sfnode = xmlNewChild(rnode, NULL,
9765 9774 (xmlChar *)"service_fmri", NULL);
9766 9775 if (sfnode == NULL)
9767 9776 uu_die(emsg_create_xml);
9768 9777
9769 9778 if (set_attr_from_prop(exp_prop, sfnode,
9770 9779 value_attr) == 0) {
9771 9780 selts->restarter = rnode;
9772 9781 continue;
9773 9782 }
9774 9783
9775 9784 xmlFreeNode(rnode);
9776 9785 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9777 9786 0) {
9778 9787 xmlNodePtr s;
9779 9788
9780 9789 s = xmlNewNode(NULL, (xmlChar *)"stability");
9781 9790 if (s == NULL)
9782 9791 uu_die(emsg_create_xml);
9783 9792
9784 9793 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9785 9794 selts->stability = s;
9786 9795 continue;
9787 9796 }
9788 9797
9789 9798 xmlFreeNode(s);
9790 9799 }
9791 9800
9792 9801 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9793 9802 }
9794 9803 if (ret == -1)
9795 9804 scfdie();
9796 9805
9797 9806 if (elts.propvals != NULL || elts.properties != NULL)
9798 9807 export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9799 9808 selts);
9800 9809 }
9801 9810
9802 9811 static void
9803 9812 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9804 9813 {
9805 9814 xmlNodePtr n, prof, cred, env;
9806 9815 uint8_t use_profile;
9807 9816 int ret, err = 0;
9808 9817
9809 9818 n = xmlNewNode(NULL, (xmlChar *)"method_context");
9810 9819
9811 9820 env = export_method_environment(pg);
9812 9821
9813 9822 /* Need to know whether we'll use a profile or not. */
9814 9823 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9815 9824 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9816 9825 prop_get_val(exp_prop, exp_val) == 0) {
9817 9826 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9818 9827 scfdie();
9819 9828
9820 9829 if (use_profile)
9821 9830 prof =
9822 9831 xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9823 9832 NULL);
9824 9833 else
9825 9834 cred =
9826 9835 xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9827 9836 NULL);
9828 9837 }
9829 9838
9830 9839 if (env != NULL)
9831 9840 (void) xmlAddChild(n, env);
9832 9841
9833 9842 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9834 9843 scfdie();
9835 9844
9836 9845 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9837 9846 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9838 9847 scfdie();
9839 9848
9840 9849 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
↓ open down ↓ |
165 lines elided |
↑ open up ↑ |
9841 9850 if (set_attr_from_prop(exp_prop, n,
9842 9851 "working_directory") != 0)
9843 9852 err = 1;
9844 9853 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9845 9854 if (set_attr_from_prop(exp_prop, n, "project") != 0)
9846 9855 err = 1;
9847 9856 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9848 9857 if (set_attr_from_prop(exp_prop, n,
9849 9858 "resource_pool") != 0)
9850 9859 err = 1;
9860 + } else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9861 + if (set_attr_from_prop(exp_prop, n,
9862 + "security_flags") != 0)
9863 + err = 1;
9851 9864 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9852 9865 /* EMPTY */
9853 9866 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9854 9867 if (use_profile ||
9855 9868 set_attr_from_prop(exp_prop, cred, "user") != 0)
9856 9869 err = 1;
9857 9870 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9858 9871 if (use_profile ||
9859 9872 set_attr_from_prop(exp_prop, cred, "group") != 0)
9860 9873 err = 1;
9861 9874 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9862 9875 if (use_profile || set_attr_from_prop(exp_prop, cred,
9863 9876 "supp_groups") != 0)
9864 9877 err = 1;
9865 9878 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9866 9879 if (use_profile || set_attr_from_prop(exp_prop, cred,
9867 9880 "privileges") != 0)
9868 9881 err = 1;
9869 9882 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9870 9883 0) {
9871 9884 if (use_profile || set_attr_from_prop(exp_prop, cred,
9872 9885 "limit_privileges") != 0)
9873 9886 err = 1;
9874 9887 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9875 9888 if (!use_profile || set_attr_from_prop(exp_prop,
9876 9889 prof, name_attr) != 0)
9877 9890 err = 1;
9878 9891 } else {
9879 9892 /* Can't have generic properties in method_context's */
9880 9893 err = 1;
9881 9894 }
9882 9895 }
9883 9896 if (ret == -1)
9884 9897 scfdie();
9885 9898
9886 9899 if (err && env == NULL) {
9887 9900 xmlFreeNode(n);
9888 9901 export_pg(pg, elts, SCE_ALL_VALUES);
9889 9902 return;
9890 9903 }
9891 9904
9892 9905 elts->method_context = n;
9893 9906 }
9894 9907
9895 9908 /*
9896 9909 * Given a dependency property group in the tfmri entity (target fmri), return
9897 9910 * a dependent element which represents it.
9898 9911 */
9899 9912 static xmlNodePtr
9900 9913 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9901 9914 {
9902 9915 uint8_t b;
9903 9916 xmlNodePtr n, sf;
9904 9917 int err = 0, ret;
9905 9918 struct pg_elts pgelts;
9906 9919
9907 9920 /*
9908 9921 * If external isn't set to true then exporting the service will
9909 9922 * export this as a normal dependency, so we should stop to avoid
9910 9923 * duplication.
9911 9924 */
9912 9925 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9913 9926 scf_property_get_value(exp_prop, exp_val) != 0 ||
9914 9927 scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9915 9928 if (g_verbose) {
9916 9929 warn(gettext("Dependent \"%s\" cannot be exported "
9917 9930 "properly because the \"%s\" property of the "
9918 9931 "\"%s\" dependency of %s is not set to true.\n"),
9919 9932 name, scf_property_external, name, tfmri);
9920 9933 }
9921 9934
9922 9935 return (NULL);
9923 9936 }
9924 9937
9925 9938 n = xmlNewNode(NULL, (xmlChar *)"dependent");
9926 9939 if (n == NULL)
9927 9940 uu_die(emsg_create_xml);
9928 9941
9929 9942 safe_setprop(n, name_attr, name);
9930 9943
9931 9944 /* Get the required attributes */
9932 9945 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9933 9946 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9934 9947 err = 1;
9935 9948
9936 9949 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9937 9950 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9938 9951 err = 1;
9939 9952
9940 9953 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9941 9954 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9942 9955 prop_get_val(exp_prop, exp_val) == 0) {
9943 9956 /* EMPTY */
9944 9957 } else
9945 9958 err = 1;
9946 9959
9947 9960 if (err) {
9948 9961 xmlFreeNode(n);
9949 9962 return (NULL);
9950 9963 }
9951 9964
9952 9965 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9953 9966 if (sf == NULL)
9954 9967 uu_die(emsg_create_xml);
9955 9968
9956 9969 safe_setprop(sf, value_attr, tfmri);
9957 9970
9958 9971 /*
9959 9972 * Now add elements for the other properties.
9960 9973 */
9961 9974 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9962 9975 scfdie();
9963 9976
9964 9977 (void) memset(&pgelts, 0, sizeof (pgelts));
9965 9978
9966 9979 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9967 9980 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9968 9981 scfdie();
9969 9982
9970 9983 if (strcmp(exp_str, scf_property_external) == 0 ||
9971 9984 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9972 9985 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9973 9986 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9974 9987 continue;
9975 9988 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9976 9989 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9977 9990 prop_get_val(exp_prop, exp_val) == 0) {
9978 9991 char type[sizeof ("service") + 1];
9979 9992
9980 9993 if (scf_value_get_astring(exp_val, type,
9981 9994 sizeof (type)) < 0)
9982 9995 scfdie();
9983 9996
9984 9997 if (strcmp(type, "service") == 0)
9985 9998 continue;
9986 9999 }
9987 10000 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9988 10001 xmlNodePtr s;
9989 10002
9990 10003 s = xmlNewNode(NULL, (xmlChar *)"stability");
9991 10004 if (s == NULL)
9992 10005 uu_die(emsg_create_xml);
9993 10006
9994 10007 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9995 10008 pgelts.stability = s;
9996 10009 continue;
9997 10010 }
9998 10011
9999 10012 xmlFreeNode(s);
10000 10013 }
10001 10014
10002 10015 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10003 10016 }
10004 10017 if (ret == -1)
10005 10018 scfdie();
10006 10019
10007 10020 (void) xmlAddChild(n, pgelts.stability);
10008 10021 (void) xmlAddChildList(n, pgelts.propvals);
10009 10022 (void) xmlAddChildList(n, pgelts.properties);
10010 10023
10011 10024 return (n);
10012 10025 }
10013 10026
10014 10027 static void
10015 10028 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10016 10029 {
10017 10030 scf_propertygroup_t *opg;
10018 10031 scf_iter_t *iter;
10019 10032 char *type, *fmri;
10020 10033 int ret;
10021 10034 struct pg_elts pgelts;
10022 10035 xmlNodePtr n;
10023 10036 scf_error_t serr;
10024 10037
10025 10038 if ((opg = scf_pg_create(g_hndl)) == NULL ||
10026 10039 (iter = scf_iter_create(g_hndl)) == NULL)
10027 10040 scfdie();
10028 10041
10029 10042 /* Can't use exp_prop_iter due to export_dependent(). */
10030 10043 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10031 10044 scfdie();
10032 10045
10033 10046 type = safe_malloc(max_scf_pg_type_len + 1);
10034 10047
10035 10048 /* Get an extra byte so we can tell if values are too long. */
10036 10049 fmri = safe_malloc(max_scf_fmri_len + 2);
10037 10050
10038 10051 (void) memset(&pgelts, 0, sizeof (pgelts));
10039 10052
10040 10053 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10041 10054 void *entity;
10042 10055 int isservice;
10043 10056 scf_type_t ty;
10044 10057
10045 10058 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10046 10059 scfdie();
10047 10060
10048 10061 if ((ty != SCF_TYPE_ASTRING &&
10049 10062 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10050 10063 prop_get_val(exp_prop, exp_val) != 0) {
10051 10064 export_property(exp_prop, NULL, &pgelts,
10052 10065 SCE_ALL_VALUES);
10053 10066 continue;
10054 10067 }
10055 10068
10056 10069 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10057 10070 scfdie();
10058 10071
10059 10072 if (scf_value_get_astring(exp_val, fmri,
10060 10073 max_scf_fmri_len + 2) < 0)
10061 10074 scfdie();
10062 10075
10063 10076 /* Look for a dependency group in the target fmri. */
10064 10077 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10065 10078 switch (serr) {
10066 10079 case SCF_ERROR_NONE:
10067 10080 break;
10068 10081
10069 10082 case SCF_ERROR_NO_MEMORY:
10070 10083 uu_die(gettext("Out of memory.\n"));
10071 10084 /* NOTREACHED */
10072 10085
10073 10086 case SCF_ERROR_INVALID_ARGUMENT:
10074 10087 if (g_verbose) {
10075 10088 if (scf_property_to_fmri(exp_prop, fmri,
10076 10089 max_scf_fmri_len + 2) < 0)
10077 10090 scfdie();
10078 10091
10079 10092 warn(gettext("The value of %s is not a valid "
10080 10093 "FMRI.\n"), fmri);
10081 10094 }
10082 10095
10083 10096 export_property(exp_prop, exp_str, &pgelts,
10084 10097 SCE_ALL_VALUES);
10085 10098 continue;
10086 10099
10087 10100 case SCF_ERROR_CONSTRAINT_VIOLATED:
10088 10101 if (g_verbose) {
10089 10102 if (scf_property_to_fmri(exp_prop, fmri,
10090 10103 max_scf_fmri_len + 2) < 0)
10091 10104 scfdie();
10092 10105
10093 10106 warn(gettext("The value of %s does not specify "
10094 10107 "a service or an instance.\n"), fmri);
10095 10108 }
10096 10109
10097 10110 export_property(exp_prop, exp_str, &pgelts,
10098 10111 SCE_ALL_VALUES);
10099 10112 continue;
10100 10113
10101 10114 case SCF_ERROR_NOT_FOUND:
10102 10115 if (g_verbose) {
10103 10116 if (scf_property_to_fmri(exp_prop, fmri,
10104 10117 max_scf_fmri_len + 2) < 0)
10105 10118 scfdie();
10106 10119
10107 10120 warn(gettext("The entity specified by %s does "
10108 10121 "not exist.\n"), fmri);
10109 10122 }
10110 10123
10111 10124 export_property(exp_prop, exp_str, &pgelts,
10112 10125 SCE_ALL_VALUES);
10113 10126 continue;
10114 10127
10115 10128 default:
10116 10129 #ifndef NDEBUG
10117 10130 (void) fprintf(stderr, "%s:%d: %s() failed with "
10118 10131 "unexpected error %d.\n", __FILE__, __LINE__,
10119 10132 "fmri_to_entity", serr);
10120 10133 #endif
10121 10134 abort();
10122 10135 }
10123 10136
10124 10137 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10125 10138 if (scf_error() != SCF_ERROR_NOT_FOUND)
10126 10139 scfdie();
10127 10140
10128 10141 warn(gettext("Entity %s is missing dependency property "
10129 10142 "group %s.\n"), fmri, exp_str);
10130 10143
10131 10144 export_property(exp_prop, NULL, &pgelts,
10132 10145 SCE_ALL_VALUES);
10133 10146 continue;
10134 10147 }
10135 10148
10136 10149 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10137 10150 scfdie();
10138 10151
10139 10152 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10140 10153 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10141 10154 scfdie();
10142 10155
10143 10156 warn(gettext("Property group %s is not of "
10144 10157 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10145 10158
10146 10159 export_property(exp_prop, NULL, &pgelts,
10147 10160 SCE_ALL_VALUES);
10148 10161 continue;
10149 10162 }
10150 10163
10151 10164 n = export_dependent(opg, exp_str, fmri);
10152 10165 if (n == NULL) {
10153 10166 export_property(exp_prop, exp_str, &pgelts,
10154 10167 SCE_ALL_VALUES);
10155 10168 } else {
10156 10169 if (eelts->dependents == NULL)
10157 10170 eelts->dependents = n;
10158 10171 else
10159 10172 (void) xmlAddSibling(eelts->dependents,
10160 10173 n);
10161 10174 }
10162 10175 }
10163 10176 if (ret == -1)
10164 10177 scfdie();
10165 10178
10166 10179 free(fmri);
10167 10180 free(type);
10168 10181
10169 10182 scf_iter_destroy(iter);
10170 10183 scf_pg_destroy(opg);
10171 10184
10172 10185 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10173 10186 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10174 10187 eelts);
10175 10188 }
10176 10189
10177 10190 static void
10178 10191 make_node(xmlNodePtr *nodep, const char *name)
10179 10192 {
10180 10193 if (*nodep == NULL) {
10181 10194 *nodep = xmlNewNode(NULL, (xmlChar *)name);
10182 10195 if (*nodep == NULL)
10183 10196 uu_die(emsg_create_xml);
10184 10197 }
10185 10198 }
10186 10199
10187 10200 static xmlNodePtr
10188 10201 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10189 10202 {
10190 10203 int ret;
10191 10204 xmlNodePtr parent = NULL;
10192 10205 xmlNodePtr loctext = NULL;
10193 10206
10194 10207 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10195 10208 scfdie();
10196 10209
10197 10210 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10198 10211 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10199 10212 prop_get_val(exp_prop, exp_val) != 0)
10200 10213 continue;
10201 10214
10202 10215 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10203 10216 scfdie();
10204 10217
10205 10218 make_node(&parent, parname);
10206 10219 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10207 10220 (xmlChar *)exp_str);
10208 10221 if (loctext == NULL)
10209 10222 uu_die(emsg_create_xml);
10210 10223
10211 10224 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10212 10225 scfdie();
10213 10226
10214 10227 safe_setprop(loctext, "xml:lang", exp_str);
10215 10228 }
10216 10229
10217 10230 if (ret == -1)
10218 10231 scfdie();
10219 10232
10220 10233 return (parent);
10221 10234 }
10222 10235
10223 10236 static xmlNodePtr
10224 10237 export_tm_manpage(scf_propertygroup_t *pg)
10225 10238 {
10226 10239 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10227 10240 if (manpage == NULL)
10228 10241 uu_die(emsg_create_xml);
10229 10242
10230 10243 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10231 10244 set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10232 10245 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10233 10246 set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10234 10247 xmlFreeNode(manpage);
10235 10248 return (NULL);
10236 10249 }
10237 10250
10238 10251 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10239 10252 (void) set_attr_from_prop_default(exp_prop,
10240 10253 manpage, "manpath", ":default");
10241 10254
10242 10255 return (manpage);
10243 10256 }
10244 10257
10245 10258 static xmlNodePtr
10246 10259 export_tm_doc_link(scf_propertygroup_t *pg)
10247 10260 {
10248 10261 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10249 10262 if (doc_link == NULL)
10250 10263 uu_die(emsg_create_xml);
10251 10264
10252 10265 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10253 10266 set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10254 10267 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10255 10268 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10256 10269 xmlFreeNode(doc_link);
10257 10270 return (NULL);
10258 10271 }
10259 10272 return (doc_link);
10260 10273 }
10261 10274
10262 10275 /*
10263 10276 * Process template information for a service or instances.
10264 10277 */
10265 10278 static void
10266 10279 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10267 10280 struct template_elts *telts)
10268 10281 {
10269 10282 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10270 10283 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10271 10284 xmlNodePtr child = NULL;
10272 10285
10273 10286 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10274 10287 scfdie();
10275 10288
10276 10289 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10277 10290 telts->common_name = export_tm_loctext(pg, "common_name");
10278 10291 if (telts->common_name == NULL)
10279 10292 export_pg(pg, elts, SCE_ALL_VALUES);
10280 10293 return;
10281 10294 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10282 10295 telts->description = export_tm_loctext(pg, "description");
10283 10296 if (telts->description == NULL)
10284 10297 export_pg(pg, elts, SCE_ALL_VALUES);
10285 10298 return;
10286 10299 }
10287 10300
10288 10301 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10289 10302 child = export_tm_manpage(pg);
10290 10303 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10291 10304 child = export_tm_doc_link(pg);
10292 10305 }
10293 10306
10294 10307 if (child != NULL) {
10295 10308 make_node(&telts->documentation, "documentation");
10296 10309 (void) xmlAddChild(telts->documentation, child);
10297 10310 } else {
10298 10311 export_pg(pg, elts, SCE_ALL_VALUES);
10299 10312 }
10300 10313 }
10301 10314
10302 10315 /*
10303 10316 * Process parameter and paramval elements
10304 10317 */
10305 10318 static void
10306 10319 export_parameter(scf_property_t *prop, const char *name,
10307 10320 struct params_elts *elts)
10308 10321 {
10309 10322 xmlNodePtr param;
10310 10323 scf_error_t err = 0;
10311 10324 int ret;
10312 10325
10313 10326 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10314 10327 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10315 10328 uu_die(emsg_create_xml);
10316 10329
10317 10330 safe_setprop(param, name_attr, name);
10318 10331
10319 10332 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10320 10333 scfdie();
10321 10334 safe_setprop(param, value_attr, exp_str);
10322 10335
10323 10336 if (elts->paramval == NULL)
10324 10337 elts->paramval = param;
10325 10338 else
10326 10339 (void) xmlAddSibling(elts->paramval, param);
10327 10340
10328 10341 return;
10329 10342 }
10330 10343
10331 10344 err = scf_error();
10332 10345
10333 10346 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10334 10347 err != SCF_ERROR_NOT_FOUND)
10335 10348 scfdie();
10336 10349
10337 10350 if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10338 10351 uu_die(emsg_create_xml);
10339 10352
10340 10353 safe_setprop(param, name_attr, name);
10341 10354
10342 10355 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10343 10356 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10344 10357 scfdie();
10345 10358
10346 10359 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10347 10360 1) {
10348 10361 xmlNodePtr vn;
10349 10362
10350 10363 if ((vn = xmlNewChild(param, NULL,
10351 10364 (xmlChar *)"value_node", NULL)) == NULL)
10352 10365 uu_die(emsg_create_xml);
10353 10366
10354 10367 if (scf_value_get_as_string(exp_val, exp_str,
10355 10368 exp_str_sz) < 0)
10356 10369 scfdie();
10357 10370
10358 10371 safe_setprop(vn, value_attr, exp_str);
10359 10372 }
10360 10373 if (ret != 0)
10361 10374 scfdie();
10362 10375 }
10363 10376
10364 10377 if (elts->parameter == NULL)
10365 10378 elts->parameter = param;
10366 10379 else
10367 10380 (void) xmlAddSibling(elts->parameter, param);
10368 10381 }
10369 10382
10370 10383 /*
10371 10384 * Process notification parameters for a service or instance
10372 10385 */
10373 10386 static void
10374 10387 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10375 10388 {
10376 10389 xmlNodePtr n, event, *type;
10377 10390 struct params_elts *eelts;
10378 10391 int ret, err, i;
10379 10392
10380 10393 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10381 10394 event = xmlNewNode(NULL, (xmlChar *)"event");
10382 10395 if (n == NULL || event == NULL)
10383 10396 uu_die(emsg_create_xml);
10384 10397
10385 10398 /* event value */
10386 10399 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10387 10400 scfdie();
10388 10401 safe_setprop(event, value_attr, exp_str);
10389 10402
10390 10403 (void) xmlAddChild(n, event);
10391 10404
10392 10405 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10393 10406 (eelts = calloc(URI_SCHEME_NUM,
10394 10407 sizeof (struct params_elts))) == NULL)
10395 10408 uu_die(gettext("Out of memory.\n"));
10396 10409
10397 10410 err = 0;
10398 10411
10399 10412 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10400 10413 scfdie();
10401 10414
10402 10415 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10403 10416 char *t, *p;
10404 10417
10405 10418 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10406 10419 scfdie();
10407 10420
10408 10421 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10409 10422 /*
10410 10423 * this is not a well formed notification parameters
10411 10424 * element, we should export as regular pg
10412 10425 */
10413 10426 err = 1;
10414 10427 break;
10415 10428 }
10416 10429
10417 10430 if ((i = check_uri_protocol(t)) < 0) {
10418 10431 err = 1;
10419 10432 break;
10420 10433 }
10421 10434
10422 10435 if (type[i] == NULL) {
10423 10436 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10424 10437 NULL)
10425 10438 uu_die(emsg_create_xml);
10426 10439
10427 10440 safe_setprop(type[i], name_attr, t);
10428 10441 }
10429 10442 if (strcmp(p, active_attr) == 0) {
10430 10443 if (set_attr_from_prop(exp_prop, type[i],
10431 10444 active_attr) != 0) {
10432 10445 err = 1;
10433 10446 break;
10434 10447 }
10435 10448 continue;
10436 10449 }
10437 10450 /*
10438 10451 * We export the parameter
10439 10452 */
10440 10453 export_parameter(exp_prop, p, &eelts[i]);
10441 10454 }
10442 10455
10443 10456 if (ret == -1)
10444 10457 scfdie();
10445 10458
10446 10459 if (err == 1) {
10447 10460 for (i = 0; i < URI_SCHEME_NUM; ++i)
10448 10461 xmlFree(type[i]);
10449 10462 free(type);
10450 10463
10451 10464 export_pg(pg, elts, SCE_ALL_VALUES);
10452 10465
10453 10466 return;
10454 10467 } else {
10455 10468 for (i = 0; i < URI_SCHEME_NUM; ++i)
10456 10469 if (type[i] != NULL) {
10457 10470 (void) xmlAddChildList(type[i],
10458 10471 eelts[i].paramval);
10459 10472 (void) xmlAddChildList(type[i],
10460 10473 eelts[i].parameter);
10461 10474 (void) xmlAddSibling(event, type[i]);
10462 10475 }
10463 10476 }
10464 10477 free(type);
10465 10478
10466 10479 if (elts->notify_params == NULL)
10467 10480 elts->notify_params = n;
10468 10481 else
10469 10482 (void) xmlAddSibling(elts->notify_params, n);
10470 10483 }
10471 10484
10472 10485 /*
10473 10486 * Process the general property group for an instance.
10474 10487 */
10475 10488 static void
10476 10489 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10477 10490 struct entity_elts *elts)
10478 10491 {
10479 10492 uint8_t enabled;
10480 10493 struct pg_elts pgelts;
10481 10494 int ret;
10482 10495
10483 10496 /* enabled */
10484 10497 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10485 10498 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10486 10499 prop_get_val(exp_prop, exp_val) == 0) {
10487 10500 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10488 10501 scfdie();
10489 10502 } else {
10490 10503 enabled = 0;
10491 10504 }
10492 10505
10493 10506 safe_setprop(inode, enabled_attr, enabled ? true : false);
10494 10507
10495 10508 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10496 10509 scfdie();
10497 10510
10498 10511 (void) memset(&pgelts, 0, sizeof (pgelts));
10499 10512
10500 10513 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10501 10514 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10502 10515 scfdie();
10503 10516
10504 10517 if (strcmp(exp_str, scf_property_enabled) == 0) {
10505 10518 continue;
10506 10519 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10507 10520 xmlNodePtr rnode, sfnode;
10508 10521
10509 10522 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10510 10523 if (rnode == NULL)
10511 10524 uu_die(emsg_create_xml);
10512 10525
10513 10526 sfnode = xmlNewChild(rnode, NULL,
10514 10527 (xmlChar *)"service_fmri", NULL);
10515 10528 if (sfnode == NULL)
10516 10529 uu_die(emsg_create_xml);
10517 10530
10518 10531 if (set_attr_from_prop(exp_prop, sfnode,
10519 10532 value_attr) == 0) {
10520 10533 elts->restarter = rnode;
10521 10534 continue;
10522 10535 }
10523 10536
10524 10537 xmlFreeNode(rnode);
10525 10538 }
10526 10539
10527 10540 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10528 10541 }
10529 10542 if (ret == -1)
10530 10543 scfdie();
10531 10544
10532 10545 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10533 10546 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10534 10547 elts);
10535 10548 }
10536 10549
10537 10550 /*
10538 10551 * Put an instance element for the given instance into selts.
10539 10552 */
10540 10553 static void
10541 10554 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10542 10555 {
10543 10556 xmlNodePtr n;
10544 10557 boolean_t isdefault;
10545 10558 struct entity_elts elts;
10546 10559 struct template_elts template_elts;
10547 10560 int ret;
10548 10561
10549 10562 n = xmlNewNode(NULL, (xmlChar *)"instance");
10550 10563 if (n == NULL)
10551 10564 uu_die(emsg_create_xml);
10552 10565
10553 10566 /* name */
10554 10567 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10555 10568 scfdie();
10556 10569 safe_setprop(n, name_attr, exp_str);
10557 10570 isdefault = strcmp(exp_str, "default") == 0;
10558 10571
10559 10572 /* check existance of general pg (since general/enabled is required) */
10560 10573 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10561 10574 if (scf_error() != SCF_ERROR_NOT_FOUND)
10562 10575 scfdie();
10563 10576
10564 10577 if (g_verbose) {
10565 10578 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10566 10579 scfdie();
10567 10580
10568 10581 warn(gettext("Instance %s has no general property "
10569 10582 "group; it will be marked disabled.\n"), exp_str);
10570 10583 }
10571 10584
10572 10585 safe_setprop(n, enabled_attr, false);
10573 10586 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10574 10587 strcmp(exp_str, scf_group_framework) != 0) {
10575 10588 if (g_verbose) {
10576 10589 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10577 10590 scfdie();
10578 10591
10579 10592 warn(gettext("Property group %s is not of type "
10580 10593 "framework; the instance will be marked "
10581 10594 "disabled.\n"), exp_str);
10582 10595 }
10583 10596
10584 10597 safe_setprop(n, enabled_attr, false);
10585 10598 }
10586 10599
10587 10600 /* property groups */
10588 10601 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10589 10602 scfdie();
10590 10603
10591 10604 (void) memset(&elts, 0, sizeof (elts));
10592 10605 (void) memset(&template_elts, 0, sizeof (template_elts));
10593 10606
10594 10607 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10595 10608 uint32_t pgflags;
10596 10609
10597 10610 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10598 10611 scfdie();
10599 10612
10600 10613 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10601 10614 continue;
10602 10615
10603 10616 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10604 10617 scfdie();
10605 10618
10606 10619 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10607 10620 export_dependency(exp_pg, &elts);
10608 10621 continue;
10609 10622 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10610 10623 export_method(exp_pg, &elts);
10611 10624 continue;
10612 10625 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10613 10626 if (scf_pg_get_name(exp_pg, exp_str,
10614 10627 max_scf_name_len + 1) < 0)
10615 10628 scfdie();
10616 10629
10617 10630 if (strcmp(exp_str, scf_pg_general) == 0) {
10618 10631 export_inst_general(exp_pg, n, &elts);
10619 10632 continue;
10620 10633 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10621 10634 0) {
10622 10635 export_method_context(exp_pg, &elts);
10623 10636 continue;
10624 10637 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10625 10638 export_dependents(exp_pg, &elts);
10626 10639 continue;
10627 10640 }
10628 10641 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10629 10642 export_template(exp_pg, &elts, &template_elts);
10630 10643 continue;
10631 10644 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10632 10645 export_notify_params(exp_pg, &elts);
10633 10646 continue;
10634 10647 }
10635 10648
10636 10649 /* Ordinary pg. */
10637 10650 export_pg(exp_pg, &elts, flags);
10638 10651 }
10639 10652 if (ret == -1)
10640 10653 scfdie();
10641 10654
10642 10655 if (template_elts.common_name != NULL) {
10643 10656 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10644 10657 (void) xmlAddChild(elts.template, template_elts.common_name);
10645 10658 (void) xmlAddChild(elts.template, template_elts.description);
10646 10659 (void) xmlAddChild(elts.template, template_elts.documentation);
10647 10660 } else {
10648 10661 xmlFreeNode(template_elts.description);
10649 10662 xmlFreeNode(template_elts.documentation);
10650 10663 }
10651 10664
10652 10665 if (isdefault && elts.restarter == NULL &&
10653 10666 elts.dependencies == NULL && elts.method_context == NULL &&
10654 10667 elts.exec_methods == NULL && elts.notify_params == NULL &&
10655 10668 elts.property_groups == NULL && elts.template == NULL) {
10656 10669 xmlChar *eval;
10657 10670
10658 10671 /* This is a default instance */
10659 10672 eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10660 10673
10661 10674 xmlFreeNode(n);
10662 10675
10663 10676 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10664 10677 if (n == NULL)
10665 10678 uu_die(emsg_create_xml);
10666 10679
10667 10680 safe_setprop(n, enabled_attr, (char *)eval);
10668 10681 xmlFree(eval);
10669 10682
10670 10683 selts->create_default_instance = n;
10671 10684 } else {
10672 10685 /* Assemble the children in order. */
10673 10686 (void) xmlAddChild(n, elts.restarter);
10674 10687 (void) xmlAddChildList(n, elts.dependencies);
10675 10688 (void) xmlAddChildList(n, elts.dependents);
10676 10689 (void) xmlAddChild(n, elts.method_context);
10677 10690 (void) xmlAddChildList(n, elts.exec_methods);
10678 10691 (void) xmlAddChildList(n, elts.notify_params);
10679 10692 (void) xmlAddChildList(n, elts.property_groups);
10680 10693 (void) xmlAddChild(n, elts.template);
10681 10694
10682 10695 if (selts->instances == NULL)
10683 10696 selts->instances = n;
10684 10697 else
10685 10698 (void) xmlAddSibling(selts->instances, n);
10686 10699 }
10687 10700 }
10688 10701
10689 10702 /*
10690 10703 * Return a service element for the given service.
10691 10704 */
10692 10705 static xmlNodePtr
10693 10706 export_service(scf_service_t *svc, int flags)
10694 10707 {
10695 10708 xmlNodePtr snode;
10696 10709 struct entity_elts elts;
10697 10710 struct template_elts template_elts;
10698 10711 int ret;
10699 10712
10700 10713 snode = xmlNewNode(NULL, (xmlChar *)"service");
10701 10714 if (snode == NULL)
10702 10715 uu_die(emsg_create_xml);
10703 10716
10704 10717 /* Get & set name attribute */
10705 10718 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10706 10719 scfdie();
10707 10720 safe_setprop(snode, name_attr, exp_str);
10708 10721
10709 10722 safe_setprop(snode, type_attr, "service");
10710 10723 safe_setprop(snode, "version", "0");
10711 10724
10712 10725 /* Acquire child elements. */
10713 10726 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10714 10727 scfdie();
10715 10728
10716 10729 (void) memset(&elts, 0, sizeof (elts));
10717 10730 (void) memset(&template_elts, 0, sizeof (template_elts));
10718 10731
10719 10732 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10720 10733 uint32_t pgflags;
10721 10734
10722 10735 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10723 10736 scfdie();
10724 10737
10725 10738 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10726 10739 continue;
10727 10740
10728 10741 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10729 10742 scfdie();
10730 10743
10731 10744 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10732 10745 export_dependency(exp_pg, &elts);
10733 10746 continue;
10734 10747 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10735 10748 export_method(exp_pg, &elts);
10736 10749 continue;
10737 10750 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10738 10751 if (scf_pg_get_name(exp_pg, exp_str,
10739 10752 max_scf_name_len + 1) < 0)
10740 10753 scfdie();
10741 10754
10742 10755 if (strcmp(exp_str, scf_pg_general) == 0) {
10743 10756 export_svc_general(exp_pg, &elts);
10744 10757 continue;
10745 10758 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10746 10759 0) {
10747 10760 export_method_context(exp_pg, &elts);
10748 10761 continue;
10749 10762 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10750 10763 export_dependents(exp_pg, &elts);
10751 10764 continue;
10752 10765 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10753 10766 continue;
10754 10767 }
10755 10768 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10756 10769 export_template(exp_pg, &elts, &template_elts);
10757 10770 continue;
10758 10771 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10759 10772 export_notify_params(exp_pg, &elts);
10760 10773 continue;
10761 10774 }
10762 10775
10763 10776 export_pg(exp_pg, &elts, flags);
10764 10777 }
10765 10778 if (ret == -1)
10766 10779 scfdie();
10767 10780
10768 10781 if (template_elts.common_name != NULL) {
10769 10782 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10770 10783 (void) xmlAddChild(elts.template, template_elts.common_name);
10771 10784 (void) xmlAddChild(elts.template, template_elts.description);
10772 10785 (void) xmlAddChild(elts.template, template_elts.documentation);
10773 10786 } else {
10774 10787 xmlFreeNode(template_elts.description);
10775 10788 xmlFreeNode(template_elts.documentation);
10776 10789 }
10777 10790
10778 10791 /* Iterate instances */
10779 10792 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10780 10793 scfdie();
10781 10794
10782 10795 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10783 10796 export_instance(exp_inst, &elts, flags);
10784 10797 if (ret == -1)
10785 10798 scfdie();
10786 10799
10787 10800 /* Now add all of the accumulated elements in order. */
10788 10801 (void) xmlAddChild(snode, elts.create_default_instance);
10789 10802 (void) xmlAddChild(snode, elts.single_instance);
10790 10803 (void) xmlAddChild(snode, elts.restarter);
10791 10804 (void) xmlAddChildList(snode, elts.dependencies);
10792 10805 (void) xmlAddChildList(snode, elts.dependents);
10793 10806 (void) xmlAddChild(snode, elts.method_context);
10794 10807 (void) xmlAddChildList(snode, elts.exec_methods);
10795 10808 (void) xmlAddChildList(snode, elts.notify_params);
10796 10809 (void) xmlAddChildList(snode, elts.property_groups);
10797 10810 (void) xmlAddChildList(snode, elts.instances);
10798 10811 (void) xmlAddChild(snode, elts.stability);
10799 10812 (void) xmlAddChild(snode, elts.template);
10800 10813
10801 10814 return (snode);
10802 10815 }
10803 10816
10804 10817 static int
10805 10818 export_callback(void *data, scf_walkinfo_t *wip)
10806 10819 {
10807 10820 FILE *f;
10808 10821 xmlDocPtr doc;
10809 10822 xmlNodePtr sb;
10810 10823 int result;
10811 10824 struct export_args *argsp = (struct export_args *)data;
10812 10825
10813 10826 if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10814 10827 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10815 10828 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10816 10829 (exp_val = scf_value_create(g_hndl)) == NULL ||
10817 10830 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10818 10831 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10819 10832 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10820 10833 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10821 10834 scfdie();
10822 10835
10823 10836 exp_str_sz = max_scf_len + 1;
10824 10837 exp_str = safe_malloc(exp_str_sz);
10825 10838
10826 10839 if (argsp->filename != NULL) {
10827 10840 errno = 0;
10828 10841 f = fopen(argsp->filename, "wb");
10829 10842 if (f == NULL) {
10830 10843 if (errno == 0)
10831 10844 uu_die(gettext("Could not open \"%s\": no free "
10832 10845 "stdio streams.\n"), argsp->filename);
10833 10846 else
10834 10847 uu_die(gettext("Could not open \"%s\""),
10835 10848 argsp->filename);
10836 10849 }
10837 10850 } else
10838 10851 f = stdout;
10839 10852
10840 10853 doc = xmlNewDoc((xmlChar *)"1.0");
10841 10854 if (doc == NULL)
10842 10855 uu_die(gettext("Could not create XML document.\n"));
10843 10856
10844 10857 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10845 10858 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10846 10859 uu_die(emsg_create_xml);
10847 10860
10848 10861 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10849 10862 if (sb == NULL)
10850 10863 uu_die(emsg_create_xml);
10851 10864 safe_setprop(sb, type_attr, "manifest");
10852 10865 safe_setprop(sb, name_attr, "export");
10853 10866 (void) xmlAddSibling(doc->children, sb);
10854 10867
10855 10868 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10856 10869
10857 10870 result = write_service_bundle(doc, f);
10858 10871
10859 10872 free(exp_str);
10860 10873 scf_iter_destroy(exp_val_iter);
10861 10874 scf_iter_destroy(exp_prop_iter);
10862 10875 scf_iter_destroy(exp_pg_iter);
10863 10876 scf_iter_destroy(exp_inst_iter);
10864 10877 scf_value_destroy(exp_val);
10865 10878 scf_property_destroy(exp_prop);
10866 10879 scf_pg_destroy(exp_pg);
10867 10880 scf_instance_destroy(exp_inst);
10868 10881
10869 10882 xmlFreeDoc(doc);
10870 10883
10871 10884 if (f != stdout)
10872 10885 (void) fclose(f);
10873 10886
10874 10887 return (result);
10875 10888 }
10876 10889
10877 10890 /*
10878 10891 * Get the service named by fmri, build an XML tree which represents it, and
10879 10892 * dump it into filename (or stdout if filename is NULL).
10880 10893 */
10881 10894 int
10882 10895 lscf_service_export(char *fmri, const char *filename, int flags)
10883 10896 {
10884 10897 struct export_args args;
10885 10898 char *fmridup;
10886 10899 const char *scope, *svc, *inst;
10887 10900 size_t cblen = 3 * max_scf_name_len;
10888 10901 char *canonbuf = alloca(cblen);
10889 10902 int ret, err;
10890 10903
10891 10904 lscf_prep_hndl();
10892 10905
10893 10906 bzero(&args, sizeof (args));
10894 10907 args.filename = filename;
10895 10908 args.flags = flags;
10896 10909
10897 10910 /*
10898 10911 * If some poor user has passed an exact instance FMRI, of the sort
10899 10912 * one might cut and paste from svcs(1) or an error message, warn
10900 10913 * and chop off the instance instead of failing.
10901 10914 */
10902 10915 fmridup = alloca(strlen(fmri) + 1);
10903 10916 (void) strcpy(fmridup, fmri);
10904 10917 if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10905 10918 sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10906 10919 scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10907 10920 inst != NULL) {
10908 10921 (void) strlcpy(canonbuf, "svc:/", cblen);
10909 10922 if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10910 10923 (void) strlcat(canonbuf, "/", cblen);
10911 10924 (void) strlcat(canonbuf, scope, cblen);
10912 10925 }
10913 10926 (void) strlcat(canonbuf, svc, cblen);
10914 10927 fmri = canonbuf;
10915 10928
10916 10929 warn(gettext("Only services may be exported; ignoring "
10917 10930 "instance portion of argument.\n"));
10918 10931 }
10919 10932
10920 10933 err = 0;
10921 10934 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10922 10935 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10923 10936 &args, &err, semerr)) != 0) {
10924 10937 if (ret != -1)
10925 10938 semerr(gettext("Failed to walk instances: %s\n"),
10926 10939 scf_strerror(ret));
10927 10940 return (-1);
10928 10941 }
10929 10942
10930 10943 /*
10931 10944 * Error message has already been printed.
10932 10945 */
10933 10946 if (err != 0)
10934 10947 return (-1);
10935 10948
10936 10949 return (0);
10937 10950 }
10938 10951
10939 10952
10940 10953 /*
10941 10954 * Archive
10942 10955 */
10943 10956
10944 10957 static xmlNodePtr
10945 10958 make_archive(int flags)
10946 10959 {
10947 10960 xmlNodePtr sb;
10948 10961 scf_scope_t *scope;
10949 10962 scf_service_t *svc;
10950 10963 scf_iter_t *iter;
10951 10964 int r;
10952 10965
10953 10966 if ((scope = scf_scope_create(g_hndl)) == NULL ||
10954 10967 (svc = scf_service_create(g_hndl)) == NULL ||
10955 10968 (iter = scf_iter_create(g_hndl)) == NULL ||
10956 10969 (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10957 10970 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10958 10971 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10959 10972 (exp_val = scf_value_create(g_hndl)) == NULL ||
10960 10973 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10961 10974 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10962 10975 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10963 10976 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10964 10977 scfdie();
10965 10978
10966 10979 exp_str_sz = max_scf_len + 1;
10967 10980 exp_str = safe_malloc(exp_str_sz);
10968 10981
10969 10982 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10970 10983 if (sb == NULL)
10971 10984 uu_die(emsg_create_xml);
10972 10985 safe_setprop(sb, type_attr, "archive");
10973 10986 safe_setprop(sb, name_attr, "none");
10974 10987
10975 10988 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10976 10989 scfdie();
10977 10990 if (scf_iter_scope_services(iter, scope) != 0)
10978 10991 scfdie();
10979 10992
10980 10993 for (;;) {
10981 10994 r = scf_iter_next_service(iter, svc);
10982 10995 if (r == 0)
10983 10996 break;
10984 10997 if (r != 1)
10985 10998 scfdie();
10986 10999
10987 11000 if (scf_service_get_name(svc, exp_str,
10988 11001 max_scf_name_len + 1) < 0)
10989 11002 scfdie();
10990 11003
10991 11004 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
10992 11005 continue;
10993 11006
10994 11007 (void) xmlAddChild(sb, export_service(svc, flags));
10995 11008 }
10996 11009
10997 11010 free(exp_str);
10998 11011
10999 11012 scf_iter_destroy(exp_val_iter);
11000 11013 scf_iter_destroy(exp_prop_iter);
11001 11014 scf_iter_destroy(exp_pg_iter);
11002 11015 scf_iter_destroy(exp_inst_iter);
11003 11016 scf_value_destroy(exp_val);
11004 11017 scf_property_destroy(exp_prop);
11005 11018 scf_pg_destroy(exp_pg);
11006 11019 scf_instance_destroy(exp_inst);
11007 11020 scf_iter_destroy(iter);
11008 11021 scf_service_destroy(svc);
11009 11022 scf_scope_destroy(scope);
11010 11023
11011 11024 return (sb);
11012 11025 }
11013 11026
11014 11027 int
11015 11028 lscf_archive(const char *filename, int flags)
11016 11029 {
11017 11030 FILE *f;
11018 11031 xmlDocPtr doc;
11019 11032 int result;
11020 11033
11021 11034 lscf_prep_hndl();
11022 11035
11023 11036 if (filename != NULL) {
11024 11037 errno = 0;
11025 11038 f = fopen(filename, "wb");
11026 11039 if (f == NULL) {
11027 11040 if (errno == 0)
11028 11041 uu_die(gettext("Could not open \"%s\": no free "
11029 11042 "stdio streams.\n"), filename);
11030 11043 else
11031 11044 uu_die(gettext("Could not open \"%s\""),
11032 11045 filename);
11033 11046 }
11034 11047 } else
11035 11048 f = stdout;
11036 11049
11037 11050 doc = xmlNewDoc((xmlChar *)"1.0");
11038 11051 if (doc == NULL)
11039 11052 uu_die(gettext("Could not create XML document.\n"));
11040 11053
11041 11054 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11042 11055 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11043 11056 uu_die(emsg_create_xml);
11044 11057
11045 11058 (void) xmlAddSibling(doc->children, make_archive(flags));
11046 11059
11047 11060 result = write_service_bundle(doc, f);
11048 11061
11049 11062 xmlFreeDoc(doc);
11050 11063
11051 11064 if (f != stdout)
11052 11065 (void) fclose(f);
11053 11066
11054 11067 return (result);
11055 11068 }
11056 11069
11057 11070
11058 11071 /*
11059 11072 * "Extract" a profile.
11060 11073 */
11061 11074 int
11062 11075 lscf_profile_extract(const char *filename)
11063 11076 {
11064 11077 FILE *f;
11065 11078 xmlDocPtr doc;
11066 11079 xmlNodePtr sb, snode, inode;
11067 11080 scf_scope_t *scope;
11068 11081 scf_service_t *svc;
11069 11082 scf_instance_t *inst;
11070 11083 scf_propertygroup_t *pg;
11071 11084 scf_property_t *prop;
11072 11085 scf_value_t *val;
11073 11086 scf_iter_t *siter, *iiter;
11074 11087 int r, s;
11075 11088 char *namebuf;
11076 11089 uint8_t b;
11077 11090 int result;
11078 11091
11079 11092 lscf_prep_hndl();
11080 11093
11081 11094 if (filename != NULL) {
11082 11095 errno = 0;
11083 11096 f = fopen(filename, "wb");
11084 11097 if (f == NULL) {
11085 11098 if (errno == 0)
11086 11099 uu_die(gettext("Could not open \"%s\": no "
11087 11100 "free stdio streams.\n"), filename);
11088 11101 else
11089 11102 uu_die(gettext("Could not open \"%s\""),
11090 11103 filename);
11091 11104 }
11092 11105 } else
11093 11106 f = stdout;
11094 11107
11095 11108 doc = xmlNewDoc((xmlChar *)"1.0");
11096 11109 if (doc == NULL)
11097 11110 uu_die(gettext("Could not create XML document.\n"));
11098 11111
11099 11112 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11100 11113 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11101 11114 uu_die(emsg_create_xml);
11102 11115
11103 11116 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11104 11117 if (sb == NULL)
11105 11118 uu_die(emsg_create_xml);
11106 11119 safe_setprop(sb, type_attr, "profile");
11107 11120 safe_setprop(sb, name_attr, "extract");
11108 11121 (void) xmlAddSibling(doc->children, sb);
11109 11122
11110 11123 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11111 11124 (svc = scf_service_create(g_hndl)) == NULL ||
11112 11125 (inst = scf_instance_create(g_hndl)) == NULL ||
11113 11126 (pg = scf_pg_create(g_hndl)) == NULL ||
11114 11127 (prop = scf_property_create(g_hndl)) == NULL ||
11115 11128 (val = scf_value_create(g_hndl)) == NULL ||
11116 11129 (siter = scf_iter_create(g_hndl)) == NULL ||
11117 11130 (iiter = scf_iter_create(g_hndl)) == NULL)
11118 11131 scfdie();
11119 11132
11120 11133 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11121 11134 scfdie();
11122 11135
11123 11136 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11124 11137 scfdie();
11125 11138
11126 11139 namebuf = safe_malloc(max_scf_name_len + 1);
11127 11140
11128 11141 while ((r = scf_iter_next_service(siter, svc)) == 1) {
11129 11142 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11130 11143 scfdie();
11131 11144
11132 11145 snode = xmlNewNode(NULL, (xmlChar *)"service");
11133 11146 if (snode == NULL)
11134 11147 uu_die(emsg_create_xml);
11135 11148
11136 11149 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11137 11150 0)
11138 11151 scfdie();
11139 11152
11140 11153 safe_setprop(snode, name_attr, namebuf);
11141 11154
11142 11155 safe_setprop(snode, type_attr, "service");
11143 11156 safe_setprop(snode, "version", "0");
11144 11157
11145 11158 while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11146 11159 if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11147 11160 SCF_SUCCESS) {
11148 11161 if (scf_error() != SCF_ERROR_NOT_FOUND)
11149 11162 scfdie();
11150 11163
11151 11164 if (g_verbose) {
11152 11165 ssize_t len;
11153 11166 char *fmri;
11154 11167
11155 11168 len =
11156 11169 scf_instance_to_fmri(inst, NULL, 0);
11157 11170 if (len < 0)
11158 11171 scfdie();
11159 11172
11160 11173 fmri = safe_malloc(len + 1);
11161 11174
11162 11175 if (scf_instance_to_fmri(inst, fmri,
11163 11176 len + 1) < 0)
11164 11177 scfdie();
11165 11178
11166 11179 warn("Instance %s has no \"%s\" "
11167 11180 "property group.\n", fmri,
11168 11181 scf_pg_general);
11169 11182
11170 11183 free(fmri);
11171 11184 }
11172 11185
11173 11186 continue;
11174 11187 }
11175 11188
11176 11189 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11177 11190 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11178 11191 prop_get_val(prop, val) != 0)
11179 11192 continue;
11180 11193
11181 11194 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11182 11195 NULL);
11183 11196 if (inode == NULL)
11184 11197 uu_die(emsg_create_xml);
11185 11198
11186 11199 if (scf_instance_get_name(inst, namebuf,
11187 11200 max_scf_name_len + 1) < 0)
11188 11201 scfdie();
11189 11202
11190 11203 safe_setprop(inode, name_attr, namebuf);
11191 11204
11192 11205 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11193 11206 scfdie();
11194 11207
11195 11208 safe_setprop(inode, enabled_attr, b ? true : false);
11196 11209 }
11197 11210 if (s < 0)
11198 11211 scfdie();
11199 11212
11200 11213 if (snode->children != NULL)
11201 11214 (void) xmlAddChild(sb, snode);
11202 11215 else
11203 11216 xmlFreeNode(snode);
11204 11217 }
11205 11218 if (r < 0)
11206 11219 scfdie();
11207 11220
11208 11221 free(namebuf);
11209 11222
11210 11223 result = write_service_bundle(doc, f);
11211 11224
11212 11225 xmlFreeDoc(doc);
11213 11226
11214 11227 if (f != stdout)
11215 11228 (void) fclose(f);
11216 11229
11217 11230 return (result);
11218 11231 }
11219 11232
11220 11233
11221 11234 /*
11222 11235 * Entity manipulation commands
11223 11236 */
11224 11237
11225 11238 /*
11226 11239 * Entity selection. If no entity is selected, then the current scope is in
11227 11240 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected,
11228 11241 * only cur_inst is NULL, and when an instance is selected, none are NULL.
11229 11242 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11230 11243 * cur_inst will be non-NULL.
11231 11244 */
11232 11245
11233 11246 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11234 11247 static int
11235 11248 select_inst(const char *name)
11236 11249 {
11237 11250 scf_instance_t *inst;
11238 11251 scf_error_t err;
11239 11252
11240 11253 assert(cur_svc != NULL);
11241 11254
11242 11255 inst = scf_instance_create(g_hndl);
11243 11256 if (inst == NULL)
11244 11257 scfdie();
11245 11258
11246 11259 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11247 11260 cur_inst = inst;
11248 11261 return (0);
11249 11262 }
11250 11263
11251 11264 err = scf_error();
11252 11265 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11253 11266 scfdie();
11254 11267
11255 11268 scf_instance_destroy(inst);
11256 11269 return (1);
11257 11270 }
11258 11271
11259 11272 /* Returns as above. */
11260 11273 static int
11261 11274 select_svc(const char *name)
11262 11275 {
11263 11276 scf_service_t *svc;
11264 11277 scf_error_t err;
11265 11278
11266 11279 assert(cur_scope != NULL);
11267 11280
11268 11281 svc = scf_service_create(g_hndl);
11269 11282 if (svc == NULL)
11270 11283 scfdie();
11271 11284
11272 11285 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11273 11286 cur_svc = svc;
11274 11287 return (0);
11275 11288 }
11276 11289
11277 11290 err = scf_error();
11278 11291 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11279 11292 scfdie();
11280 11293
11281 11294 scf_service_destroy(svc);
11282 11295 return (1);
11283 11296 }
11284 11297
11285 11298 /* ARGSUSED */
11286 11299 static int
11287 11300 select_callback(void *unused, scf_walkinfo_t *wip)
11288 11301 {
11289 11302 scf_instance_t *inst;
11290 11303 scf_service_t *svc;
11291 11304 scf_scope_t *scope;
11292 11305
11293 11306 if (wip->inst != NULL) {
11294 11307 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11295 11308 (svc = scf_service_create(g_hndl)) == NULL ||
11296 11309 (inst = scf_instance_create(g_hndl)) == NULL)
11297 11310 scfdie();
11298 11311
11299 11312 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11300 11313 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11301 11314 scfdie();
11302 11315 } else {
11303 11316 assert(wip->svc != NULL);
11304 11317
11305 11318 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11306 11319 (svc = scf_service_create(g_hndl)) == NULL)
11307 11320 scfdie();
11308 11321
11309 11322 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11310 11323 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11311 11324 scfdie();
11312 11325
11313 11326 inst = NULL;
11314 11327 }
11315 11328
11316 11329 /* Clear out the current selection */
11317 11330 assert(cur_scope != NULL);
11318 11331 scf_scope_destroy(cur_scope);
11319 11332 scf_service_destroy(cur_svc);
11320 11333 scf_instance_destroy(cur_inst);
11321 11334
11322 11335 cur_scope = scope;
11323 11336 cur_svc = svc;
11324 11337 cur_inst = inst;
11325 11338
11326 11339 return (0);
11327 11340 }
11328 11341
11329 11342 static int
11330 11343 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11331 11344 {
11332 11345 char **fmri = fmri_p;
11333 11346
11334 11347 *fmri = strdup(wip->fmri);
11335 11348 if (*fmri == NULL)
11336 11349 uu_die(gettext("Out of memory.\n"));
11337 11350
11338 11351 return (0);
11339 11352 }
11340 11353
11341 11354 /*
11342 11355 * validate [fmri]
11343 11356 * Perform the validation of an FMRI instance.
11344 11357 */
11345 11358 void
11346 11359 lscf_validate_fmri(const char *fmri)
11347 11360 {
11348 11361 int ret = 0;
11349 11362 size_t inst_sz;
11350 11363 char *inst_fmri = NULL;
11351 11364 scf_tmpl_errors_t *errs = NULL;
11352 11365 char *snapbuf = NULL;
11353 11366
11354 11367 lscf_prep_hndl();
11355 11368
11356 11369 if (fmri == NULL) {
11357 11370 inst_sz = max_scf_fmri_len + 1;
11358 11371 inst_fmri = safe_malloc(inst_sz);
11359 11372
11360 11373 if (cur_snap != NULL) {
11361 11374 snapbuf = safe_malloc(max_scf_name_len + 1);
11362 11375 if (scf_snapshot_get_name(cur_snap, snapbuf,
11363 11376 max_scf_name_len + 1) < 0)
11364 11377 scfdie();
11365 11378 }
11366 11379 if (cur_inst == NULL) {
11367 11380 semerr(gettext("No instance selected\n"));
11368 11381 goto cleanup;
11369 11382 } else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11370 11383 inst_sz) >= inst_sz) {
11371 11384 /* sanity check. Should never get here */
11372 11385 uu_die(gettext("Unexpected error! file %s, line %d\n"),
11373 11386 __FILE__, __LINE__);
11374 11387 }
11375 11388 } else {
11376 11389 scf_error_t scf_err;
11377 11390 int err = 0;
11378 11391
11379 11392 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11380 11393 validate_callback, &inst_fmri, &err, semerr)) != 0) {
11381 11394 uu_warn("Failed to walk instances: %s\n",
11382 11395 scf_strerror(scf_err));
11383 11396 goto cleanup;
11384 11397 }
11385 11398 if (err != 0) {
11386 11399 /* error message displayed by scf_walk_fmri */
11387 11400 goto cleanup;
11388 11401 }
11389 11402 }
11390 11403
11391 11404 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11392 11405 SCF_TMPL_VALIDATE_FLAG_CURRENT);
11393 11406 if (ret == -1) {
11394 11407 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11395 11408 warn(gettext("Template data for %s is invalid. "
11396 11409 "Consider reverting to a previous snapshot or "
11397 11410 "restoring original configuration.\n"), inst_fmri);
11398 11411 } else {
11399 11412 uu_warn("%s: %s\n",
11400 11413 gettext("Error validating the instance"),
11401 11414 scf_strerror(scf_error()));
11402 11415 }
11403 11416 } else if (ret == 1 && errs != NULL) {
11404 11417 scf_tmpl_error_t *err = NULL;
11405 11418 char *msg;
11406 11419 size_t len = 256; /* initial error buffer size */
11407 11420 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11408 11421 SCF_TMPL_STRERROR_HUMAN : 0;
11409 11422
11410 11423 msg = safe_malloc(len);
11411 11424
11412 11425 while ((err = scf_tmpl_next_error(errs)) != NULL) {
11413 11426 int ret;
11414 11427
11415 11428 if ((ret = scf_tmpl_strerror(err, msg, len,
11416 11429 flag)) >= len) {
11417 11430 len = ret + 1;
11418 11431 msg = realloc(msg, len);
11419 11432 if (msg == NULL)
11420 11433 uu_die(gettext(
11421 11434 "Out of memory.\n"));
11422 11435 (void) scf_tmpl_strerror(err, msg, len,
11423 11436 flag);
11424 11437 }
11425 11438 (void) fprintf(stderr, "%s\n", msg);
11426 11439 }
11427 11440 if (msg != NULL)
11428 11441 free(msg);
11429 11442 }
11430 11443 if (errs != NULL)
11431 11444 scf_tmpl_errors_destroy(errs);
11432 11445
11433 11446 cleanup:
11434 11447 free(inst_fmri);
11435 11448 free(snapbuf);
11436 11449 }
11437 11450
11438 11451 static void
11439 11452 lscf_validate_file(const char *filename)
11440 11453 {
11441 11454 tmpl_errors_t *errs;
11442 11455
11443 11456 bundle_t *b = internal_bundle_new();
11444 11457 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11445 11458 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11446 11459 tmpl_errors_print(stderr, errs, "");
11447 11460 semerr(gettext("Validation failed.\n"));
11448 11461 }
11449 11462 tmpl_errors_destroy(errs);
11450 11463 }
11451 11464 (void) internal_bundle_free(b);
11452 11465 }
11453 11466
11454 11467 /*
11455 11468 * validate [fmri|file]
11456 11469 */
11457 11470 void
11458 11471 lscf_validate(const char *arg)
11459 11472 {
11460 11473 const char *str;
11461 11474
11462 11475 if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11463 11476 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11464 11477 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11465 11478 lscf_validate_file(str);
11466 11479 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11467 11480 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11468 11481 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11469 11482 lscf_validate_fmri(str);
11470 11483 } else if (access(arg, R_OK | F_OK) == 0) {
11471 11484 lscf_validate_file(arg);
11472 11485 } else {
11473 11486 lscf_validate_fmri(arg);
11474 11487 }
11475 11488 }
11476 11489
11477 11490 void
11478 11491 lscf_select(const char *fmri)
11479 11492 {
11480 11493 int ret, err;
11481 11494
11482 11495 lscf_prep_hndl();
11483 11496
11484 11497 if (cur_snap != NULL) {
11485 11498 struct snaplevel *elt;
11486 11499 char *buf;
11487 11500
11488 11501 /* Error unless name is that of the next level. */
11489 11502 elt = uu_list_next(cur_levels, cur_elt);
11490 11503 if (elt == NULL) {
11491 11504 semerr(gettext("No children.\n"));
11492 11505 return;
11493 11506 }
11494 11507
11495 11508 buf = safe_malloc(max_scf_name_len + 1);
11496 11509
11497 11510 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11498 11511 max_scf_name_len + 1) < 0)
11499 11512 scfdie();
11500 11513
11501 11514 if (strcmp(buf, fmri) != 0) {
11502 11515 semerr(gettext("No such child.\n"));
11503 11516 free(buf);
11504 11517 return;
11505 11518 }
11506 11519
11507 11520 free(buf);
11508 11521
11509 11522 cur_elt = elt;
11510 11523 cur_level = elt->sl;
11511 11524 return;
11512 11525 }
11513 11526
11514 11527 /*
11515 11528 * Special case for 'svc:', which takes the user to the scope level.
11516 11529 */
11517 11530 if (strcmp(fmri, "svc:") == 0) {
11518 11531 scf_instance_destroy(cur_inst);
11519 11532 scf_service_destroy(cur_svc);
11520 11533 cur_inst = NULL;
11521 11534 cur_svc = NULL;
11522 11535 return;
11523 11536 }
11524 11537
11525 11538 /*
11526 11539 * Special case for ':properties'. This appears as part of 'list' but
11527 11540 * can't be selected. Give a more helpful error message in this case.
11528 11541 */
11529 11542 if (strcmp(fmri, ":properties") == 0) {
11530 11543 semerr(gettext(":properties is not an entity. Try 'listprop' "
11531 11544 "to list properties.\n"));
11532 11545 return;
11533 11546 }
11534 11547
11535 11548 /*
11536 11549 * First try the argument as relative to the current selection.
11537 11550 */
11538 11551 if (cur_inst != NULL) {
11539 11552 /* EMPTY */;
11540 11553 } else if (cur_svc != NULL) {
11541 11554 if (select_inst(fmri) != 1)
11542 11555 return;
11543 11556 } else {
11544 11557 if (select_svc(fmri) != 1)
11545 11558 return;
11546 11559 }
11547 11560
11548 11561 err = 0;
11549 11562 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11550 11563 select_callback, NULL, &err, semerr)) != 0) {
11551 11564 semerr(gettext("Failed to walk instances: %s\n"),
11552 11565 scf_strerror(ret));
11553 11566 }
11554 11567 }
11555 11568
11556 11569 void
11557 11570 lscf_unselect(void)
11558 11571 {
11559 11572 lscf_prep_hndl();
11560 11573
11561 11574 if (cur_snap != NULL) {
11562 11575 struct snaplevel *elt;
11563 11576
11564 11577 elt = uu_list_prev(cur_levels, cur_elt);
11565 11578 if (elt == NULL) {
11566 11579 semerr(gettext("No parent levels.\n"));
11567 11580 } else {
11568 11581 cur_elt = elt;
11569 11582 cur_level = elt->sl;
11570 11583 }
11571 11584 } else if (cur_inst != NULL) {
11572 11585 scf_instance_destroy(cur_inst);
11573 11586 cur_inst = NULL;
11574 11587 } else if (cur_svc != NULL) {
11575 11588 scf_service_destroy(cur_svc);
11576 11589 cur_svc = NULL;
11577 11590 } else {
11578 11591 semerr(gettext("Cannot unselect at scope level.\n"));
11579 11592 }
11580 11593 }
11581 11594
11582 11595 /*
11583 11596 * Return the FMRI of the current selection, for the prompt.
11584 11597 */
11585 11598 void
11586 11599 lscf_get_selection_str(char *buf, size_t bufsz)
11587 11600 {
11588 11601 char *cp;
11589 11602 ssize_t fmrilen, szret;
11590 11603 boolean_t deleted = B_FALSE;
11591 11604
11592 11605 if (g_hndl == NULL) {
11593 11606 (void) strlcpy(buf, "svc:", bufsz);
11594 11607 return;
11595 11608 }
11596 11609
11597 11610 if (cur_level != NULL) {
11598 11611 assert(cur_snap != NULL);
11599 11612
11600 11613 /* [ snapshot ] FMRI [: instance ] */
11601 11614 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11602 11615 + 2 + max_scf_name_len + 1 + 1);
11603 11616
11604 11617 buf[0] = '[';
11605 11618
11606 11619 szret = scf_snapshot_get_name(cur_snap, buf + 1,
11607 11620 max_scf_name_len + 1);
11608 11621 if (szret < 0) {
11609 11622 if (scf_error() != SCF_ERROR_DELETED)
11610 11623 scfdie();
11611 11624
11612 11625 goto snap_deleted;
11613 11626 }
11614 11627
11615 11628 (void) strcat(buf, "]svc:/");
11616 11629
11617 11630 cp = strchr(buf, '\0');
11618 11631
11619 11632 szret = scf_snaplevel_get_service_name(cur_level, cp,
11620 11633 max_scf_name_len + 1);
11621 11634 if (szret < 0) {
11622 11635 if (scf_error() != SCF_ERROR_DELETED)
11623 11636 scfdie();
11624 11637
11625 11638 goto snap_deleted;
11626 11639 }
11627 11640
11628 11641 cp = strchr(cp, '\0');
11629 11642
11630 11643 if (snaplevel_is_instance(cur_level)) {
11631 11644 *cp++ = ':';
11632 11645
11633 11646 if (scf_snaplevel_get_instance_name(cur_level, cp,
11634 11647 max_scf_name_len + 1) < 0) {
11635 11648 if (scf_error() != SCF_ERROR_DELETED)
11636 11649 scfdie();
11637 11650
11638 11651 goto snap_deleted;
11639 11652 }
11640 11653 } else {
11641 11654 *cp++ = '[';
11642 11655 *cp++ = ':';
11643 11656
11644 11657 if (scf_instance_get_name(cur_inst, cp,
11645 11658 max_scf_name_len + 1) < 0) {
11646 11659 if (scf_error() != SCF_ERROR_DELETED)
11647 11660 scfdie();
11648 11661
11649 11662 goto snap_deleted;
11650 11663 }
11651 11664
11652 11665 (void) strcat(buf, "]");
11653 11666 }
11654 11667
11655 11668 return;
11656 11669
11657 11670 snap_deleted:
11658 11671 deleted = B_TRUE;
11659 11672 free(buf);
11660 11673 unselect_cursnap();
11661 11674 }
11662 11675
11663 11676 assert(cur_snap == NULL);
11664 11677
11665 11678 if (cur_inst != NULL) {
11666 11679 assert(cur_svc != NULL);
11667 11680 assert(cur_scope != NULL);
11668 11681
11669 11682 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11670 11683 if (fmrilen >= 0) {
11671 11684 assert(fmrilen < bufsz);
11672 11685 if (deleted)
11673 11686 warn(emsg_deleted);
11674 11687 return;
11675 11688 }
11676 11689
11677 11690 if (scf_error() != SCF_ERROR_DELETED)
11678 11691 scfdie();
11679 11692
11680 11693 deleted = B_TRUE;
11681 11694
11682 11695 scf_instance_destroy(cur_inst);
11683 11696 cur_inst = NULL;
11684 11697 }
11685 11698
11686 11699 if (cur_svc != NULL) {
11687 11700 assert(cur_scope != NULL);
11688 11701
11689 11702 szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11690 11703 if (szret >= 0) {
11691 11704 assert(szret < bufsz);
11692 11705 if (deleted)
11693 11706 warn(emsg_deleted);
11694 11707 return;
11695 11708 }
11696 11709
11697 11710 if (scf_error() != SCF_ERROR_DELETED)
11698 11711 scfdie();
11699 11712
11700 11713 deleted = B_TRUE;
11701 11714 scf_service_destroy(cur_svc);
11702 11715 cur_svc = NULL;
11703 11716 }
11704 11717
11705 11718 assert(cur_scope != NULL);
11706 11719 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11707 11720
11708 11721 if (fmrilen < 0)
11709 11722 scfdie();
11710 11723
11711 11724 assert(fmrilen < bufsz);
11712 11725 if (deleted)
11713 11726 warn(emsg_deleted);
11714 11727 }
11715 11728
11716 11729 /*
11717 11730 * Entity listing. Entities and colon namespaces (e.g., :properties and
11718 11731 * :statistics) are listed for the current selection.
11719 11732 */
11720 11733 void
11721 11734 lscf_list(const char *pattern)
11722 11735 {
11723 11736 scf_iter_t *iter;
11724 11737 char *buf;
11725 11738 int ret;
11726 11739
11727 11740 lscf_prep_hndl();
11728 11741
11729 11742 if (cur_level != NULL) {
11730 11743 struct snaplevel *elt;
11731 11744
11732 11745 (void) fputs(COLON_NAMESPACES, stdout);
11733 11746
11734 11747 elt = uu_list_next(cur_levels, cur_elt);
11735 11748 if (elt == NULL)
11736 11749 return;
11737 11750
11738 11751 /*
11739 11752 * For now, we know that the next level is an instance. But
11740 11753 * if we ever have multiple scopes, this could be complicated.
11741 11754 */
11742 11755 buf = safe_malloc(max_scf_name_len + 1);
11743 11756 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11744 11757 max_scf_name_len + 1) >= 0) {
11745 11758 (void) puts(buf);
11746 11759 } else {
11747 11760 if (scf_error() != SCF_ERROR_DELETED)
11748 11761 scfdie();
11749 11762 }
11750 11763
11751 11764 free(buf);
11752 11765
11753 11766 return;
11754 11767 }
11755 11768
11756 11769 if (cur_inst != NULL) {
11757 11770 (void) fputs(COLON_NAMESPACES, stdout);
11758 11771 return;
11759 11772 }
11760 11773
11761 11774 iter = scf_iter_create(g_hndl);
11762 11775 if (iter == NULL)
11763 11776 scfdie();
11764 11777
11765 11778 buf = safe_malloc(max_scf_name_len + 1);
11766 11779
11767 11780 if (cur_svc != NULL) {
11768 11781 /* List the instances in this service. */
11769 11782 scf_instance_t *inst;
11770 11783
11771 11784 inst = scf_instance_create(g_hndl);
11772 11785 if (inst == NULL)
11773 11786 scfdie();
11774 11787
11775 11788 if (scf_iter_service_instances(iter, cur_svc) == 0) {
11776 11789 safe_printf(COLON_NAMESPACES);
11777 11790
11778 11791 for (;;) {
11779 11792 ret = scf_iter_next_instance(iter, inst);
11780 11793 if (ret == 0)
11781 11794 break;
11782 11795 if (ret != 1) {
11783 11796 if (scf_error() != SCF_ERROR_DELETED)
11784 11797 scfdie();
11785 11798
11786 11799 break;
11787 11800 }
11788 11801
11789 11802 if (scf_instance_get_name(inst, buf,
11790 11803 max_scf_name_len + 1) >= 0) {
11791 11804 if (pattern == NULL ||
11792 11805 fnmatch(pattern, buf, 0) == 0)
11793 11806 (void) puts(buf);
11794 11807 } else {
11795 11808 if (scf_error() != SCF_ERROR_DELETED)
11796 11809 scfdie();
11797 11810 }
11798 11811 }
11799 11812 } else {
11800 11813 if (scf_error() != SCF_ERROR_DELETED)
11801 11814 scfdie();
11802 11815 }
11803 11816
11804 11817 scf_instance_destroy(inst);
11805 11818 } else {
11806 11819 /* List the services in this scope. */
11807 11820 scf_service_t *svc;
11808 11821
11809 11822 assert(cur_scope != NULL);
11810 11823
11811 11824 svc = scf_service_create(g_hndl);
11812 11825 if (svc == NULL)
11813 11826 scfdie();
11814 11827
11815 11828 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11816 11829 scfdie();
11817 11830
11818 11831 for (;;) {
11819 11832 ret = scf_iter_next_service(iter, svc);
11820 11833 if (ret == 0)
11821 11834 break;
11822 11835 if (ret != 1)
11823 11836 scfdie();
11824 11837
11825 11838 if (scf_service_get_name(svc, buf,
11826 11839 max_scf_name_len + 1) >= 0) {
11827 11840 if (pattern == NULL ||
11828 11841 fnmatch(pattern, buf, 0) == 0)
11829 11842 safe_printf("%s\n", buf);
11830 11843 } else {
11831 11844 if (scf_error() != SCF_ERROR_DELETED)
11832 11845 scfdie();
11833 11846 }
11834 11847 }
11835 11848
11836 11849 scf_service_destroy(svc);
11837 11850 }
11838 11851
11839 11852 free(buf);
11840 11853 scf_iter_destroy(iter);
11841 11854 }
11842 11855
11843 11856 /*
11844 11857 * Entity addition. Creates an empty entity in the current selection.
11845 11858 */
11846 11859 void
11847 11860 lscf_add(const char *name)
11848 11861 {
11849 11862 lscf_prep_hndl();
11850 11863
11851 11864 if (cur_snap != NULL) {
11852 11865 semerr(emsg_cant_modify_snapshots);
11853 11866 } else if (cur_inst != NULL) {
11854 11867 semerr(gettext("Cannot add entities to an instance.\n"));
11855 11868 } else if (cur_svc != NULL) {
11856 11869
11857 11870 if (scf_service_add_instance(cur_svc, name, NULL) !=
11858 11871 SCF_SUCCESS) {
11859 11872 switch (scf_error()) {
11860 11873 case SCF_ERROR_INVALID_ARGUMENT:
11861 11874 semerr(gettext("Invalid name.\n"));
11862 11875 break;
11863 11876
11864 11877 case SCF_ERROR_EXISTS:
11865 11878 semerr(gettext("Instance already exists.\n"));
11866 11879 break;
11867 11880
11868 11881 case SCF_ERROR_PERMISSION_DENIED:
11869 11882 semerr(emsg_permission_denied);
11870 11883 break;
11871 11884
11872 11885 default:
11873 11886 scfdie();
11874 11887 }
11875 11888 }
11876 11889 } else {
11877 11890 assert(cur_scope != NULL);
11878 11891
11879 11892 if (scf_scope_add_service(cur_scope, name, NULL) !=
11880 11893 SCF_SUCCESS) {
11881 11894 switch (scf_error()) {
11882 11895 case SCF_ERROR_INVALID_ARGUMENT:
11883 11896 semerr(gettext("Invalid name.\n"));
11884 11897 break;
11885 11898
11886 11899 case SCF_ERROR_EXISTS:
11887 11900 semerr(gettext("Service already exists.\n"));
11888 11901 break;
11889 11902
11890 11903 case SCF_ERROR_PERMISSION_DENIED:
11891 11904 semerr(emsg_permission_denied);
11892 11905 break;
11893 11906
11894 11907 case SCF_ERROR_BACKEND_READONLY:
11895 11908 semerr(emsg_read_only);
11896 11909 break;
11897 11910
11898 11911 default:
11899 11912 scfdie();
11900 11913 }
11901 11914 }
11902 11915 }
11903 11916 }
11904 11917
11905 11918 /* return 1 if the entity has no persistent pgs, else return 0 */
11906 11919 static int
11907 11920 entity_has_no_pgs(void *ent, int isservice)
11908 11921 {
11909 11922 scf_iter_t *iter = NULL;
11910 11923 scf_propertygroup_t *pg = NULL;
11911 11924 uint32_t flags;
11912 11925 int err;
11913 11926 int ret = 1;
11914 11927
11915 11928 if ((iter = scf_iter_create(g_hndl)) == NULL ||
11916 11929 (pg = scf_pg_create(g_hndl)) == NULL)
11917 11930 scfdie();
11918 11931
11919 11932 if (isservice) {
11920 11933 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11921 11934 scfdie();
11922 11935 } else {
11923 11936 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11924 11937 scfdie();
11925 11938 }
11926 11939
11927 11940 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11928 11941 if (scf_pg_get_flags(pg, &flags) != 0)
11929 11942 scfdie();
11930 11943
11931 11944 /* skip nonpersistent pgs */
11932 11945 if (flags & SCF_PG_FLAG_NONPERSISTENT)
11933 11946 continue;
11934 11947
11935 11948 ret = 0;
11936 11949 break;
11937 11950 }
11938 11951
11939 11952 if (err == -1)
11940 11953 scfdie();
11941 11954
11942 11955 scf_pg_destroy(pg);
11943 11956 scf_iter_destroy(iter);
11944 11957
11945 11958 return (ret);
11946 11959 }
11947 11960
11948 11961 /* return 1 if the service has no instances, else return 0 */
11949 11962 static int
11950 11963 svc_has_no_insts(scf_service_t *svc)
11951 11964 {
11952 11965 scf_instance_t *inst;
11953 11966 scf_iter_t *iter;
11954 11967 int r;
11955 11968 int ret = 1;
11956 11969
11957 11970 if ((inst = scf_instance_create(g_hndl)) == NULL ||
11958 11971 (iter = scf_iter_create(g_hndl)) == NULL)
11959 11972 scfdie();
11960 11973
11961 11974 if (scf_iter_service_instances(iter, svc) != 0)
11962 11975 scfdie();
11963 11976
11964 11977 r = scf_iter_next_instance(iter, inst);
11965 11978 if (r == 1) {
11966 11979 ret = 0;
11967 11980 } else if (r == 0) {
11968 11981 ret = 1;
11969 11982 } else if (r == -1) {
11970 11983 scfdie();
11971 11984 } else {
11972 11985 bad_error("scf_iter_next_instance", r);
11973 11986 }
11974 11987
11975 11988 scf_iter_destroy(iter);
11976 11989 scf_instance_destroy(inst);
11977 11990
11978 11991 return (ret);
11979 11992 }
11980 11993
11981 11994 /*
11982 11995 * Entity deletion.
11983 11996 */
11984 11997
11985 11998 /*
11986 11999 * Delete the property group <fmri>/:properties/<name>. Returns
11987 12000 * SCF_ERROR_NONE on success (or if the entity is not found),
11988 12001 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
11989 12002 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
11990 12003 * denied.
11991 12004 */
11992 12005 static scf_error_t
11993 12006 delete_dependency_pg(const char *fmri, const char *name)
11994 12007 {
11995 12008 void *entity = NULL;
11996 12009 int isservice;
11997 12010 scf_propertygroup_t *pg = NULL;
11998 12011 scf_error_t result;
11999 12012 char *pgty;
12000 12013 scf_service_t *svc = NULL;
12001 12014 scf_instance_t *inst = NULL;
12002 12015 scf_iter_t *iter = NULL;
12003 12016 char *name_buf = NULL;
12004 12017
12005 12018 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12006 12019 switch (result) {
12007 12020 case SCF_ERROR_NONE:
12008 12021 break;
12009 12022
12010 12023 case SCF_ERROR_NO_MEMORY:
12011 12024 uu_die(gettext("Out of memory.\n"));
12012 12025 /* NOTREACHED */
12013 12026
12014 12027 case SCF_ERROR_INVALID_ARGUMENT:
12015 12028 case SCF_ERROR_CONSTRAINT_VIOLATED:
12016 12029 return (SCF_ERROR_INVALID_ARGUMENT);
12017 12030
12018 12031 case SCF_ERROR_NOT_FOUND:
12019 12032 result = SCF_ERROR_NONE;
12020 12033 goto out;
12021 12034
12022 12035 default:
12023 12036 bad_error("fmri_to_entity", result);
12024 12037 }
12025 12038
12026 12039 pg = scf_pg_create(g_hndl);
12027 12040 if (pg == NULL)
12028 12041 scfdie();
12029 12042
12030 12043 if (entity_get_pg(entity, isservice, name, pg) != 0) {
12031 12044 if (scf_error() != SCF_ERROR_NOT_FOUND)
12032 12045 scfdie();
12033 12046
12034 12047 result = SCF_ERROR_NONE;
12035 12048 goto out;
12036 12049 }
12037 12050
12038 12051 pgty = safe_malloc(max_scf_pg_type_len + 1);
12039 12052
12040 12053 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12041 12054 scfdie();
12042 12055
12043 12056 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12044 12057 result = SCF_ERROR_TYPE_MISMATCH;
12045 12058 free(pgty);
12046 12059 goto out;
12047 12060 }
12048 12061
12049 12062 free(pgty);
12050 12063
12051 12064 if (scf_pg_delete(pg) != 0) {
12052 12065 result = scf_error();
12053 12066 if (result != SCF_ERROR_PERMISSION_DENIED)
12054 12067 scfdie();
12055 12068 goto out;
12056 12069 }
12057 12070
12058 12071 /*
12059 12072 * We have to handle the case where we've just deleted the last
12060 12073 * property group of a "dummy" entity (instance or service).
12061 12074 * A "dummy" entity is an entity only present to hold an
12062 12075 * external dependency.
12063 12076 * So, in the case we deleted the last property group then we
12064 12077 * can also delete the entity. If the entity is an instance then
12065 12078 * we must verify if this was the last instance for the service
12066 12079 * and if it is, we can also delete the service if it doesn't
12067 12080 * have any property group either.
12068 12081 */
12069 12082
12070 12083 result = SCF_ERROR_NONE;
12071 12084
12072 12085 if (isservice) {
12073 12086 svc = (scf_service_t *)entity;
12074 12087
12075 12088 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12076 12089 (iter = scf_iter_create(g_hndl)) == NULL)
12077 12090 scfdie();
12078 12091
12079 12092 name_buf = safe_malloc(max_scf_name_len + 1);
12080 12093 } else {
12081 12094 inst = (scf_instance_t *)entity;
12082 12095 }
12083 12096
12084 12097 /*
12085 12098 * If the entity is an instance and we've just deleted its last
12086 12099 * property group then we should delete it.
12087 12100 */
12088 12101 if (!isservice && entity_has_no_pgs(entity, isservice)) {
12089 12102 /* find the service before deleting the inst. - needed later */
12090 12103 if ((svc = scf_service_create(g_hndl)) == NULL)
12091 12104 scfdie();
12092 12105
12093 12106 if (scf_instance_get_parent(inst, svc) != 0)
12094 12107 scfdie();
12095 12108
12096 12109 /* delete the instance */
12097 12110 if (scf_instance_delete(inst) != 0) {
12098 12111 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12099 12112 scfdie();
12100 12113
12101 12114 result = SCF_ERROR_PERMISSION_DENIED;
12102 12115 goto out;
12103 12116 }
12104 12117 /* no need to refresh the instance */
12105 12118 inst = NULL;
12106 12119 }
12107 12120
12108 12121 /*
12109 12122 * If the service has no more instances and pgs or we just deleted the
12110 12123 * last instance and the service doesn't have anymore propery groups
12111 12124 * then the service should be deleted.
12112 12125 */
12113 12126 if (svc != NULL &&
12114 12127 svc_has_no_insts(svc) &&
12115 12128 entity_has_no_pgs((void *)svc, 1)) {
12116 12129 if (scf_service_delete(svc) == 0) {
12117 12130 if (isservice) {
12118 12131 /* no need to refresh the service */
12119 12132 svc = NULL;
12120 12133 }
12121 12134
12122 12135 goto out;
12123 12136 }
12124 12137
12125 12138 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12126 12139 scfdie();
12127 12140
12128 12141 result = SCF_ERROR_PERMISSION_DENIED;
12129 12142 }
12130 12143
12131 12144 /* if the entity has not been deleted, refresh it */
12132 12145 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12133 12146 (void) refresh_entity(isservice, entity, fmri, inst, iter,
12134 12147 name_buf);
12135 12148 }
12136 12149
12137 12150 out:
12138 12151 if (isservice && (inst != NULL && iter != NULL)) {
12139 12152 free(name_buf);
12140 12153 scf_iter_destroy(iter);
12141 12154 scf_instance_destroy(inst);
12142 12155 }
12143 12156
12144 12157 if (!isservice && svc != NULL) {
12145 12158 scf_service_destroy(svc);
12146 12159 }
12147 12160
12148 12161 scf_pg_destroy(pg);
12149 12162 if (entity != NULL)
12150 12163 entity_destroy(entity, isservice);
12151 12164
12152 12165 return (result);
12153 12166 }
12154 12167
12155 12168 static int
12156 12169 delete_dependents(scf_propertygroup_t *pg)
12157 12170 {
12158 12171 char *pgty, *name, *fmri;
12159 12172 scf_property_t *prop;
12160 12173 scf_value_t *val;
12161 12174 scf_iter_t *iter;
12162 12175 int r;
12163 12176 scf_error_t err;
12164 12177
12165 12178 /* Verify that the pg has the correct type. */
12166 12179 pgty = safe_malloc(max_scf_pg_type_len + 1);
12167 12180 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12168 12181 scfdie();
12169 12182
12170 12183 if (strcmp(pgty, scf_group_framework) != 0) {
12171 12184 if (g_verbose) {
12172 12185 fmri = safe_malloc(max_scf_fmri_len + 1);
12173 12186 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12174 12187 scfdie();
12175 12188
12176 12189 warn(gettext("Property group %s is not of expected "
12177 12190 "type %s.\n"), fmri, scf_group_framework);
12178 12191
12179 12192 free(fmri);
12180 12193 }
12181 12194
12182 12195 free(pgty);
12183 12196 return (-1);
12184 12197 }
12185 12198
12186 12199 free(pgty);
12187 12200
12188 12201 /* map delete_dependency_pg onto the properties. */
12189 12202 if ((prop = scf_property_create(g_hndl)) == NULL ||
12190 12203 (val = scf_value_create(g_hndl)) == NULL ||
12191 12204 (iter = scf_iter_create(g_hndl)) == NULL)
12192 12205 scfdie();
12193 12206
12194 12207 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12195 12208 scfdie();
12196 12209
12197 12210 name = safe_malloc(max_scf_name_len + 1);
12198 12211 fmri = safe_malloc(max_scf_fmri_len + 2);
12199 12212
12200 12213 while ((r = scf_iter_next_property(iter, prop)) == 1) {
12201 12214 scf_type_t ty;
12202 12215
12203 12216 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12204 12217 scfdie();
12205 12218
12206 12219 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12207 12220 scfdie();
12208 12221
12209 12222 if ((ty != SCF_TYPE_ASTRING &&
12210 12223 prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12211 12224 prop_get_val(prop, val) != 0)
12212 12225 continue;
12213 12226
12214 12227 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12215 12228 scfdie();
12216 12229
12217 12230 err = delete_dependency_pg(fmri, name);
12218 12231 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12219 12232 if (scf_property_to_fmri(prop, fmri,
12220 12233 max_scf_fmri_len + 2) < 0)
12221 12234 scfdie();
12222 12235
12223 12236 warn(gettext("Value of %s is not a valid FMRI.\n"),
12224 12237 fmri);
12225 12238 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12226 12239 warn(gettext("Property group \"%s\" of entity \"%s\" "
12227 12240 "does not have dependency type.\n"), name, fmri);
12228 12241 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12229 12242 warn(gettext("Could not delete property group \"%s\" "
12230 12243 "of entity \"%s\" (permission denied).\n"), name,
12231 12244 fmri);
12232 12245 }
12233 12246 }
12234 12247 if (r == -1)
12235 12248 scfdie();
12236 12249
12237 12250 scf_value_destroy(val);
12238 12251 scf_property_destroy(prop);
12239 12252
12240 12253 return (0);
12241 12254 }
12242 12255
12243 12256 /*
12244 12257 * Returns 1 if the instance may be running, and 0 otherwise.
12245 12258 */
12246 12259 static int
12247 12260 inst_is_running(scf_instance_t *inst)
12248 12261 {
12249 12262 scf_propertygroup_t *pg;
12250 12263 scf_property_t *prop;
12251 12264 scf_value_t *val;
12252 12265 char buf[MAX_SCF_STATE_STRING_SZ];
12253 12266 int ret = 0;
12254 12267 ssize_t szret;
12255 12268
12256 12269 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12257 12270 (prop = scf_property_create(g_hndl)) == NULL ||
12258 12271 (val = scf_value_create(g_hndl)) == NULL)
12259 12272 scfdie();
12260 12273
12261 12274 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12262 12275 if (scf_error() != SCF_ERROR_NOT_FOUND)
12263 12276 scfdie();
12264 12277 goto out;
12265 12278 }
12266 12279
12267 12280 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12268 12281 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12269 12282 prop_get_val(prop, val) != 0)
12270 12283 goto out;
12271 12284
12272 12285 szret = scf_value_get_astring(val, buf, sizeof (buf));
12273 12286 assert(szret >= 0);
12274 12287
12275 12288 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12276 12289 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12277 12290
12278 12291 out:
12279 12292 scf_value_destroy(val);
12280 12293 scf_property_destroy(prop);
12281 12294 scf_pg_destroy(pg);
12282 12295 return (ret);
12283 12296 }
12284 12297
12285 12298 static uint8_t
12286 12299 pg_is_external_dependency(scf_propertygroup_t *pg)
12287 12300 {
12288 12301 char *type;
12289 12302 scf_value_t *val;
12290 12303 scf_property_t *prop;
12291 12304 uint8_t b = B_FALSE;
12292 12305
12293 12306 type = safe_malloc(max_scf_pg_type_len + 1);
12294 12307
12295 12308 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12296 12309 scfdie();
12297 12310
12298 12311 if ((prop = scf_property_create(g_hndl)) == NULL ||
12299 12312 (val = scf_value_create(g_hndl)) == NULL)
12300 12313 scfdie();
12301 12314
12302 12315 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12303 12316 if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12304 12317 if (scf_property_get_value(prop, val) != 0)
12305 12318 scfdie();
12306 12319 if (scf_value_get_boolean(val, &b) != 0)
12307 12320 scfdie();
12308 12321 }
12309 12322 }
12310 12323
12311 12324 free(type);
12312 12325 (void) scf_value_destroy(val);
12313 12326 (void) scf_property_destroy(prop);
12314 12327
12315 12328 return (b);
12316 12329 }
12317 12330
12318 12331 #define DELETE_FAILURE -1
12319 12332 #define DELETE_SUCCESS_NOEXTDEPS 0
12320 12333 #define DELETE_SUCCESS_EXTDEPS 1
12321 12334
12322 12335 /*
12323 12336 * lscf_instance_delete() deletes an instance. Before calling
12324 12337 * scf_instance_delete(), though, we make sure the instance isn't
12325 12338 * running and delete dependencies in other entities which the instance
12326 12339 * declared as "dependents". If there are dependencies which were
12327 12340 * created for other entities, then instead of deleting the instance we
12328 12341 * make it "empty" by deleting all other property groups and all
12329 12342 * snapshots.
12330 12343 *
12331 12344 * lscf_instance_delete() verifies that there is no external dependency pgs
12332 12345 * before suppressing the instance. If there is, then we must not remove them
12333 12346 * now in case the instance is re-created otherwise the dependencies would be
12334 12347 * lost. The external dependency pgs will be removed if the dependencies are
12335 12348 * removed.
12336 12349 *
12337 12350 * Returns:
12338 12351 * DELETE_FAILURE on failure
12339 12352 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12340 12353 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12341 12354 */
12342 12355 static int
12343 12356 lscf_instance_delete(scf_instance_t *inst, int force)
12344 12357 {
12345 12358 scf_propertygroup_t *pg;
12346 12359 scf_snapshot_t *snap;
12347 12360 scf_iter_t *iter;
12348 12361 int err;
12349 12362 int external = 0;
12350 12363
12351 12364 /* If we're not forcing and the instance is running, refuse. */
12352 12365 if (!force && inst_is_running(inst)) {
12353 12366 char *fmri;
12354 12367
12355 12368 fmri = safe_malloc(max_scf_fmri_len + 1);
12356 12369
12357 12370 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12358 12371 scfdie();
12359 12372
12360 12373 semerr(gettext("Instance %s may be running. "
12361 12374 "Use delete -f if it is not.\n"), fmri);
12362 12375
12363 12376 free(fmri);
12364 12377 return (DELETE_FAILURE);
12365 12378 }
12366 12379
12367 12380 pg = scf_pg_create(g_hndl);
12368 12381 if (pg == NULL)
12369 12382 scfdie();
12370 12383
12371 12384 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12372 12385 (void) delete_dependents(pg);
12373 12386 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12374 12387 scfdie();
12375 12388
12376 12389 scf_pg_destroy(pg);
12377 12390
12378 12391 /*
12379 12392 * If the instance has some external dependencies then we must
12380 12393 * keep them in case the instance is reimported otherwise the
12381 12394 * dependencies would be lost on reimport.
12382 12395 */
12383 12396 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12384 12397 (pg = scf_pg_create(g_hndl)) == NULL)
12385 12398 scfdie();
12386 12399
12387 12400 if (scf_iter_instance_pgs(iter, inst) < 0)
12388 12401 scfdie();
12389 12402
12390 12403 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12391 12404 if (pg_is_external_dependency(pg)) {
12392 12405 external = 1;
12393 12406 continue;
12394 12407 }
12395 12408
12396 12409 if (scf_pg_delete(pg) != 0) {
12397 12410 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12398 12411 scfdie();
12399 12412 else {
12400 12413 semerr(emsg_permission_denied);
12401 12414
12402 12415 (void) scf_iter_destroy(iter);
12403 12416 (void) scf_pg_destroy(pg);
12404 12417 return (DELETE_FAILURE);
12405 12418 }
12406 12419 }
12407 12420 }
12408 12421
12409 12422 if (err == -1)
12410 12423 scfdie();
12411 12424
12412 12425 (void) scf_iter_destroy(iter);
12413 12426 (void) scf_pg_destroy(pg);
12414 12427
12415 12428 if (external) {
12416 12429 /*
12417 12430 * All the pgs have been deleted for the instance except
12418 12431 * the ones holding the external dependencies.
12419 12432 * For the job to be complete, we must also delete the
12420 12433 * snapshots associated with the instance.
12421 12434 */
12422 12435 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12423 12436 NULL)
12424 12437 scfdie();
12425 12438 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12426 12439 scfdie();
12427 12440
12428 12441 if (scf_iter_instance_snapshots(iter, inst) == -1)
12429 12442 scfdie();
12430 12443
12431 12444 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12432 12445 if (_scf_snapshot_delete(snap) != 0) {
12433 12446 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12434 12447 scfdie();
12435 12448
12436 12449 semerr(emsg_permission_denied);
12437 12450
12438 12451 (void) scf_iter_destroy(iter);
12439 12452 (void) scf_snapshot_destroy(snap);
12440 12453 return (DELETE_FAILURE);
12441 12454 }
12442 12455 }
12443 12456
12444 12457 if (err == -1)
12445 12458 scfdie();
12446 12459
12447 12460 (void) scf_iter_destroy(iter);
12448 12461 (void) scf_snapshot_destroy(snap);
12449 12462 return (DELETE_SUCCESS_EXTDEPS);
12450 12463 }
12451 12464
12452 12465 if (scf_instance_delete(inst) != 0) {
12453 12466 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12454 12467 scfdie();
12455 12468
12456 12469 semerr(emsg_permission_denied);
12457 12470
12458 12471 return (DELETE_FAILURE);
12459 12472 }
12460 12473
12461 12474 return (DELETE_SUCCESS_NOEXTDEPS);
12462 12475 }
12463 12476
12464 12477 /*
12465 12478 * lscf_service_delete() deletes a service. Before calling
12466 12479 * scf_service_delete(), though, we call lscf_instance_delete() for
12467 12480 * each of the instances and delete dependencies in other entities
12468 12481 * which were created as "dependents" of this service. If there are
12469 12482 * dependencies which were created for other entities, then we delete
12470 12483 * all other property groups in the service and leave it as "empty".
12471 12484 *
12472 12485 * lscf_service_delete() verifies that there is no external dependency
12473 12486 * pgs at the instance & service level before suppressing the service.
12474 12487 * If there is, then we must not remove them now in case the service
12475 12488 * is re-imported otherwise the dependencies would be lost. The external
12476 12489 * dependency pgs will be removed if the dependencies are removed.
12477 12490 *
12478 12491 * Returns:
12479 12492 * DELETE_FAILURE on failure
12480 12493 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12481 12494 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12482 12495 */
12483 12496 static int
12484 12497 lscf_service_delete(scf_service_t *svc, int force)
12485 12498 {
12486 12499 int r;
12487 12500 scf_instance_t *inst;
12488 12501 scf_propertygroup_t *pg;
12489 12502 scf_iter_t *iter;
12490 12503 int ret;
12491 12504 int external = 0;
12492 12505
12493 12506 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12494 12507 (pg = scf_pg_create(g_hndl)) == NULL ||
12495 12508 (iter = scf_iter_create(g_hndl)) == NULL)
12496 12509 scfdie();
12497 12510
12498 12511 if (scf_iter_service_instances(iter, svc) != 0)
12499 12512 scfdie();
12500 12513
12501 12514 for (r = scf_iter_next_instance(iter, inst);
12502 12515 r == 1;
12503 12516 r = scf_iter_next_instance(iter, inst)) {
12504 12517
12505 12518 ret = lscf_instance_delete(inst, force);
12506 12519 if (ret == DELETE_FAILURE) {
12507 12520 scf_iter_destroy(iter);
12508 12521 scf_pg_destroy(pg);
12509 12522 scf_instance_destroy(inst);
12510 12523 return (DELETE_FAILURE);
12511 12524 }
12512 12525
12513 12526 /*
12514 12527 * Record the fact that there is some external dependencies
12515 12528 * at the instance level.
12516 12529 */
12517 12530 if (ret == DELETE_SUCCESS_EXTDEPS)
12518 12531 external |= 1;
12519 12532 }
12520 12533
12521 12534 if (r != 0)
12522 12535 scfdie();
12523 12536
12524 12537 /* Delete dependency property groups in dependent services. */
12525 12538 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12526 12539 (void) delete_dependents(pg);
12527 12540 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12528 12541 scfdie();
12529 12542
12530 12543 scf_iter_destroy(iter);
12531 12544 scf_pg_destroy(pg);
12532 12545 scf_instance_destroy(inst);
12533 12546
12534 12547 /*
12535 12548 * If the service has some external dependencies then we don't
12536 12549 * want to remove them in case the service is re-imported.
12537 12550 */
12538 12551 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12539 12552 (iter = scf_iter_create(g_hndl)) == NULL)
12540 12553 scfdie();
12541 12554
12542 12555 if (scf_iter_service_pgs(iter, svc) < 0)
12543 12556 scfdie();
12544 12557
12545 12558 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12546 12559 if (pg_is_external_dependency(pg)) {
12547 12560 external |= 2;
12548 12561 continue;
12549 12562 }
12550 12563
12551 12564 if (scf_pg_delete(pg) != 0) {
12552 12565 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12553 12566 scfdie();
12554 12567 else {
12555 12568 semerr(emsg_permission_denied);
12556 12569
12557 12570 (void) scf_iter_destroy(iter);
12558 12571 (void) scf_pg_destroy(pg);
12559 12572 return (DELETE_FAILURE);
12560 12573 }
12561 12574 }
12562 12575 }
12563 12576
12564 12577 if (r == -1)
12565 12578 scfdie();
12566 12579
12567 12580 (void) scf_iter_destroy(iter);
12568 12581 (void) scf_pg_destroy(pg);
12569 12582
12570 12583 if (external != 0)
12571 12584 return (DELETE_SUCCESS_EXTDEPS);
12572 12585
12573 12586 if (scf_service_delete(svc) == 0)
12574 12587 return (DELETE_SUCCESS_NOEXTDEPS);
12575 12588
12576 12589 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12577 12590 scfdie();
12578 12591
12579 12592 semerr(emsg_permission_denied);
12580 12593 return (DELETE_FAILURE);
12581 12594 }
12582 12595
12583 12596 static int
12584 12597 delete_callback(void *data, scf_walkinfo_t *wip)
12585 12598 {
12586 12599 int force = (int)data;
12587 12600
12588 12601 if (wip->inst != NULL)
12589 12602 (void) lscf_instance_delete(wip->inst, force);
12590 12603 else
12591 12604 (void) lscf_service_delete(wip->svc, force);
12592 12605
12593 12606 return (0);
12594 12607 }
12595 12608
12596 12609 void
12597 12610 lscf_delete(const char *fmri, int force)
12598 12611 {
12599 12612 scf_service_t *svc;
12600 12613 scf_instance_t *inst;
12601 12614 int ret;
12602 12615
12603 12616 lscf_prep_hndl();
12604 12617
12605 12618 if (cur_snap != NULL) {
12606 12619 if (!snaplevel_is_instance(cur_level)) {
12607 12620 char *buf;
12608 12621
12609 12622 buf = safe_malloc(max_scf_name_len + 1);
12610 12623 if (scf_instance_get_name(cur_inst, buf,
12611 12624 max_scf_name_len + 1) >= 0) {
12612 12625 if (strcmp(buf, fmri) == 0) {
12613 12626 semerr(emsg_cant_modify_snapshots);
12614 12627 free(buf);
12615 12628 return;
12616 12629 }
12617 12630 } else if (scf_error() != SCF_ERROR_DELETED) {
12618 12631 scfdie();
12619 12632 }
12620 12633 free(buf);
12621 12634 }
12622 12635 } else if (cur_inst != NULL) {
12623 12636 /* EMPTY */;
12624 12637 } else if (cur_svc != NULL) {
12625 12638 inst = scf_instance_create(g_hndl);
12626 12639 if (inst == NULL)
12627 12640 scfdie();
12628 12641
12629 12642 if (scf_service_get_instance(cur_svc, fmri, inst) ==
12630 12643 SCF_SUCCESS) {
12631 12644 (void) lscf_instance_delete(inst, force);
12632 12645 scf_instance_destroy(inst);
12633 12646 return;
12634 12647 }
12635 12648
12636 12649 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12637 12650 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12638 12651 scfdie();
12639 12652
12640 12653 scf_instance_destroy(inst);
12641 12654 } else {
12642 12655 assert(cur_scope != NULL);
12643 12656
12644 12657 svc = scf_service_create(g_hndl);
12645 12658 if (svc == NULL)
12646 12659 scfdie();
12647 12660
12648 12661 if (scf_scope_get_service(cur_scope, fmri, svc) ==
12649 12662 SCF_SUCCESS) {
12650 12663 (void) lscf_service_delete(svc, force);
12651 12664 scf_service_destroy(svc);
12652 12665 return;
12653 12666 }
12654 12667
12655 12668 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12656 12669 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12657 12670 scfdie();
12658 12671
12659 12672 scf_service_destroy(svc);
12660 12673 }
12661 12674
12662 12675 /*
12663 12676 * Match FMRI to entity.
12664 12677 */
12665 12678 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12666 12679 delete_callback, (void *)force, NULL, semerr)) != 0) {
12667 12680 semerr(gettext("Failed to walk instances: %s\n"),
12668 12681 scf_strerror(ret));
12669 12682 }
12670 12683 }
12671 12684
12672 12685
12673 12686
12674 12687 /*
12675 12688 * :properties commands. These all end with "pg" or "prop" and generally
12676 12689 * operate on the currently selected entity.
12677 12690 */
12678 12691
12679 12692 /*
12680 12693 * Property listing. List the property groups, properties, their types and
12681 12694 * their values for the currently selected entity.
12682 12695 */
12683 12696 static void
12684 12697 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12685 12698 {
12686 12699 char *buf;
12687 12700 uint32_t flags;
12688 12701
12689 12702 buf = safe_malloc(max_scf_pg_type_len + 1);
12690 12703
12691 12704 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12692 12705 scfdie();
12693 12706
12694 12707 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12695 12708 scfdie();
12696 12709
12697 12710 safe_printf("%-*s %s", namewidth, name, buf);
12698 12711
12699 12712 if (flags & SCF_PG_FLAG_NONPERSISTENT)
12700 12713 safe_printf("\tNONPERSISTENT");
12701 12714
12702 12715 safe_printf("\n");
12703 12716
12704 12717 free(buf);
12705 12718 }
12706 12719
12707 12720 static boolean_t
12708 12721 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12709 12722 {
12710 12723 if (scf_property_get_value(prop, val) == 0) {
12711 12724 return (B_FALSE);
12712 12725 } else {
12713 12726 switch (scf_error()) {
12714 12727 case SCF_ERROR_NOT_FOUND:
12715 12728 return (B_FALSE);
12716 12729 case SCF_ERROR_PERMISSION_DENIED:
12717 12730 case SCF_ERROR_CONSTRAINT_VIOLATED:
12718 12731 return (B_TRUE);
12719 12732 default:
12720 12733 scfdie();
12721 12734 /*NOTREACHED*/
12722 12735 }
12723 12736 }
12724 12737 }
12725 12738
12726 12739 static void
12727 12740 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12728 12741 {
12729 12742 scf_iter_t *iter;
12730 12743 scf_value_t *val;
12731 12744 const char *type;
12732 12745 int multiple_strings = 0;
12733 12746 int ret;
12734 12747
12735 12748 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12736 12749 (val = scf_value_create(g_hndl)) == NULL)
12737 12750 scfdie();
12738 12751
12739 12752 type = prop_to_typestr(prop);
12740 12753 assert(type != NULL);
12741 12754
12742 12755 safe_printf("%-*s %-7s ", len, name, type);
12743 12756
12744 12757 if (prop_has_multiple_values(prop, val) &&
12745 12758 (scf_value_type(val) == SCF_TYPE_ASTRING ||
12746 12759 scf_value_type(val) == SCF_TYPE_USTRING))
12747 12760 multiple_strings = 1;
12748 12761
12749 12762 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12750 12763 scfdie();
12751 12764
12752 12765 while ((ret = scf_iter_next_value(iter, val)) == 1) {
12753 12766 char *buf;
12754 12767 ssize_t vlen, szret;
12755 12768
12756 12769 vlen = scf_value_get_as_string(val, NULL, 0);
12757 12770 if (vlen < 0)
12758 12771 scfdie();
12759 12772
12760 12773 buf = safe_malloc(vlen + 1);
12761 12774
12762 12775 szret = scf_value_get_as_string(val, buf, vlen + 1);
12763 12776 if (szret < 0)
12764 12777 scfdie();
12765 12778 assert(szret <= vlen);
12766 12779
12767 12780 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12768 12781 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12769 12782 safe_printf(" \"");
12770 12783 (void) quote_and_print(buf, stdout, 0);
12771 12784 (void) putchar('"');
12772 12785 if (ferror(stdout)) {
12773 12786 (void) putchar('\n');
12774 12787 uu_die(gettext("Error writing to stdout.\n"));
12775 12788 }
12776 12789 } else {
12777 12790 safe_printf(" %s", buf);
12778 12791 }
12779 12792
12780 12793 free(buf);
12781 12794 }
12782 12795 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12783 12796 scfdie();
12784 12797
12785 12798 if (putchar('\n') != '\n')
12786 12799 uu_die(gettext("Could not output newline"));
12787 12800 }
12788 12801
12789 12802 /*
12790 12803 * Outputs template property group info for the describe subcommand.
12791 12804 * If 'templates' == 2, verbose output is printed in the format expected
12792 12805 * for describe -v, which includes all templates fields. If pg is
12793 12806 * not NULL, we're describing the template data, not an existing property
12794 12807 * group, and formatting should be appropriate for describe -t.
12795 12808 */
12796 12809 static void
12797 12810 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12798 12811 {
12799 12812 char *buf;
12800 12813 uint8_t required;
12801 12814 scf_property_t *stability_prop;
12802 12815 scf_value_t *stability_val;
12803 12816
12804 12817 if (templates == 0)
12805 12818 return;
12806 12819
12807 12820 if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12808 12821 (stability_val = scf_value_create(g_hndl)) == NULL)
12809 12822 scfdie();
12810 12823
12811 12824 if (templates == 2 && pg != NULL) {
12812 12825 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12813 12826 stability_prop) == 0) {
12814 12827 if (prop_check_type(stability_prop,
12815 12828 SCF_TYPE_ASTRING) == 0 &&
12816 12829 prop_get_val(stability_prop, stability_val) == 0) {
12817 12830 char *stability;
12818 12831
12819 12832 stability = safe_malloc(max_scf_value_len + 1);
12820 12833
12821 12834 if (scf_value_get_astring(stability_val,
12822 12835 stability, max_scf_value_len + 1) == -1 &&
12823 12836 scf_error() != SCF_ERROR_NOT_FOUND)
12824 12837 scfdie();
12825 12838
12826 12839 safe_printf("%s%s: %s\n", TMPL_INDENT,
12827 12840 gettext("stability"), stability);
12828 12841
12829 12842 free(stability);
12830 12843 }
12831 12844 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12832 12845 scfdie();
12833 12846 }
12834 12847
12835 12848 scf_property_destroy(stability_prop);
12836 12849 scf_value_destroy(stability_val);
12837 12850
12838 12851 if (pgt == NULL)
12839 12852 return;
12840 12853
12841 12854 if (pg == NULL || templates == 2) {
12842 12855 /* print type info only if scf_tmpl_pg_name succeeds */
12843 12856 if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12844 12857 if (pg != NULL)
12845 12858 safe_printf("%s", TMPL_INDENT);
12846 12859 safe_printf("%s: ", gettext("name"));
12847 12860 safe_printf("%s\n", buf);
12848 12861 free(buf);
12849 12862 }
12850 12863
12851 12864 /* print type info only if scf_tmpl_pg_type succeeds */
12852 12865 if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12853 12866 if (pg != NULL)
12854 12867 safe_printf("%s", TMPL_INDENT);
12855 12868 safe_printf("%s: ", gettext("type"));
12856 12869 safe_printf("%s\n", buf);
12857 12870 free(buf);
12858 12871 }
12859 12872 }
12860 12873
12861 12874 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12862 12875 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12863 12876 required ? "true" : "false");
12864 12877
12865 12878 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12866 12879 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12867 12880 buf);
12868 12881 free(buf);
12869 12882 }
12870 12883
12871 12884 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12872 12885 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12873 12886 buf);
12874 12887 free(buf);
12875 12888 }
12876 12889
12877 12890 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12878 12891 if (templates == 2)
12879 12892 safe_printf("%s%s: %s\n", TMPL_INDENT,
12880 12893 gettext("description"), buf);
12881 12894 else
12882 12895 safe_printf("%s%s\n", TMPL_INDENT, buf);
12883 12896 free(buf);
12884 12897 }
12885 12898
12886 12899 }
12887 12900
12888 12901 /*
12889 12902 * With as_value set to true, indent as appropriate for the value level.
12890 12903 * If false, indent to appropriate level for inclusion in constraint
12891 12904 * or choice printout.
12892 12905 */
12893 12906 static void
12894 12907 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12895 12908 int as_value)
12896 12909 {
12897 12910 char *buf;
12898 12911
12899 12912 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12900 12913 if (as_value == 0)
12901 12914 safe_printf("%s", TMPL_CHOICE_INDENT);
12902 12915 else
12903 12916 safe_printf("%s", TMPL_INDENT);
12904 12917 safe_printf("%s: %s\n", gettext("value common name"), buf);
12905 12918 free(buf);
12906 12919 }
12907 12920
12908 12921 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12909 12922 if (as_value == 0)
12910 12923 safe_printf("%s", TMPL_CHOICE_INDENT);
12911 12924 else
12912 12925 safe_printf("%s", TMPL_INDENT);
12913 12926 safe_printf("%s: %s\n", gettext("value description"), buf);
12914 12927 free(buf);
12915 12928 }
12916 12929 }
12917 12930
12918 12931 static void
12919 12932 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12920 12933 {
12921 12934 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12922 12935 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12923 12936 safe_printf("%s\n", val_buf);
12924 12937
12925 12938 print_template_value_details(prt, val_buf, 1);
12926 12939 }
12927 12940
12928 12941 static void
12929 12942 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12930 12943 {
12931 12944 int i, printed = 0;
12932 12945 scf_values_t values;
12933 12946 scf_count_ranges_t c_ranges;
12934 12947 scf_int_ranges_t i_ranges;
12935 12948
12936 12949 printed = 0;
12937 12950 i = 0;
12938 12951 if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12939 12952 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12940 12953 gettext("value constraints"));
12941 12954 printed++;
12942 12955 for (i = 0; i < values.value_count; ++i) {
12943 12956 safe_printf("%s%s: %s\n", TMPL_INDENT,
12944 12957 gettext("value name"), values.values_as_strings[i]);
12945 12958 if (verbose == 1)
12946 12959 print_template_value_details(prt,
12947 12960 values.values_as_strings[i], 0);
12948 12961 }
12949 12962
12950 12963 scf_values_destroy(&values);
12951 12964 }
12952 12965
12953 12966 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12954 12967 if (printed++ == 0)
12955 12968 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12956 12969 gettext("value constraints"));
12957 12970 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12958 12971 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12959 12972 gettext("range"), c_ranges.scr_min[i],
12960 12973 c_ranges.scr_max[i]);
12961 12974 }
12962 12975 scf_count_ranges_destroy(&c_ranges);
12963 12976 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12964 12977 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12965 12978 if (printed++ == 0)
12966 12979 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12967 12980 gettext("value constraints"));
12968 12981 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12969 12982 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12970 12983 gettext("range"), i_ranges.sir_min[i],
12971 12984 i_ranges.sir_max[i]);
12972 12985 }
12973 12986 scf_int_ranges_destroy(&i_ranges);
12974 12987 }
12975 12988 }
12976 12989
12977 12990 static void
12978 12991 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12979 12992 {
12980 12993 int i = 0, printed = 0;
12981 12994 scf_values_t values;
12982 12995 scf_count_ranges_t c_ranges;
12983 12996 scf_int_ranges_t i_ranges;
12984 12997
12985 12998 printed = 0;
12986 12999 if (scf_tmpl_value_name_choices(prt, &values) == 0) {
12987 13000 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12988 13001 gettext("value constraints"));
12989 13002 printed++;
12990 13003 for (i = 0; i < values.value_count; i++) {
12991 13004 safe_printf("%s%s: %s\n", TMPL_INDENT,
12992 13005 gettext("value name"), values.values_as_strings[i]);
12993 13006 if (verbose == 1)
12994 13007 print_template_value_details(prt,
12995 13008 values.values_as_strings[i], 0);
12996 13009 }
12997 13010
12998 13011 scf_values_destroy(&values);
12999 13012 }
13000 13013
13001 13014 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13002 13015 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13003 13016 if (printed++ == 0)
13004 13017 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13005 13018 gettext("value choices"));
13006 13019 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13007 13020 gettext("range"), c_ranges.scr_min[i],
13008 13021 c_ranges.scr_max[i]);
13009 13022 }
13010 13023 scf_count_ranges_destroy(&c_ranges);
13011 13024 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13012 13025 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13013 13026 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13014 13027 if (printed++ == 0)
13015 13028 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13016 13029 gettext("value choices"));
13017 13030 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13018 13031 gettext("range"), i_ranges.sir_min[i],
13019 13032 i_ranges.sir_max[i]);
13020 13033 }
13021 13034 scf_int_ranges_destroy(&i_ranges);
13022 13035 }
13023 13036 }
13024 13037
13025 13038 static void
13026 13039 list_values_by_template(scf_prop_tmpl_t *prt)
13027 13040 {
13028 13041 print_template_constraints(prt, 1);
13029 13042 print_template_choices(prt, 1);
13030 13043 }
13031 13044
13032 13045 static void
13033 13046 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13034 13047 {
13035 13048 char *val_buf;
13036 13049 scf_iter_t *iter;
13037 13050 scf_value_t *val;
13038 13051 int ret;
13039 13052
13040 13053 if ((iter = scf_iter_create(g_hndl)) == NULL ||
13041 13054 (val = scf_value_create(g_hndl)) == NULL)
13042 13055 scfdie();
13043 13056
13044 13057 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13045 13058 scfdie();
13046 13059
13047 13060 val_buf = safe_malloc(max_scf_value_len + 1);
13048 13061
13049 13062 while ((ret = scf_iter_next_value(iter, val)) == 1) {
13050 13063 if (scf_value_get_as_string(val, val_buf,
13051 13064 max_scf_value_len + 1) < 0)
13052 13065 scfdie();
13053 13066
13054 13067 print_template_value(prt, val_buf);
13055 13068 }
13056 13069 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13057 13070 scfdie();
13058 13071 free(val_buf);
13059 13072
13060 13073 print_template_constraints(prt, 0);
13061 13074 print_template_choices(prt, 0);
13062 13075
13063 13076 }
13064 13077
13065 13078 /*
13066 13079 * Outputs property info for the describe subcommand
13067 13080 * Verbose output if templates == 2, -v option of svccfg describe
13068 13081 * Displays template data if prop is not NULL, -t option of svccfg describe
13069 13082 */
13070 13083 static void
13071 13084 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13072 13085 {
13073 13086 char *buf;
13074 13087 uint8_t u_buf;
13075 13088 int i;
13076 13089 uint64_t min, max;
13077 13090 scf_values_t values;
13078 13091
13079 13092 if (prt == NULL || templates == 0)
13080 13093 return;
13081 13094
13082 13095 if (prop == NULL) {
13083 13096 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13084 13097 if (scf_tmpl_prop_name(prt, &buf) > 0) {
13085 13098 safe_printf("%s\n", buf);
13086 13099 free(buf);
13087 13100 } else
13088 13101 safe_printf("(%s)\n", gettext("any"));
13089 13102 }
13090 13103
13091 13104 if (prop == NULL || templates == 2) {
13092 13105 if (prop != NULL)
13093 13106 safe_printf("%s", TMPL_INDENT);
13094 13107 else
13095 13108 safe_printf("%s", TMPL_VALUE_INDENT);
13096 13109 safe_printf("%s: ", gettext("type"));
13097 13110 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13098 13111 safe_printf("%s\n", buf);
13099 13112 free(buf);
13100 13113 } else
13101 13114 safe_printf("(%s)\n", gettext("any"));
13102 13115 }
13103 13116
13104 13117 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13105 13118 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13106 13119 u_buf ? "true" : "false");
13107 13120
13108 13121 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13109 13122 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13110 13123 buf);
13111 13124 free(buf);
13112 13125 }
13113 13126
13114 13127 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13115 13128 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13116 13129 buf);
13117 13130 free(buf);
13118 13131 }
13119 13132
13120 13133 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13121 13134 safe_printf("%s%s\n", TMPL_INDENT, buf);
13122 13135 free(buf);
13123 13136 }
13124 13137
13125 13138 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13126 13139 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13127 13140 scf_tmpl_visibility_to_string(u_buf));
13128 13141
13129 13142 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13130 13143 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13131 13144 gettext("minimum number of values"), min);
13132 13145 if (max == ULLONG_MAX) {
13133 13146 safe_printf("%s%s: %s\n", TMPL_INDENT,
13134 13147 gettext("maximum number of values"),
13135 13148 gettext("unlimited"));
13136 13149 } else {
13137 13150 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13138 13151 gettext("maximum number of values"), max);
13139 13152 }
13140 13153 }
13141 13154
13142 13155 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13143 13156 for (i = 0; i < values.value_count; i++) {
13144 13157 if (i == 0) {
13145 13158 safe_printf("%s%s:", TMPL_INDENT,
13146 13159 gettext("internal separators"));
13147 13160 }
13148 13161 safe_printf(" \"%s\"", values.values_as_strings[i]);
13149 13162 }
13150 13163 safe_printf("\n");
13151 13164 }
13152 13165
13153 13166 if (templates != 2)
13154 13167 return;
13155 13168
13156 13169 if (prop != NULL)
13157 13170 list_values_tmpl(prt, prop);
13158 13171 else
13159 13172 list_values_by_template(prt);
13160 13173 }
13161 13174
13162 13175 static char *
13163 13176 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13164 13177 {
13165 13178 char *rv;
13166 13179
13167 13180 rv = _scf_read_single_astring_from_pg(pg, prop_name);
13168 13181 if (rv == NULL) {
13169 13182 switch (scf_error()) {
13170 13183 case SCF_ERROR_NOT_FOUND:
13171 13184 break;
13172 13185 default:
13173 13186 scfdie();
13174 13187 }
13175 13188 }
13176 13189 return (rv);
13177 13190 }
13178 13191
13179 13192 static void
13180 13193 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13181 13194 {
13182 13195 size_t doc_len;
13183 13196 size_t man_len;
13184 13197 char *pg_name;
13185 13198 char *text = NULL;
13186 13199 int rv;
13187 13200
13188 13201 doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13189 13202 man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13190 13203 pg_name = safe_malloc(max_scf_name_len + 1);
13191 13204 while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13192 13205 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13193 13206 scfdie();
13194 13207 }
13195 13208 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13196 13209 /* Display doc_link and and uri */
13197 13210 safe_printf("%s%s:\n", TMPL_INDENT,
13198 13211 gettext("doc_link"));
13199 13212 text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13200 13213 if (text != NULL) {
13201 13214 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13202 13215 TMPL_INDENT, gettext("name"), text);
13203 13216 uu_free(text);
13204 13217 }
13205 13218 text = read_astring(pg, SCF_PROPERTY_TM_URI);
13206 13219 if (text != NULL) {
13207 13220 safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13208 13221 gettext("uri"), text);
13209 13222 uu_free(text);
13210 13223 }
13211 13224 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13212 13225 man_len) == 0) {
13213 13226 /* Display manpage title, section and path */
13214 13227 safe_printf("%s%s:\n", TMPL_INDENT,
13215 13228 gettext("manpage"));
13216 13229 text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13217 13230 if (text != NULL) {
13218 13231 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13219 13232 TMPL_INDENT, gettext("title"), text);
13220 13233 uu_free(text);
13221 13234 }
13222 13235 text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13223 13236 if (text != NULL) {
13224 13237 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13225 13238 TMPL_INDENT, gettext("section"), text);
13226 13239 uu_free(text);
13227 13240 }
13228 13241 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13229 13242 if (text != NULL) {
13230 13243 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13231 13244 TMPL_INDENT, gettext("manpath"), text);
13232 13245 uu_free(text);
13233 13246 }
13234 13247 }
13235 13248 }
13236 13249 if (rv == -1)
13237 13250 scfdie();
13238 13251
13239 13252 done:
13240 13253 free(pg_name);
13241 13254 }
13242 13255
13243 13256 static void
13244 13257 list_entity_tmpl(int templates)
13245 13258 {
13246 13259 char *common_name = NULL;
13247 13260 char *description = NULL;
13248 13261 char *locale = NULL;
13249 13262 scf_iter_t *iter;
13250 13263 scf_propertygroup_t *pg;
13251 13264 scf_property_t *prop;
13252 13265 int r;
13253 13266 scf_value_t *val;
13254 13267
13255 13268 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13256 13269 (prop = scf_property_create(g_hndl)) == NULL ||
13257 13270 (val = scf_value_create(g_hndl)) == NULL ||
13258 13271 (iter = scf_iter_create(g_hndl)) == NULL)
13259 13272 scfdie();
13260 13273
13261 13274 locale = setlocale(LC_MESSAGES, NULL);
13262 13275
13263 13276 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13264 13277 common_name = safe_malloc(max_scf_value_len + 1);
13265 13278
13266 13279 /* Try both the current locale and the "C" locale. */
13267 13280 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13268 13281 (scf_error() == SCF_ERROR_NOT_FOUND &&
13269 13282 scf_pg_get_property(pg, "C", prop) == 0)) {
13270 13283 if (prop_get_val(prop, val) == 0 &&
13271 13284 scf_value_get_ustring(val, common_name,
13272 13285 max_scf_value_len + 1) != -1) {
13273 13286 safe_printf("%s%s: %s\n", TMPL_INDENT,
13274 13287 gettext("common name"), common_name);
13275 13288 }
13276 13289 }
13277 13290 }
13278 13291
13279 13292 /*
13280 13293 * Do description, manpages, and doc links if templates == 2.
13281 13294 */
13282 13295 if (templates == 2) {
13283 13296 /* Get the description. */
13284 13297 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13285 13298 description = safe_malloc(max_scf_value_len + 1);
13286 13299
13287 13300 /* Try both the current locale and the "C" locale. */
13288 13301 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13289 13302 (scf_error() == SCF_ERROR_NOT_FOUND &&
13290 13303 scf_pg_get_property(pg, "C", prop) == 0)) {
13291 13304 if (prop_get_val(prop, val) == 0 &&
13292 13305 scf_value_get_ustring(val, description,
13293 13306 max_scf_value_len + 1) != -1) {
13294 13307 safe_printf("%s%s: %s\n", TMPL_INDENT,
13295 13308 gettext("description"),
13296 13309 description);
13297 13310 }
13298 13311 }
13299 13312 }
13300 13313
13301 13314 /* Process doc_link & manpage elements. */
13302 13315 if (cur_level != NULL) {
13303 13316 r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13304 13317 SCF_GROUP_TEMPLATE);
13305 13318 } else if (cur_inst != NULL) {
13306 13319 r = scf_iter_instance_pgs_typed(iter, cur_inst,
13307 13320 SCF_GROUP_TEMPLATE);
13308 13321 } else {
13309 13322 r = scf_iter_service_pgs_typed(iter, cur_svc,
13310 13323 SCF_GROUP_TEMPLATE);
13311 13324 }
13312 13325 if (r == 0) {
13313 13326 display_documentation(iter, pg);
13314 13327 }
13315 13328 }
13316 13329
13317 13330 free(common_name);
13318 13331 free(description);
13319 13332 scf_pg_destroy(pg);
13320 13333 scf_property_destroy(prop);
13321 13334 scf_value_destroy(val);
13322 13335 scf_iter_destroy(iter);
13323 13336 }
13324 13337
13325 13338 static void
13326 13339 listtmpl(const char *pattern, int templates)
13327 13340 {
13328 13341 scf_pg_tmpl_t *pgt;
13329 13342 scf_prop_tmpl_t *prt;
13330 13343 char *snapbuf = NULL;
13331 13344 char *fmribuf;
13332 13345 char *pg_name = NULL, *prop_name = NULL;
13333 13346 ssize_t prop_name_size;
13334 13347 char *qual_prop_name;
13335 13348 char *search_name;
13336 13349 int listed = 0;
13337 13350
13338 13351 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13339 13352 (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13340 13353 scfdie();
13341 13354
13342 13355 fmribuf = safe_malloc(max_scf_name_len + 1);
13343 13356 qual_prop_name = safe_malloc(max_scf_name_len + 1);
13344 13357
13345 13358 if (cur_snap != NULL) {
13346 13359 snapbuf = safe_malloc(max_scf_name_len + 1);
13347 13360 if (scf_snapshot_get_name(cur_snap, snapbuf,
13348 13361 max_scf_name_len + 1) < 0)
13349 13362 scfdie();
13350 13363 }
13351 13364
13352 13365 if (cur_inst != NULL) {
13353 13366 if (scf_instance_to_fmri(cur_inst, fmribuf,
13354 13367 max_scf_name_len + 1) < 0)
13355 13368 scfdie();
13356 13369 } else if (cur_svc != NULL) {
13357 13370 if (scf_service_to_fmri(cur_svc, fmribuf,
13358 13371 max_scf_name_len + 1) < 0)
13359 13372 scfdie();
13360 13373 } else
13361 13374 abort();
13362 13375
13363 13376 /* If pattern is specified, we want to list only those items. */
13364 13377 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13365 13378 listed = 0;
13366 13379 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13367 13380 fnmatch(pattern, pg_name, 0) == 0)) {
13368 13381 list_pg_tmpl(pgt, NULL, templates);
13369 13382 listed++;
13370 13383 }
13371 13384
13372 13385 scf_tmpl_prop_reset(prt);
13373 13386
13374 13387 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13375 13388 search_name = NULL;
13376 13389 prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13377 13390 if ((prop_name_size > 0) && (pg_name != NULL)) {
13378 13391 if (snprintf(qual_prop_name,
13379 13392 max_scf_name_len + 1, "%s/%s",
13380 13393 pg_name, prop_name) >=
13381 13394 max_scf_name_len + 1) {
13382 13395 prop_name_size = -1;
13383 13396 } else {
13384 13397 search_name = qual_prop_name;
13385 13398 }
13386 13399 }
13387 13400 if (listed > 0 || pattern == NULL ||
13388 13401 (prop_name_size > 0 &&
13389 13402 fnmatch(pattern, search_name,
13390 13403 FNM_PATHNAME) == 0))
13391 13404 list_prop_tmpl(prt, NULL, templates);
13392 13405 if (prop_name != NULL) {
13393 13406 free(prop_name);
13394 13407 prop_name = NULL;
13395 13408 }
13396 13409 }
13397 13410 if (pg_name != NULL) {
13398 13411 free(pg_name);
13399 13412 pg_name = NULL;
13400 13413 }
13401 13414 }
13402 13415
13403 13416 scf_tmpl_prop_destroy(prt);
13404 13417 scf_tmpl_pg_destroy(pgt);
13405 13418 free(snapbuf);
13406 13419 free(fmribuf);
13407 13420 free(qual_prop_name);
13408 13421 }
13409 13422
13410 13423 static void
13411 13424 listprop(const char *pattern, int only_pgs, int templates)
13412 13425 {
13413 13426 scf_propertygroup_t *pg;
13414 13427 scf_property_t *prop;
13415 13428 scf_iter_t *iter, *piter;
13416 13429 char *pgnbuf, *prnbuf, *ppnbuf;
13417 13430 scf_pg_tmpl_t *pgt, *pgtp;
13418 13431 scf_prop_tmpl_t *prt;
13419 13432
13420 13433 void **objects;
13421 13434 char **names;
13422 13435 void **tmpls;
13423 13436 int allocd, i;
13424 13437
13425 13438 int ret;
13426 13439 ssize_t pgnlen, prnlen, szret;
13427 13440 size_t max_len = 0;
13428 13441
13429 13442 if (cur_svc == NULL && cur_inst == NULL) {
13430 13443 semerr(emsg_entity_not_selected);
13431 13444 return;
13432 13445 }
13433 13446
13434 13447 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13435 13448 (prop = scf_property_create(g_hndl)) == NULL ||
13436 13449 (iter = scf_iter_create(g_hndl)) == NULL ||
13437 13450 (piter = scf_iter_create(g_hndl)) == NULL ||
13438 13451 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13439 13452 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13440 13453 scfdie();
13441 13454
13442 13455 prnbuf = safe_malloc(max_scf_name_len + 1);
13443 13456
13444 13457 if (cur_level != NULL)
13445 13458 ret = scf_iter_snaplevel_pgs(iter, cur_level);
13446 13459 else if (cur_inst != NULL)
13447 13460 ret = scf_iter_instance_pgs(iter, cur_inst);
13448 13461 else
13449 13462 ret = scf_iter_service_pgs(iter, cur_svc);
13450 13463 if (ret != 0) {
13451 13464 return;
13452 13465 }
13453 13466
13454 13467 /*
13455 13468 * We want to only list items which match pattern, and we want the
13456 13469 * second column to line up, so during the first pass we'll save
13457 13470 * matching items, their names, and their templates in objects,
13458 13471 * names, and tmpls, computing the maximum name length as we go,
13459 13472 * and then we'll print them out.
13460 13473 *
13461 13474 * Note: We always keep an extra slot available so the array can be
13462 13475 * NULL-terminated.
13463 13476 */
13464 13477 i = 0;
13465 13478 allocd = 1;
13466 13479 objects = safe_malloc(sizeof (*objects));
13467 13480 names = safe_malloc(sizeof (*names));
13468 13481 tmpls = safe_malloc(sizeof (*tmpls));
13469 13482
13470 13483 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13471 13484 int new_pg = 0;
13472 13485 int print_props = 0;
13473 13486 pgtp = NULL;
13474 13487
13475 13488 pgnlen = scf_pg_get_name(pg, NULL, 0);
13476 13489 if (pgnlen < 0)
13477 13490 scfdie();
13478 13491
13479 13492 pgnbuf = safe_malloc(pgnlen + 1);
13480 13493
13481 13494 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13482 13495 if (szret < 0)
13483 13496 scfdie();
13484 13497 assert(szret <= pgnlen);
13485 13498
13486 13499 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13487 13500 if (scf_error() != SCF_ERROR_NOT_FOUND)
13488 13501 scfdie();
13489 13502 pgtp = NULL;
13490 13503 } else {
13491 13504 pgtp = pgt;
13492 13505 }
13493 13506
13494 13507 if (pattern == NULL ||
13495 13508 fnmatch(pattern, pgnbuf, 0) == 0) {
13496 13509 if (i+1 >= allocd) {
13497 13510 allocd *= 2;
13498 13511 objects = realloc(objects,
13499 13512 sizeof (*objects) * allocd);
13500 13513 names =
13501 13514 realloc(names, sizeof (*names) * allocd);
13502 13515 tmpls = realloc(tmpls,
13503 13516 sizeof (*tmpls) * allocd);
13504 13517 if (objects == NULL || names == NULL ||
13505 13518 tmpls == NULL)
13506 13519 uu_die(gettext("Out of memory"));
13507 13520 }
13508 13521 objects[i] = pg;
13509 13522 names[i] = pgnbuf;
13510 13523
13511 13524 if (pgtp == NULL)
13512 13525 tmpls[i] = NULL;
13513 13526 else
13514 13527 tmpls[i] = pgt;
13515 13528
13516 13529 ++i;
13517 13530
13518 13531 if (pgnlen > max_len)
13519 13532 max_len = pgnlen;
13520 13533
13521 13534 new_pg = 1;
13522 13535 print_props = 1;
13523 13536 }
13524 13537
13525 13538 if (only_pgs) {
13526 13539 if (new_pg) {
13527 13540 pg = scf_pg_create(g_hndl);
13528 13541 if (pg == NULL)
13529 13542 scfdie();
13530 13543 pgt = scf_tmpl_pg_create(g_hndl);
13531 13544 if (pgt == NULL)
13532 13545 scfdie();
13533 13546 } else
13534 13547 free(pgnbuf);
13535 13548
13536 13549 continue;
13537 13550 }
13538 13551
13539 13552 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13540 13553 scfdie();
13541 13554
13542 13555 while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13543 13556 prnlen = scf_property_get_name(prop, prnbuf,
13544 13557 max_scf_name_len + 1);
13545 13558 if (prnlen < 0)
13546 13559 scfdie();
13547 13560
13548 13561 /* Will prepend the property group name and a slash. */
13549 13562 prnlen += pgnlen + 1;
13550 13563
13551 13564 ppnbuf = safe_malloc(prnlen + 1);
13552 13565
13553 13566 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13554 13567 prnbuf) < 0)
13555 13568 uu_die("snprintf");
13556 13569
13557 13570 if (pattern == NULL || print_props == 1 ||
13558 13571 fnmatch(pattern, ppnbuf, 0) == 0) {
13559 13572 if (i+1 >= allocd) {
13560 13573 allocd *= 2;
13561 13574 objects = realloc(objects,
13562 13575 sizeof (*objects) * allocd);
13563 13576 names = realloc(names,
13564 13577 sizeof (*names) * allocd);
13565 13578 tmpls = realloc(tmpls,
13566 13579 sizeof (*tmpls) * allocd);
13567 13580 if (objects == NULL || names == NULL ||
13568 13581 tmpls == NULL)
13569 13582 uu_die(gettext(
13570 13583 "Out of memory"));
13571 13584 }
13572 13585
13573 13586 objects[i] = prop;
13574 13587 names[i] = ppnbuf;
13575 13588
13576 13589 if (pgtp != NULL) {
13577 13590 if (scf_tmpl_get_by_prop(pgt, prnbuf,
13578 13591 prt, 0) < 0) {
13579 13592 if (scf_error() !=
13580 13593 SCF_ERROR_NOT_FOUND)
13581 13594 scfdie();
13582 13595 tmpls[i] = NULL;
13583 13596 } else {
13584 13597 tmpls[i] = prt;
13585 13598 }
13586 13599 } else {
13587 13600 tmpls[i] = NULL;
13588 13601 }
13589 13602
13590 13603 ++i;
13591 13604
13592 13605 if (prnlen > max_len)
13593 13606 max_len = prnlen;
13594 13607
13595 13608 prop = scf_property_create(g_hndl);
13596 13609 prt = scf_tmpl_prop_create(g_hndl);
13597 13610 } else {
13598 13611 free(ppnbuf);
13599 13612 }
13600 13613 }
13601 13614
13602 13615 if (new_pg) {
13603 13616 pg = scf_pg_create(g_hndl);
13604 13617 if (pg == NULL)
13605 13618 scfdie();
13606 13619 pgt = scf_tmpl_pg_create(g_hndl);
13607 13620 if (pgt == NULL)
13608 13621 scfdie();
13609 13622 } else
13610 13623 free(pgnbuf);
13611 13624 }
13612 13625 if (ret != 0)
13613 13626 scfdie();
13614 13627
13615 13628 objects[i] = NULL;
13616 13629
13617 13630 scf_pg_destroy(pg);
13618 13631 scf_tmpl_pg_destroy(pgt);
13619 13632 scf_property_destroy(prop);
13620 13633 scf_tmpl_prop_destroy(prt);
13621 13634
13622 13635 for (i = 0; objects[i] != NULL; ++i) {
13623 13636 if (strchr(names[i], '/') == NULL) {
13624 13637 /* property group */
13625 13638 pg = (scf_propertygroup_t *)objects[i];
13626 13639 pgt = (scf_pg_tmpl_t *)tmpls[i];
13627 13640 list_pg_info(pg, names[i], max_len);
13628 13641 list_pg_tmpl(pgt, pg, templates);
13629 13642 free(names[i]);
13630 13643 scf_pg_destroy(pg);
13631 13644 if (pgt != NULL)
13632 13645 scf_tmpl_pg_destroy(pgt);
13633 13646 } else {
13634 13647 /* property */
13635 13648 prop = (scf_property_t *)objects[i];
13636 13649 prt = (scf_prop_tmpl_t *)tmpls[i];
13637 13650 list_prop_info(prop, names[i], max_len);
13638 13651 list_prop_tmpl(prt, prop, templates);
13639 13652 free(names[i]);
13640 13653 scf_property_destroy(prop);
13641 13654 if (prt != NULL)
13642 13655 scf_tmpl_prop_destroy(prt);
13643 13656 }
13644 13657 }
13645 13658
13646 13659 free(names);
13647 13660 free(objects);
13648 13661 free(tmpls);
13649 13662 }
13650 13663
13651 13664 void
13652 13665 lscf_listpg(const char *pattern)
13653 13666 {
13654 13667 lscf_prep_hndl();
13655 13668
13656 13669 listprop(pattern, 1, 0);
13657 13670 }
13658 13671
13659 13672 /*
13660 13673 * Property group and property creation, setting, and deletion. setprop (and
13661 13674 * its alias, addprop) can either create a property group of a given type, or
13662 13675 * it can create or set a property to a given type and list of values.
13663 13676 */
13664 13677 void
13665 13678 lscf_addpg(const char *name, const char *type, const char *flags)
13666 13679 {
13667 13680 scf_propertygroup_t *pg;
13668 13681 int ret;
13669 13682 uint32_t flgs = 0;
13670 13683 const char *cp;
13671 13684
13672 13685
13673 13686 lscf_prep_hndl();
13674 13687
13675 13688 if (cur_snap != NULL) {
13676 13689 semerr(emsg_cant_modify_snapshots);
13677 13690 return;
13678 13691 }
13679 13692
13680 13693 if (cur_inst == NULL && cur_svc == NULL) {
13681 13694 semerr(emsg_entity_not_selected);
13682 13695 return;
13683 13696 }
13684 13697
13685 13698 if (flags != NULL) {
13686 13699 for (cp = flags; *cp != '\0'; ++cp) {
13687 13700 switch (*cp) {
13688 13701 case 'P':
13689 13702 flgs |= SCF_PG_FLAG_NONPERSISTENT;
13690 13703 break;
13691 13704
13692 13705 case 'p':
13693 13706 flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13694 13707 break;
13695 13708
13696 13709 default:
13697 13710 semerr(gettext("Invalid property group flag "
13698 13711 "%c."), *cp);
13699 13712 return;
13700 13713 }
13701 13714 }
13702 13715 }
13703 13716
13704 13717 pg = scf_pg_create(g_hndl);
13705 13718 if (pg == NULL)
13706 13719 scfdie();
13707 13720
13708 13721 if (cur_inst != NULL)
13709 13722 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13710 13723 else
13711 13724 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13712 13725
13713 13726 if (ret != SCF_SUCCESS) {
13714 13727 switch (scf_error()) {
13715 13728 case SCF_ERROR_INVALID_ARGUMENT:
13716 13729 semerr(gettext("Name, type, or flags are invalid.\n"));
13717 13730 break;
13718 13731
13719 13732 case SCF_ERROR_EXISTS:
13720 13733 semerr(gettext("Property group already exists.\n"));
13721 13734 break;
13722 13735
13723 13736 case SCF_ERROR_PERMISSION_DENIED:
13724 13737 semerr(emsg_permission_denied);
13725 13738 break;
13726 13739
13727 13740 case SCF_ERROR_BACKEND_ACCESS:
13728 13741 semerr(gettext("Backend refused access.\n"));
13729 13742 break;
13730 13743
13731 13744 default:
13732 13745 scfdie();
13733 13746 }
13734 13747 }
13735 13748
13736 13749 scf_pg_destroy(pg);
13737 13750
13738 13751 private_refresh();
13739 13752 }
13740 13753
13741 13754 void
13742 13755 lscf_delpg(char *name)
13743 13756 {
13744 13757 lscf_prep_hndl();
13745 13758
13746 13759 if (cur_snap != NULL) {
13747 13760 semerr(emsg_cant_modify_snapshots);
13748 13761 return;
13749 13762 }
13750 13763
13751 13764 if (cur_inst == NULL && cur_svc == NULL) {
13752 13765 semerr(emsg_entity_not_selected);
13753 13766 return;
13754 13767 }
13755 13768
13756 13769 if (strchr(name, '/') != NULL) {
13757 13770 semerr(emsg_invalid_pg_name, name);
13758 13771 return;
13759 13772 }
13760 13773
13761 13774 lscf_delprop(name);
13762 13775 }
13763 13776
13764 13777 /*
13765 13778 * scf_delhash() is used to remove the property group related to the
13766 13779 * hash entry for a specific manifest in the repository. pgname will be
13767 13780 * constructed from the location of the manifest file. If deathrow isn't 0,
13768 13781 * manifest file doesn't need to exist (manifest string will be used as
13769 13782 * an absolute path).
13770 13783 */
13771 13784 void
13772 13785 lscf_delhash(char *manifest, int deathrow)
13773 13786 {
13774 13787 char *pgname;
13775 13788
13776 13789 if (cur_snap != NULL ||
13777 13790 cur_inst != NULL || cur_svc != NULL) {
13778 13791 warn(gettext("error, an entity is selected\n"));
13779 13792 return;
13780 13793 }
13781 13794
13782 13795 /* select smf/manifest */
13783 13796 lscf_select(HASH_SVC);
13784 13797 /*
13785 13798 * Translate the manifest file name to property name. In the deathrow
13786 13799 * case, the manifest file does not need to exist.
13787 13800 */
13788 13801 pgname = mhash_filename_to_propname(manifest,
13789 13802 deathrow ? B_TRUE : B_FALSE);
13790 13803 if (pgname == NULL) {
13791 13804 warn(gettext("cannot resolve pathname for %s\n"), manifest);
13792 13805 return;
13793 13806 }
13794 13807 /* delete the hash property name */
13795 13808 lscf_delpg(pgname);
13796 13809 }
13797 13810
13798 13811 void
13799 13812 lscf_listprop(const char *pattern)
13800 13813 {
13801 13814 lscf_prep_hndl();
13802 13815
13803 13816 listprop(pattern, 0, 0);
13804 13817 }
13805 13818
13806 13819 int
13807 13820 lscf_setprop(const char *pgname, const char *type, const char *value,
13808 13821 const uu_list_t *values)
13809 13822 {
13810 13823 scf_type_t ty, current_ty;
13811 13824 scf_service_t *svc;
13812 13825 scf_propertygroup_t *pg, *parent_pg;
13813 13826 scf_property_t *prop, *parent_prop;
13814 13827 scf_pg_tmpl_t *pgt;
13815 13828 scf_prop_tmpl_t *prt;
13816 13829 int ret, result = 0;
13817 13830 scf_transaction_t *tx;
13818 13831 scf_transaction_entry_t *e;
13819 13832 scf_value_t *v;
13820 13833 uu_list_walk_t *walk;
13821 13834 string_list_t *sp;
13822 13835 char *propname;
13823 13836 int req_quotes = 0;
13824 13837
13825 13838 lscf_prep_hndl();
13826 13839
13827 13840 if ((e = scf_entry_create(g_hndl)) == NULL ||
13828 13841 (svc = scf_service_create(g_hndl)) == NULL ||
13829 13842 (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13830 13843 (pg = scf_pg_create(g_hndl)) == NULL ||
13831 13844 (parent_prop = scf_property_create(g_hndl)) == NULL ||
13832 13845 (prop = scf_property_create(g_hndl)) == NULL ||
13833 13846 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13834 13847 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13835 13848 (tx = scf_transaction_create(g_hndl)) == NULL)
13836 13849 scfdie();
13837 13850
13838 13851 if (cur_snap != NULL) {
13839 13852 semerr(emsg_cant_modify_snapshots);
13840 13853 goto fail;
13841 13854 }
13842 13855
13843 13856 if (cur_inst == NULL && cur_svc == NULL) {
13844 13857 semerr(emsg_entity_not_selected);
13845 13858 goto fail;
13846 13859 }
13847 13860
13848 13861 propname = strchr(pgname, '/');
13849 13862 if (propname == NULL) {
13850 13863 semerr(gettext("Property names must contain a `/'.\n"));
13851 13864 goto fail;
13852 13865 }
13853 13866
13854 13867 *propname = '\0';
13855 13868 ++propname;
13856 13869
13857 13870 if (type != NULL) {
13858 13871 ty = string_to_type(type);
13859 13872 if (ty == SCF_TYPE_INVALID) {
13860 13873 semerr(gettext("Unknown type \"%s\".\n"), type);
13861 13874 goto fail;
13862 13875 }
13863 13876 }
13864 13877
13865 13878 if (cur_inst != NULL)
13866 13879 ret = scf_instance_get_pg(cur_inst, pgname, pg);
13867 13880 else
13868 13881 ret = scf_service_get_pg(cur_svc, pgname, pg);
13869 13882 if (ret != SCF_SUCCESS) {
13870 13883 switch (scf_error()) {
13871 13884 case SCF_ERROR_NOT_FOUND:
13872 13885 semerr(emsg_no_such_pg, pgname);
13873 13886 goto fail;
13874 13887
13875 13888 case SCF_ERROR_INVALID_ARGUMENT:
13876 13889 semerr(emsg_invalid_pg_name, pgname);
13877 13890 goto fail;
13878 13891
13879 13892 default:
13880 13893 scfdie();
13881 13894 break;
13882 13895 }
13883 13896 }
13884 13897
13885 13898 do {
13886 13899 if (scf_pg_update(pg) == -1)
13887 13900 scfdie();
13888 13901 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13889 13902 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13890 13903 scfdie();
13891 13904
13892 13905 semerr(emsg_permission_denied);
13893 13906 goto fail;
13894 13907 }
13895 13908
13896 13909 ret = scf_pg_get_property(pg, propname, prop);
13897 13910 if (ret == SCF_SUCCESS) {
13898 13911 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS)
13899 13912 scfdie();
13900 13913
13901 13914 if (type == NULL)
13902 13915 ty = current_ty;
13903 13916 if (scf_transaction_property_change_type(tx, e,
13904 13917 propname, ty) == -1)
13905 13918 scfdie();
13906 13919
13907 13920 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13908 13921 /* Infer the type, if possible. */
13909 13922 if (type == NULL) {
13910 13923 /*
13911 13924 * First check if we're an instance and the
13912 13925 * property is set on the service.
13913 13926 */
13914 13927 if (cur_inst != NULL &&
13915 13928 scf_instance_get_parent(cur_inst,
13916 13929 svc) == 0 &&
13917 13930 scf_service_get_pg(cur_svc, pgname,
13918 13931 parent_pg) == 0 &&
13919 13932 scf_pg_get_property(parent_pg, propname,
13920 13933 parent_prop) == 0 &&
13921 13934 scf_property_type(parent_prop,
13922 13935 ¤t_ty) == 0) {
13923 13936 ty = current_ty;
13924 13937
13925 13938 /* Then check for a type set in a template. */
13926 13939 } else if (scf_tmpl_get_by_pg(pg, pgt,
13927 13940 0) == 0 &&
13928 13941 scf_tmpl_get_by_prop(pgt, propname, prt,
13929 13942 0) == 0 &&
13930 13943 scf_tmpl_prop_type(prt, ¤t_ty) == 0) {
13931 13944 ty = current_ty;
13932 13945
13933 13946 /* If type can't be inferred, fail. */
13934 13947 } else {
13935 13948 semerr(gettext("Type required for new "
13936 13949 "properties.\n"));
13937 13950 goto fail;
13938 13951 }
13939 13952 }
13940 13953 if (scf_transaction_property_new(tx, e, propname,
13941 13954 ty) == -1)
13942 13955 scfdie();
13943 13956 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13944 13957 semerr(emsg_invalid_prop_name, propname);
13945 13958 goto fail;
13946 13959 } else {
13947 13960 scfdie();
13948 13961 }
13949 13962
13950 13963 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13951 13964 req_quotes = 1;
13952 13965
13953 13966 if (value != NULL) {
13954 13967 v = string_to_value(value, ty, 0);
13955 13968
13956 13969 if (v == NULL)
13957 13970 goto fail;
13958 13971
13959 13972 ret = scf_entry_add_value(e, v);
13960 13973 assert(ret == SCF_SUCCESS);
13961 13974 } else {
13962 13975 assert(values != NULL);
13963 13976
13964 13977 walk = uu_list_walk_start((uu_list_t *)values,
13965 13978 UU_DEFAULT);
13966 13979 if (walk == NULL)
13967 13980 uu_die(gettext("Could not walk list"));
13968 13981
13969 13982 for (sp = uu_list_walk_next(walk); sp != NULL;
13970 13983 sp = uu_list_walk_next(walk)) {
13971 13984 v = string_to_value(sp->str, ty, req_quotes);
13972 13985
13973 13986 if (v == NULL) {
13974 13987 scf_entry_destroy_children(e);
13975 13988 goto fail;
13976 13989 }
13977 13990
13978 13991 ret = scf_entry_add_value(e, v);
13979 13992 assert(ret == SCF_SUCCESS);
13980 13993 }
13981 13994 uu_list_walk_end(walk);
13982 13995 }
13983 13996 result = scf_transaction_commit(tx);
13984 13997
13985 13998 scf_transaction_reset(tx);
13986 13999 scf_entry_destroy_children(e);
13987 14000 } while (result == 0);
13988 14001
13989 14002 if (result < 0) {
13990 14003 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13991 14004 scfdie();
13992 14005
13993 14006 semerr(emsg_permission_denied);
13994 14007 goto fail;
13995 14008 }
13996 14009
13997 14010 ret = 0;
13998 14011
13999 14012 private_refresh();
14000 14013
14001 14014 goto cleanup;
14002 14015
14003 14016 fail:
14004 14017 ret = -1;
14005 14018
14006 14019 cleanup:
14007 14020 scf_transaction_destroy(tx);
14008 14021 scf_entry_destroy(e);
14009 14022 scf_service_destroy(svc);
14010 14023 scf_pg_destroy(parent_pg);
14011 14024 scf_pg_destroy(pg);
14012 14025 scf_property_destroy(parent_prop);
14013 14026 scf_property_destroy(prop);
14014 14027 scf_tmpl_pg_destroy(pgt);
14015 14028 scf_tmpl_prop_destroy(prt);
14016 14029
14017 14030 return (ret);
14018 14031 }
14019 14032
14020 14033 void
14021 14034 lscf_delprop(char *pgn)
14022 14035 {
14023 14036 char *slash, *pn;
14024 14037 scf_propertygroup_t *pg;
14025 14038 scf_transaction_t *tx;
14026 14039 scf_transaction_entry_t *e;
14027 14040 int ret;
14028 14041
14029 14042
14030 14043 lscf_prep_hndl();
14031 14044
14032 14045 if (cur_snap != NULL) {
14033 14046 semerr(emsg_cant_modify_snapshots);
14034 14047 return;
14035 14048 }
14036 14049
14037 14050 if (cur_inst == NULL && cur_svc == NULL) {
14038 14051 semerr(emsg_entity_not_selected);
14039 14052 return;
14040 14053 }
14041 14054
14042 14055 pg = scf_pg_create(g_hndl);
14043 14056 if (pg == NULL)
14044 14057 scfdie();
14045 14058
14046 14059 slash = strchr(pgn, '/');
14047 14060 if (slash == NULL) {
14048 14061 pn = NULL;
14049 14062 } else {
14050 14063 *slash = '\0';
14051 14064 pn = slash + 1;
14052 14065 }
14053 14066
14054 14067 if (cur_inst != NULL)
14055 14068 ret = scf_instance_get_pg(cur_inst, pgn, pg);
14056 14069 else
14057 14070 ret = scf_service_get_pg(cur_svc, pgn, pg);
14058 14071 if (ret != SCF_SUCCESS) {
14059 14072 switch (scf_error()) {
14060 14073 case SCF_ERROR_NOT_FOUND:
14061 14074 semerr(emsg_no_such_pg, pgn);
14062 14075 break;
14063 14076
14064 14077 case SCF_ERROR_INVALID_ARGUMENT:
14065 14078 semerr(emsg_invalid_pg_name, pgn);
14066 14079 break;
14067 14080
14068 14081 default:
14069 14082 scfdie();
14070 14083 }
14071 14084
14072 14085 scf_pg_destroy(pg);
14073 14086
14074 14087 return;
14075 14088 }
14076 14089
14077 14090 if (pn == NULL) {
14078 14091 /* Try to delete the property group. */
14079 14092 if (scf_pg_delete(pg) != SCF_SUCCESS) {
14080 14093 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14081 14094 scfdie();
14082 14095
14083 14096 semerr(emsg_permission_denied);
14084 14097 } else {
14085 14098 private_refresh();
14086 14099 }
14087 14100
14088 14101 scf_pg_destroy(pg);
14089 14102 return;
14090 14103 }
14091 14104
14092 14105 e = scf_entry_create(g_hndl);
14093 14106 tx = scf_transaction_create(g_hndl);
14094 14107
14095 14108 do {
14096 14109 if (scf_pg_update(pg) == -1)
14097 14110 scfdie();
14098 14111 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14099 14112 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14100 14113 scfdie();
14101 14114
14102 14115 semerr(emsg_permission_denied);
14103 14116 break;
14104 14117 }
14105 14118
14106 14119 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14107 14120 if (scf_error() == SCF_ERROR_NOT_FOUND) {
14108 14121 semerr(gettext("No such property %s/%s.\n"),
14109 14122 pgn, pn);
14110 14123 break;
14111 14124 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14112 14125 semerr(emsg_invalid_prop_name, pn);
14113 14126 break;
14114 14127 } else {
14115 14128 scfdie();
14116 14129 }
14117 14130 }
14118 14131
14119 14132 ret = scf_transaction_commit(tx);
14120 14133
14121 14134 if (ret == 0)
14122 14135 scf_transaction_reset(tx);
14123 14136 } while (ret == 0);
14124 14137
14125 14138 if (ret < 0) {
14126 14139 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14127 14140 scfdie();
14128 14141
14129 14142 semerr(emsg_permission_denied);
14130 14143 } else {
14131 14144 private_refresh();
14132 14145 }
14133 14146
14134 14147 scf_transaction_destroy(tx);
14135 14148 scf_entry_destroy(e);
14136 14149 scf_pg_destroy(pg);
14137 14150 }
14138 14151
14139 14152 /*
14140 14153 * Property editing.
14141 14154 */
14142 14155
14143 14156 static int
14144 14157 write_edit_script(FILE *strm)
14145 14158 {
14146 14159 char *fmribuf;
14147 14160 ssize_t fmrilen;
14148 14161
14149 14162 scf_propertygroup_t *pg;
14150 14163 scf_property_t *prop;
14151 14164 scf_value_t *val;
14152 14165 scf_type_t ty;
14153 14166 int ret, result = 0;
14154 14167 scf_iter_t *iter, *piter, *viter;
14155 14168 char *buf, *tybuf, *pname;
14156 14169 const char *emsg_write_error;
14157 14170
14158 14171
14159 14172 emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14160 14173
14161 14174
14162 14175 /* select fmri */
14163 14176 if (cur_inst != NULL) {
14164 14177 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14165 14178 if (fmrilen < 0)
14166 14179 scfdie();
14167 14180 fmribuf = safe_malloc(fmrilen + 1);
14168 14181 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14169 14182 scfdie();
14170 14183 } else {
14171 14184 assert(cur_svc != NULL);
14172 14185 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14173 14186 if (fmrilen < 0)
14174 14187 scfdie();
14175 14188 fmribuf = safe_malloc(fmrilen + 1);
14176 14189 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14177 14190 scfdie();
14178 14191 }
14179 14192
14180 14193 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14181 14194 warn(emsg_write_error, strerror(errno));
14182 14195 free(fmribuf);
14183 14196 return (-1);
14184 14197 }
14185 14198
14186 14199 free(fmribuf);
14187 14200
14188 14201
14189 14202 if ((pg = scf_pg_create(g_hndl)) == NULL ||
14190 14203 (prop = scf_property_create(g_hndl)) == NULL ||
14191 14204 (val = scf_value_create(g_hndl)) == NULL ||
14192 14205 (iter = scf_iter_create(g_hndl)) == NULL ||
14193 14206 (piter = scf_iter_create(g_hndl)) == NULL ||
14194 14207 (viter = scf_iter_create(g_hndl)) == NULL)
14195 14208 scfdie();
14196 14209
14197 14210 buf = safe_malloc(max_scf_name_len + 1);
14198 14211 tybuf = safe_malloc(max_scf_pg_type_len + 1);
14199 14212 pname = safe_malloc(max_scf_name_len + 1);
14200 14213
14201 14214 if (cur_inst != NULL)
14202 14215 ret = scf_iter_instance_pgs(iter, cur_inst);
14203 14216 else
14204 14217 ret = scf_iter_service_pgs(iter, cur_svc);
14205 14218 if (ret != SCF_SUCCESS)
14206 14219 scfdie();
14207 14220
14208 14221 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14209 14222 int ret2;
14210 14223
14211 14224 /*
14212 14225 * # delprop pg
14213 14226 * # addpg pg type
14214 14227 */
14215 14228 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14216 14229 scfdie();
14217 14230
14218 14231 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14219 14232 scfdie();
14220 14233
14221 14234 if (fprintf(strm, "# Property group \"%s\"\n"
14222 14235 "# delprop %s\n"
14223 14236 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14224 14237 warn(emsg_write_error, strerror(errno));
14225 14238 result = -1;
14226 14239 goto out;
14227 14240 }
14228 14241
14229 14242 /* # setprop pg/prop = (values) */
14230 14243
14231 14244 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14232 14245 scfdie();
14233 14246
14234 14247 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14235 14248 int first = 1;
14236 14249 int ret3;
14237 14250 int multiple;
14238 14251 int is_str;
14239 14252 scf_type_t bty;
14240 14253
14241 14254 if (scf_property_get_name(prop, pname,
14242 14255 max_scf_name_len + 1) < 0)
14243 14256 scfdie();
14244 14257
14245 14258 if (scf_property_type(prop, &ty) != 0)
14246 14259 scfdie();
14247 14260
14248 14261 multiple = prop_has_multiple_values(prop, val);
14249 14262
14250 14263 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14251 14264 pname, scf_type_to_string(ty), multiple ? "(" : "")
14252 14265 < 0) {
14253 14266 warn(emsg_write_error, strerror(errno));
14254 14267 result = -1;
14255 14268 goto out;
14256 14269 }
14257 14270
14258 14271 (void) scf_type_base_type(ty, &bty);
14259 14272 is_str = (bty == SCF_TYPE_ASTRING);
14260 14273
14261 14274 if (scf_iter_property_values(viter, prop) !=
14262 14275 SCF_SUCCESS)
14263 14276 scfdie();
14264 14277
14265 14278 while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14266 14279 char *buf;
14267 14280 ssize_t buflen;
14268 14281
14269 14282 buflen = scf_value_get_as_string(val, NULL, 0);
14270 14283 if (buflen < 0)
14271 14284 scfdie();
14272 14285
14273 14286 buf = safe_malloc(buflen + 1);
14274 14287
14275 14288 if (scf_value_get_as_string(val, buf,
14276 14289 buflen + 1) < 0)
14277 14290 scfdie();
14278 14291
14279 14292 if (first)
14280 14293 first = 0;
14281 14294 else {
14282 14295 if (putc(' ', strm) != ' ') {
14283 14296 warn(emsg_write_error,
14284 14297 strerror(errno));
14285 14298 result = -1;
14286 14299 goto out;
14287 14300 }
14288 14301 }
14289 14302
14290 14303 if ((is_str && multiple) ||
14291 14304 strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14292 14305 (void) putc('"', strm);
14293 14306 (void) quote_and_print(buf, strm, 1);
14294 14307 (void) putc('"', strm);
14295 14308
14296 14309 if (ferror(strm)) {
14297 14310 warn(emsg_write_error,
14298 14311 strerror(errno));
14299 14312 result = -1;
14300 14313 goto out;
14301 14314 }
14302 14315 } else {
14303 14316 if (fprintf(strm, "%s", buf) < 0) {
14304 14317 warn(emsg_write_error,
14305 14318 strerror(errno));
14306 14319 result = -1;
14307 14320 goto out;
14308 14321 }
14309 14322 }
14310 14323
14311 14324 free(buf);
14312 14325 }
14313 14326 if (ret3 < 0 &&
14314 14327 scf_error() != SCF_ERROR_PERMISSION_DENIED)
14315 14328 scfdie();
14316 14329
14317 14330 /* Write closing paren if mult-value property */
14318 14331 if ((multiple && putc(')', strm) == EOF) ||
14319 14332
14320 14333 /* Write final newline */
14321 14334 fputc('\n', strm) == EOF) {
14322 14335 warn(emsg_write_error, strerror(errno));
14323 14336 result = -1;
14324 14337 goto out;
14325 14338 }
14326 14339 }
14327 14340 if (ret2 < 0)
14328 14341 scfdie();
14329 14342
14330 14343 if (fputc('\n', strm) == EOF) {
14331 14344 warn(emsg_write_error, strerror(errno));
14332 14345 result = -1;
14333 14346 goto out;
14334 14347 }
14335 14348 }
14336 14349 if (ret < 0)
14337 14350 scfdie();
14338 14351
14339 14352 out:
14340 14353 free(pname);
14341 14354 free(tybuf);
14342 14355 free(buf);
14343 14356 scf_iter_destroy(viter);
14344 14357 scf_iter_destroy(piter);
14345 14358 scf_iter_destroy(iter);
14346 14359 scf_value_destroy(val);
14347 14360 scf_property_destroy(prop);
14348 14361 scf_pg_destroy(pg);
14349 14362
14350 14363 if (result == 0) {
14351 14364 if (fflush(strm) != 0) {
14352 14365 warn(emsg_write_error, strerror(errno));
14353 14366 return (-1);
14354 14367 }
14355 14368 }
14356 14369
14357 14370 return (result);
14358 14371 }
14359 14372
14360 14373 int
14361 14374 lscf_editprop()
14362 14375 {
14363 14376 char *buf, *editor;
14364 14377 size_t bufsz;
14365 14378 int tmpfd;
14366 14379 char tempname[] = TEMP_FILE_PATTERN;
14367 14380
14368 14381 lscf_prep_hndl();
14369 14382
14370 14383 if (cur_snap != NULL) {
14371 14384 semerr(emsg_cant_modify_snapshots);
14372 14385 return (-1);
14373 14386 }
14374 14387
14375 14388 if (cur_svc == NULL && cur_inst == NULL) {
14376 14389 semerr(emsg_entity_not_selected);
14377 14390 return (-1);
14378 14391 }
14379 14392
14380 14393 tmpfd = mkstemp(tempname);
14381 14394 if (tmpfd == -1) {
14382 14395 semerr(gettext("Could not create temporary file.\n"));
14383 14396 return (-1);
14384 14397 }
14385 14398
14386 14399 (void) strcpy(tempfilename, tempname);
14387 14400
14388 14401 tempfile = fdopen(tmpfd, "r+");
14389 14402 if (tempfile == NULL) {
14390 14403 warn(gettext("Could not create temporary file.\n"));
14391 14404 if (close(tmpfd) == -1)
14392 14405 warn(gettext("Could not close temporary file: %s.\n"),
14393 14406 strerror(errno));
14394 14407
14395 14408 remove_tempfile();
14396 14409
14397 14410 return (-1);
14398 14411 }
14399 14412
14400 14413 if (write_edit_script(tempfile) == -1) {
14401 14414 remove_tempfile();
14402 14415 return (-1);
14403 14416 }
14404 14417
14405 14418 editor = getenv("EDITOR");
14406 14419 if (editor == NULL)
14407 14420 editor = "vi";
14408 14421
14409 14422 bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14410 14423 buf = safe_malloc(bufsz);
14411 14424
14412 14425 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14413 14426 uu_die(gettext("Error creating editor command"));
14414 14427
14415 14428 if (system(buf) == -1) {
14416 14429 semerr(gettext("Could not launch editor %s: %s\n"), editor,
14417 14430 strerror(errno));
14418 14431 free(buf);
14419 14432 remove_tempfile();
14420 14433 return (-1);
14421 14434 }
14422 14435
14423 14436 free(buf);
14424 14437
14425 14438 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14426 14439
14427 14440 remove_tempfile();
14428 14441
14429 14442 return (0);
14430 14443 }
14431 14444
14432 14445 static void
14433 14446 add_string(uu_list_t *strlist, const char *str)
14434 14447 {
14435 14448 string_list_t *elem;
14436 14449 elem = safe_malloc(sizeof (*elem));
14437 14450 uu_list_node_init(elem, &elem->node, string_pool);
14438 14451 elem->str = safe_strdup(str);
14439 14452 if (uu_list_append(strlist, elem) != 0)
14440 14453 uu_die(gettext("libuutil error: %s\n"),
14441 14454 uu_strerror(uu_error()));
14442 14455 }
14443 14456
14444 14457 static int
14445 14458 remove_string(uu_list_t *strlist, const char *str)
14446 14459 {
14447 14460 uu_list_walk_t *elems;
14448 14461 string_list_t *sp;
14449 14462
14450 14463 /*
14451 14464 * Find the element that needs to be removed.
14452 14465 */
14453 14466 elems = uu_list_walk_start(strlist, UU_DEFAULT);
14454 14467 while ((sp = uu_list_walk_next(elems)) != NULL) {
14455 14468 if (strcmp(sp->str, str) == 0)
14456 14469 break;
14457 14470 }
14458 14471 uu_list_walk_end(elems);
14459 14472
14460 14473 /*
14461 14474 * Returning 1 here as the value was not found, this
14462 14475 * might not be an error. Leave it to the caller to
14463 14476 * decide.
14464 14477 */
14465 14478 if (sp == NULL) {
14466 14479 return (1);
14467 14480 }
14468 14481
14469 14482 uu_list_remove(strlist, sp);
14470 14483
14471 14484 free(sp->str);
14472 14485 free(sp);
14473 14486
14474 14487 return (0);
14475 14488 }
14476 14489
14477 14490 /*
14478 14491 * Get all property values that don't match the given glob pattern,
14479 14492 * if a pattern is specified.
14480 14493 */
14481 14494 static void
14482 14495 get_prop_values(scf_property_t *prop, uu_list_t *values,
14483 14496 const char *pattern)
14484 14497 {
14485 14498 scf_iter_t *iter;
14486 14499 scf_value_t *val;
14487 14500 int ret;
14488 14501
14489 14502 if ((iter = scf_iter_create(g_hndl)) == NULL ||
14490 14503 (val = scf_value_create(g_hndl)) == NULL)
14491 14504 scfdie();
14492 14505
14493 14506 if (scf_iter_property_values(iter, prop) != 0)
14494 14507 scfdie();
14495 14508
14496 14509 while ((ret = scf_iter_next_value(iter, val)) == 1) {
14497 14510 char *buf;
14498 14511 ssize_t vlen, szret;
14499 14512
14500 14513 vlen = scf_value_get_as_string(val, NULL, 0);
14501 14514 if (vlen < 0)
14502 14515 scfdie();
14503 14516
14504 14517 buf = safe_malloc(vlen + 1);
14505 14518
14506 14519 szret = scf_value_get_as_string(val, buf, vlen + 1);
14507 14520 if (szret < 0)
14508 14521 scfdie();
14509 14522 assert(szret <= vlen);
14510 14523
14511 14524 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14512 14525 add_string(values, buf);
14513 14526
14514 14527 free(buf);
14515 14528 }
14516 14529
14517 14530 if (ret == -1)
14518 14531 scfdie();
14519 14532
14520 14533 scf_value_destroy(val);
14521 14534 scf_iter_destroy(iter);
14522 14535 }
14523 14536
14524 14537 static int
14525 14538 lscf_setpropvalue(const char *pgname, const char *type,
14526 14539 const char *arg, int isadd, int isnotfoundok)
14527 14540 {
14528 14541 scf_type_t ty;
14529 14542 scf_propertygroup_t *pg;
14530 14543 scf_property_t *prop;
14531 14544 int ret, result = 0;
14532 14545 scf_transaction_t *tx;
14533 14546 scf_transaction_entry_t *e;
14534 14547 scf_value_t *v;
14535 14548 string_list_t *sp;
14536 14549 char *propname;
14537 14550 uu_list_t *values;
14538 14551 uu_list_walk_t *walk;
14539 14552 void *cookie = NULL;
14540 14553 char *pattern = NULL;
14541 14554
14542 14555 lscf_prep_hndl();
14543 14556
14544 14557 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14545 14558 uu_die(gettext("Could not create property list: %s\n"),
14546 14559 uu_strerror(uu_error()));
14547 14560
14548 14561 if (!isadd)
14549 14562 pattern = safe_strdup(arg);
14550 14563
14551 14564 if ((e = scf_entry_create(g_hndl)) == NULL ||
14552 14565 (pg = scf_pg_create(g_hndl)) == NULL ||
14553 14566 (prop = scf_property_create(g_hndl)) == NULL ||
14554 14567 (tx = scf_transaction_create(g_hndl)) == NULL)
14555 14568 scfdie();
14556 14569
14557 14570 if (cur_snap != NULL) {
14558 14571 semerr(emsg_cant_modify_snapshots);
14559 14572 goto fail;
14560 14573 }
14561 14574
14562 14575 if (cur_inst == NULL && cur_svc == NULL) {
14563 14576 semerr(emsg_entity_not_selected);
14564 14577 goto fail;
14565 14578 }
14566 14579
14567 14580 propname = strchr(pgname, '/');
14568 14581 if (propname == NULL) {
14569 14582 semerr(gettext("Property names must contain a `/'.\n"));
14570 14583 goto fail;
14571 14584 }
14572 14585
14573 14586 *propname = '\0';
14574 14587 ++propname;
14575 14588
14576 14589 if (type != NULL) {
14577 14590 ty = string_to_type(type);
14578 14591 if (ty == SCF_TYPE_INVALID) {
14579 14592 semerr(gettext("Unknown type \"%s\".\n"), type);
14580 14593 goto fail;
14581 14594 }
14582 14595 }
14583 14596
14584 14597 if (cur_inst != NULL)
14585 14598 ret = scf_instance_get_pg(cur_inst, pgname, pg);
14586 14599 else
14587 14600 ret = scf_service_get_pg(cur_svc, pgname, pg);
14588 14601 if (ret != 0) {
14589 14602 switch (scf_error()) {
14590 14603 case SCF_ERROR_NOT_FOUND:
14591 14604 if (isnotfoundok) {
14592 14605 result = 0;
14593 14606 } else {
14594 14607 semerr(emsg_no_such_pg, pgname);
14595 14608 result = -1;
14596 14609 }
14597 14610 goto out;
14598 14611
14599 14612 case SCF_ERROR_INVALID_ARGUMENT:
14600 14613 semerr(emsg_invalid_pg_name, pgname);
14601 14614 goto fail;
14602 14615
14603 14616 default:
14604 14617 scfdie();
14605 14618 }
14606 14619 }
14607 14620
14608 14621 do {
14609 14622 if (scf_pg_update(pg) == -1)
14610 14623 scfdie();
14611 14624 if (scf_transaction_start(tx, pg) != 0) {
14612 14625 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14613 14626 scfdie();
14614 14627
14615 14628 semerr(emsg_permission_denied);
14616 14629 goto fail;
14617 14630 }
14618 14631
14619 14632 ret = scf_pg_get_property(pg, propname, prop);
14620 14633 if (ret == 0) {
14621 14634 scf_type_t ptype;
14622 14635 char *pat = pattern;
14623 14636
14624 14637 if (scf_property_type(prop, &ptype) != 0)
14625 14638 scfdie();
14626 14639
14627 14640 if (isadd) {
14628 14641 if (type != NULL && ptype != ty) {
14629 14642 semerr(gettext("Property \"%s\" is not "
14630 14643 "of type \"%s\".\n"), propname,
14631 14644 type);
14632 14645 goto fail;
14633 14646 }
14634 14647
14635 14648 pat = NULL;
14636 14649 } else {
14637 14650 size_t len = strlen(pat);
14638 14651 if (len > 0 && pat[len - 1] == '\"')
14639 14652 pat[len - 1] = '\0';
14640 14653 if (len > 0 && pat[0] == '\"')
14641 14654 pat++;
14642 14655 }
14643 14656
14644 14657 ty = ptype;
14645 14658
14646 14659 get_prop_values(prop, values, pat);
14647 14660
14648 14661 if (isadd)
14649 14662 add_string(values, arg);
14650 14663
14651 14664 if (scf_transaction_property_change(tx, e,
14652 14665 propname, ty) == -1)
14653 14666 scfdie();
14654 14667 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14655 14668 if (isadd) {
14656 14669 if (type == NULL) {
14657 14670 semerr(gettext("Type required "
14658 14671 "for new properties.\n"));
14659 14672 goto fail;
14660 14673 }
14661 14674
14662 14675 add_string(values, arg);
14663 14676
14664 14677 if (scf_transaction_property_new(tx, e,
14665 14678 propname, ty) == -1)
14666 14679 scfdie();
14667 14680 } else if (isnotfoundok) {
14668 14681 result = 0;
14669 14682 goto out;
14670 14683 } else {
14671 14684 semerr(gettext("No such property %s/%s.\n"),
14672 14685 pgname, propname);
14673 14686 result = -1;
14674 14687 goto out;
14675 14688 }
14676 14689 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14677 14690 semerr(emsg_invalid_prop_name, propname);
14678 14691 goto fail;
14679 14692 } else {
14680 14693 scfdie();
14681 14694 }
14682 14695
14683 14696 walk = uu_list_walk_start(values, UU_DEFAULT);
14684 14697 if (walk == NULL)
14685 14698 uu_die(gettext("Could not walk property list.\n"));
14686 14699
14687 14700 for (sp = uu_list_walk_next(walk); sp != NULL;
14688 14701 sp = uu_list_walk_next(walk)) {
14689 14702 v = string_to_value(sp->str, ty, 0);
14690 14703
14691 14704 if (v == NULL) {
14692 14705 scf_entry_destroy_children(e);
14693 14706 goto fail;
14694 14707 }
14695 14708 ret = scf_entry_add_value(e, v);
14696 14709 assert(ret == 0);
14697 14710 }
14698 14711 uu_list_walk_end(walk);
14699 14712
14700 14713 result = scf_transaction_commit(tx);
14701 14714
14702 14715 scf_transaction_reset(tx);
14703 14716 scf_entry_destroy_children(e);
14704 14717 } while (result == 0);
14705 14718
14706 14719 if (result < 0) {
14707 14720 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14708 14721 scfdie();
14709 14722
14710 14723 semerr(emsg_permission_denied);
14711 14724 goto fail;
14712 14725 }
14713 14726
14714 14727 result = 0;
14715 14728
14716 14729 private_refresh();
14717 14730
14718 14731 out:
14719 14732 scf_transaction_destroy(tx);
14720 14733 scf_entry_destroy(e);
14721 14734 scf_pg_destroy(pg);
14722 14735 scf_property_destroy(prop);
14723 14736 free(pattern);
14724 14737
14725 14738 while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14726 14739 free(sp->str);
14727 14740 free(sp);
14728 14741 }
14729 14742
14730 14743 uu_list_destroy(values);
14731 14744
14732 14745 return (result);
14733 14746
14734 14747 fail:
14735 14748 result = -1;
14736 14749 goto out;
14737 14750 }
14738 14751
14739 14752 int
14740 14753 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14741 14754 {
14742 14755 return (lscf_setpropvalue(pgname, type, value, 1, 0));
14743 14756 }
14744 14757
14745 14758 int
14746 14759 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14747 14760 {
14748 14761 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14749 14762 }
14750 14763
14751 14764 /*
14752 14765 * Look for a standard start method, first in the instance (if any),
14753 14766 * then the service.
14754 14767 */
14755 14768 static const char *
14756 14769 start_method_name(int *in_instance)
14757 14770 {
14758 14771 scf_propertygroup_t *pg;
14759 14772 char **p;
14760 14773 int ret;
14761 14774 scf_instance_t *inst = cur_inst;
14762 14775
14763 14776 if ((pg = scf_pg_create(g_hndl)) == NULL)
14764 14777 scfdie();
14765 14778
14766 14779 again:
14767 14780 for (p = start_method_names; *p != NULL; p++) {
14768 14781 if (inst != NULL)
14769 14782 ret = scf_instance_get_pg(inst, *p, pg);
14770 14783 else
14771 14784 ret = scf_service_get_pg(cur_svc, *p, pg);
14772 14785
14773 14786 if (ret == 0) {
14774 14787 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14775 14788 char *buf = safe_malloc(bufsz);
14776 14789
14777 14790 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14778 14791 free(buf);
14779 14792 continue;
14780 14793 }
14781 14794 if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14782 14795 free(buf);
14783 14796 continue;
14784 14797 }
14785 14798
14786 14799 free(buf);
14787 14800 *in_instance = (inst != NULL);
14788 14801 scf_pg_destroy(pg);
14789 14802 return (*p);
14790 14803 }
14791 14804
14792 14805 if (scf_error() == SCF_ERROR_NOT_FOUND)
14793 14806 continue;
14794 14807
14795 14808 scfdie();
14796 14809 }
14797 14810
14798 14811 if (inst != NULL) {
14799 14812 inst = NULL;
14800 14813 goto again;
14801 14814 }
14802 14815
14803 14816 scf_pg_destroy(pg);
14804 14817 return (NULL);
14805 14818 }
14806 14819
14807 14820 static int
14808 14821 addpg(const char *name, const char *type)
14809 14822 {
14810 14823 scf_propertygroup_t *pg;
14811 14824 int ret;
14812 14825
14813 14826 pg = scf_pg_create(g_hndl);
14814 14827 if (pg == NULL)
14815 14828 scfdie();
14816 14829
14817 14830 if (cur_inst != NULL)
14818 14831 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14819 14832 else
14820 14833 ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14821 14834
14822 14835 if (ret != 0) {
14823 14836 switch (scf_error()) {
14824 14837 case SCF_ERROR_EXISTS:
14825 14838 ret = 0;
14826 14839 break;
14827 14840
14828 14841 case SCF_ERROR_PERMISSION_DENIED:
14829 14842 semerr(emsg_permission_denied);
14830 14843 break;
14831 14844
14832 14845 default:
14833 14846 scfdie();
14834 14847 }
14835 14848 }
14836 14849
14837 14850 scf_pg_destroy(pg);
14838 14851 return (ret);
14839 14852 }
14840 14853
14841 14854 int
14842 14855 lscf_setenv(uu_list_t *args, int isunset)
14843 14856 {
14844 14857 int ret = 0;
14845 14858 size_t i;
14846 14859 int argc;
14847 14860 char **argv = NULL;
14848 14861 string_list_t *slp;
14849 14862 char *pattern;
14850 14863 char *prop;
14851 14864 int do_service = 0;
14852 14865 int do_instance = 0;
14853 14866 const char *method = NULL;
14854 14867 const char *name = NULL;
14855 14868 const char *value = NULL;
14856 14869 scf_instance_t *saved_cur_inst = cur_inst;
14857 14870
14858 14871 lscf_prep_hndl();
14859 14872
14860 14873 argc = uu_list_numnodes(args);
14861 14874 if (argc < 1)
14862 14875 goto usage;
14863 14876
14864 14877 argv = calloc(argc + 1, sizeof (char *));
14865 14878 if (argv == NULL)
14866 14879 uu_die(gettext("Out of memory.\n"));
14867 14880
14868 14881 for (slp = uu_list_first(args), i = 0;
14869 14882 slp != NULL;
14870 14883 slp = uu_list_next(args, slp), ++i)
14871 14884 argv[i] = slp->str;
14872 14885
14873 14886 argv[i] = NULL;
14874 14887
14875 14888 opterr = 0;
14876 14889 optind = 0;
14877 14890 for (;;) {
14878 14891 ret = getopt(argc, argv, "sim:");
14879 14892 if (ret == -1)
14880 14893 break;
14881 14894
14882 14895 switch (ret) {
14883 14896 case 's':
14884 14897 do_service = 1;
14885 14898 cur_inst = NULL;
14886 14899 break;
14887 14900
14888 14901 case 'i':
14889 14902 do_instance = 1;
14890 14903 break;
14891 14904
14892 14905 case 'm':
14893 14906 method = optarg;
14894 14907 break;
14895 14908
14896 14909 case '?':
14897 14910 goto usage;
14898 14911
14899 14912 default:
14900 14913 bad_error("getopt", ret);
14901 14914 }
14902 14915 }
14903 14916
14904 14917 argc -= optind;
14905 14918 if ((do_service && do_instance) ||
14906 14919 (isunset && argc != 1) ||
14907 14920 (!isunset && argc != 2))
14908 14921 goto usage;
14909 14922
14910 14923 name = argv[optind];
14911 14924 if (!isunset)
14912 14925 value = argv[optind + 1];
14913 14926
14914 14927 if (cur_snap != NULL) {
14915 14928 semerr(emsg_cant_modify_snapshots);
14916 14929 ret = -1;
14917 14930 goto out;
14918 14931 }
14919 14932
14920 14933 if (cur_inst == NULL && cur_svc == NULL) {
14921 14934 semerr(emsg_entity_not_selected);
14922 14935 ret = -1;
14923 14936 goto out;
14924 14937 }
14925 14938
14926 14939 if (do_instance && cur_inst == NULL) {
14927 14940 semerr(gettext("No instance is selected.\n"));
14928 14941 ret = -1;
14929 14942 goto out;
14930 14943 }
14931 14944
14932 14945 if (do_service && cur_svc == NULL) {
14933 14946 semerr(gettext("No service is selected.\n"));
14934 14947 ret = -1;
14935 14948 goto out;
14936 14949 }
14937 14950
14938 14951 if (method == NULL) {
14939 14952 if (do_instance || do_service) {
14940 14953 method = "method_context";
14941 14954 if (!isunset) {
14942 14955 ret = addpg("method_context",
14943 14956 SCF_GROUP_FRAMEWORK);
14944 14957 if (ret != 0)
14945 14958 goto out;
14946 14959 }
14947 14960 } else {
14948 14961 int in_instance;
14949 14962 method = start_method_name(&in_instance);
14950 14963 if (method == NULL) {
14951 14964 semerr(gettext(
14952 14965 "Couldn't find start method; please "
14953 14966 "specify a method with '-m'.\n"));
14954 14967 ret = -1;
14955 14968 goto out;
14956 14969 }
14957 14970 if (!in_instance)
14958 14971 cur_inst = NULL;
14959 14972 }
14960 14973 } else {
14961 14974 scf_propertygroup_t *pg;
14962 14975 size_t bufsz;
14963 14976 char *buf;
14964 14977 int ret;
14965 14978
14966 14979 if ((pg = scf_pg_create(g_hndl)) == NULL)
14967 14980 scfdie();
14968 14981
14969 14982 if (cur_inst != NULL)
14970 14983 ret = scf_instance_get_pg(cur_inst, method, pg);
14971 14984 else
14972 14985 ret = scf_service_get_pg(cur_svc, method, pg);
14973 14986
14974 14987 if (ret != 0) {
14975 14988 scf_pg_destroy(pg);
14976 14989 switch (scf_error()) {
14977 14990 case SCF_ERROR_NOT_FOUND:
14978 14991 semerr(gettext("Couldn't find the method "
14979 14992 "\"%s\".\n"), method);
14980 14993 goto out;
14981 14994
14982 14995 case SCF_ERROR_INVALID_ARGUMENT:
14983 14996 semerr(gettext("Invalid method name \"%s\".\n"),
14984 14997 method);
14985 14998 goto out;
14986 14999
14987 15000 default:
14988 15001 scfdie();
14989 15002 }
14990 15003 }
14991 15004
14992 15005 bufsz = strlen(SCF_GROUP_METHOD) + 1;
14993 15006 buf = safe_malloc(bufsz);
14994 15007
14995 15008 if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
14996 15009 strcmp(buf, SCF_GROUP_METHOD) != 0) {
14997 15010 semerr(gettext("Property group \"%s\" is not of type "
14998 15011 "\"method\".\n"), method);
14999 15012 ret = -1;
15000 15013 free(buf);
15001 15014 scf_pg_destroy(pg);
15002 15015 goto out;
15003 15016 }
15004 15017
15005 15018 free(buf);
15006 15019 scf_pg_destroy(pg);
15007 15020 }
15008 15021
15009 15022 prop = uu_msprintf("%s/environment", method);
15010 15023 pattern = uu_msprintf("%s=*", name);
15011 15024
15012 15025 if (prop == NULL || pattern == NULL)
15013 15026 uu_die(gettext("Out of memory.\n"));
15014 15027
15015 15028 ret = lscf_delpropvalue(prop, pattern, !isunset);
15016 15029
15017 15030 if (ret == 0 && !isunset) {
15018 15031 uu_free(pattern);
15019 15032 uu_free(prop);
15020 15033 prop = uu_msprintf("%s/environment", method);
15021 15034 pattern = uu_msprintf("%s=%s", name, value);
15022 15035 if (prop == NULL || pattern == NULL)
15023 15036 uu_die(gettext("Out of memory.\n"));
15024 15037 ret = lscf_addpropvalue(prop, "astring:", pattern);
15025 15038 }
15026 15039 uu_free(pattern);
15027 15040 uu_free(prop);
15028 15041
15029 15042 out:
15030 15043 cur_inst = saved_cur_inst;
15031 15044
15032 15045 free(argv);
15033 15046 return (ret);
15034 15047 usage:
15035 15048 ret = -2;
15036 15049 goto out;
15037 15050 }
15038 15051
15039 15052 /*
15040 15053 * Snapshot commands
15041 15054 */
15042 15055
15043 15056 void
15044 15057 lscf_listsnap()
15045 15058 {
15046 15059 scf_snapshot_t *snap;
15047 15060 scf_iter_t *iter;
15048 15061 char *nb;
15049 15062 int r;
15050 15063
15051 15064 lscf_prep_hndl();
15052 15065
15053 15066 if (cur_inst == NULL) {
15054 15067 semerr(gettext("Instance not selected.\n"));
15055 15068 return;
15056 15069 }
15057 15070
15058 15071 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15059 15072 (iter = scf_iter_create(g_hndl)) == NULL)
15060 15073 scfdie();
15061 15074
15062 15075 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15063 15076 scfdie();
15064 15077
15065 15078 nb = safe_malloc(max_scf_name_len + 1);
15066 15079
15067 15080 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15068 15081 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15069 15082 scfdie();
15070 15083
15071 15084 (void) puts(nb);
15072 15085 }
15073 15086 if (r < 0)
15074 15087 scfdie();
15075 15088
15076 15089 free(nb);
15077 15090 scf_iter_destroy(iter);
15078 15091 scf_snapshot_destroy(snap);
15079 15092 }
15080 15093
15081 15094 void
15082 15095 lscf_selectsnap(const char *name)
15083 15096 {
15084 15097 scf_snapshot_t *snap;
15085 15098 scf_snaplevel_t *level;
15086 15099
15087 15100 lscf_prep_hndl();
15088 15101
15089 15102 if (cur_inst == NULL) {
15090 15103 semerr(gettext("Instance not selected.\n"));
15091 15104 return;
15092 15105 }
15093 15106
15094 15107 if (cur_snap != NULL) {
15095 15108 if (name != NULL) {
15096 15109 char *cur_snap_name;
15097 15110 boolean_t nochange;
15098 15111
15099 15112 cur_snap_name = safe_malloc(max_scf_name_len + 1);
15100 15113
15101 15114 if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15102 15115 max_scf_name_len + 1) < 0)
15103 15116 scfdie();
15104 15117
15105 15118 nochange = strcmp(name, cur_snap_name) == 0;
15106 15119
15107 15120 free(cur_snap_name);
15108 15121
15109 15122 if (nochange)
15110 15123 return;
15111 15124 }
15112 15125
15113 15126 unselect_cursnap();
15114 15127 }
15115 15128
15116 15129 if (name == NULL)
15117 15130 return;
15118 15131
15119 15132 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15120 15133 (level = scf_snaplevel_create(g_hndl)) == NULL)
15121 15134 scfdie();
15122 15135
15123 15136 if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15124 15137 SCF_SUCCESS) {
15125 15138 switch (scf_error()) {
15126 15139 case SCF_ERROR_INVALID_ARGUMENT:
15127 15140 semerr(gettext("Invalid name \"%s\".\n"), name);
15128 15141 break;
15129 15142
15130 15143 case SCF_ERROR_NOT_FOUND:
15131 15144 semerr(gettext("No such snapshot \"%s\".\n"), name);
15132 15145 break;
15133 15146
15134 15147 default:
15135 15148 scfdie();
15136 15149 }
15137 15150
15138 15151 scf_snaplevel_destroy(level);
15139 15152 scf_snapshot_destroy(snap);
15140 15153 return;
15141 15154 }
15142 15155
15143 15156 /* Load the snaplevels into our list. */
15144 15157 cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15145 15158 if (cur_levels == NULL)
15146 15159 uu_die(gettext("Could not create list: %s\n"),
15147 15160 uu_strerror(uu_error()));
15148 15161
15149 15162 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15150 15163 if (scf_error() != SCF_ERROR_NOT_FOUND)
15151 15164 scfdie();
15152 15165
15153 15166 semerr(gettext("Snapshot has no snaplevels.\n"));
15154 15167
15155 15168 scf_snaplevel_destroy(level);
15156 15169 scf_snapshot_destroy(snap);
15157 15170 return;
15158 15171 }
15159 15172
15160 15173 cur_snap = snap;
15161 15174
15162 15175 for (;;) {
15163 15176 cur_elt = safe_malloc(sizeof (*cur_elt));
15164 15177 uu_list_node_init(cur_elt, &cur_elt->list_node,
15165 15178 snaplevel_pool);
15166 15179 cur_elt->sl = level;
15167 15180 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15168 15181 uu_die(gettext("libuutil error: %s\n"),
15169 15182 uu_strerror(uu_error()));
15170 15183
15171 15184 level = scf_snaplevel_create(g_hndl);
15172 15185 if (level == NULL)
15173 15186 scfdie();
15174 15187
15175 15188 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15176 15189 level) != SCF_SUCCESS) {
15177 15190 if (scf_error() != SCF_ERROR_NOT_FOUND)
15178 15191 scfdie();
15179 15192
15180 15193 scf_snaplevel_destroy(level);
15181 15194 break;
15182 15195 }
15183 15196 }
15184 15197
15185 15198 cur_elt = uu_list_last(cur_levels);
15186 15199 cur_level = cur_elt->sl;
15187 15200 }
15188 15201
15189 15202 /*
15190 15203 * Copies the properties & values in src to dst. Assumes src won't change.
15191 15204 * Returns -1 if permission is denied, -2 if another transaction interrupts,
15192 15205 * and 0 on success.
15193 15206 *
15194 15207 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15195 15208 * property, if it is copied and has type boolean. (See comment in
15196 15209 * lscf_revert()).
15197 15210 */
15198 15211 static int
15199 15212 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15200 15213 uint8_t enabled)
15201 15214 {
15202 15215 scf_transaction_t *tx;
15203 15216 scf_iter_t *iter, *viter;
15204 15217 scf_property_t *prop;
15205 15218 scf_value_t *v;
15206 15219 char *nbuf;
15207 15220 int r;
15208 15221
15209 15222 tx = scf_transaction_create(g_hndl);
15210 15223 if (tx == NULL)
15211 15224 scfdie();
15212 15225
15213 15226 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15214 15227 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15215 15228 scfdie();
15216 15229
15217 15230 scf_transaction_destroy(tx);
15218 15231
15219 15232 return (-1);
15220 15233 }
15221 15234
15222 15235 if ((iter = scf_iter_create(g_hndl)) == NULL ||
15223 15236 (prop = scf_property_create(g_hndl)) == NULL ||
15224 15237 (viter = scf_iter_create(g_hndl)) == NULL)
15225 15238 scfdie();
15226 15239
15227 15240 nbuf = safe_malloc(max_scf_name_len + 1);
15228 15241
15229 15242 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15230 15243 scfdie();
15231 15244
15232 15245 for (;;) {
15233 15246 scf_transaction_entry_t *e;
15234 15247 scf_type_t ty;
15235 15248
15236 15249 r = scf_iter_next_property(iter, prop);
15237 15250 if (r == -1)
15238 15251 scfdie();
15239 15252 if (r == 0)
15240 15253 break;
15241 15254
15242 15255 e = scf_entry_create(g_hndl);
15243 15256 if (e == NULL)
15244 15257 scfdie();
15245 15258
15246 15259 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15247 15260 scfdie();
15248 15261
15249 15262 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15250 15263 scfdie();
15251 15264
15252 15265 if (scf_transaction_property_new(tx, e, nbuf,
15253 15266 ty) != SCF_SUCCESS)
15254 15267 scfdie();
15255 15268
15256 15269 if ((enabled == 0 || enabled == 1) &&
15257 15270 strcmp(nbuf, scf_property_enabled) == 0 &&
15258 15271 ty == SCF_TYPE_BOOLEAN) {
15259 15272 v = scf_value_create(g_hndl);
15260 15273 if (v == NULL)
15261 15274 scfdie();
15262 15275
15263 15276 scf_value_set_boolean(v, enabled);
15264 15277
15265 15278 if (scf_entry_add_value(e, v) != 0)
15266 15279 scfdie();
15267 15280 } else {
15268 15281 if (scf_iter_property_values(viter, prop) != 0)
15269 15282 scfdie();
15270 15283
15271 15284 for (;;) {
15272 15285 v = scf_value_create(g_hndl);
15273 15286 if (v == NULL)
15274 15287 scfdie();
15275 15288
15276 15289 r = scf_iter_next_value(viter, v);
15277 15290 if (r == -1)
15278 15291 scfdie();
15279 15292 if (r == 0) {
15280 15293 scf_value_destroy(v);
15281 15294 break;
15282 15295 }
15283 15296
15284 15297 if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15285 15298 scfdie();
15286 15299 }
15287 15300 }
15288 15301 }
15289 15302
15290 15303 free(nbuf);
15291 15304 scf_iter_destroy(viter);
15292 15305 scf_property_destroy(prop);
15293 15306 scf_iter_destroy(iter);
15294 15307
15295 15308 r = scf_transaction_commit(tx);
15296 15309 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15297 15310 scfdie();
15298 15311
15299 15312 scf_transaction_destroy_children(tx);
15300 15313 scf_transaction_destroy(tx);
15301 15314
15302 15315 switch (r) {
15303 15316 case 1: return (0);
15304 15317 case 0: return (-2);
15305 15318 case -1: return (-1);
15306 15319
15307 15320 default:
15308 15321 abort();
15309 15322 }
15310 15323
15311 15324 /* NOTREACHED */
15312 15325 }
15313 15326
15314 15327 void
15315 15328 lscf_revert(const char *snapname)
15316 15329 {
15317 15330 scf_snapshot_t *snap, *prev;
15318 15331 scf_snaplevel_t *level, *nlevel;
15319 15332 scf_iter_t *iter;
15320 15333 scf_propertygroup_t *pg, *npg;
15321 15334 scf_property_t *prop;
15322 15335 scf_value_t *val;
15323 15336 char *nbuf, *tbuf;
15324 15337 uint8_t enabled;
15325 15338
15326 15339 lscf_prep_hndl();
15327 15340
15328 15341 if (cur_inst == NULL) {
15329 15342 semerr(gettext("Instance not selected.\n"));
15330 15343 return;
15331 15344 }
15332 15345
15333 15346 if (snapname != NULL) {
15334 15347 snap = scf_snapshot_create(g_hndl);
15335 15348 if (snap == NULL)
15336 15349 scfdie();
15337 15350
15338 15351 if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15339 15352 SCF_SUCCESS) {
15340 15353 switch (scf_error()) {
15341 15354 case SCF_ERROR_INVALID_ARGUMENT:
15342 15355 semerr(gettext("Invalid snapshot name "
15343 15356 "\"%s\".\n"), snapname);
15344 15357 break;
15345 15358
15346 15359 case SCF_ERROR_NOT_FOUND:
15347 15360 semerr(gettext("No such snapshot.\n"));
15348 15361 break;
15349 15362
15350 15363 default:
15351 15364 scfdie();
15352 15365 }
15353 15366
15354 15367 scf_snapshot_destroy(snap);
15355 15368 return;
15356 15369 }
15357 15370 } else {
15358 15371 if (cur_snap != NULL) {
15359 15372 snap = cur_snap;
15360 15373 } else {
15361 15374 semerr(gettext("No snapshot selected.\n"));
15362 15375 return;
15363 15376 }
15364 15377 }
15365 15378
15366 15379 if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15367 15380 (level = scf_snaplevel_create(g_hndl)) == NULL ||
15368 15381 (iter = scf_iter_create(g_hndl)) == NULL ||
15369 15382 (pg = scf_pg_create(g_hndl)) == NULL ||
15370 15383 (npg = scf_pg_create(g_hndl)) == NULL ||
15371 15384 (prop = scf_property_create(g_hndl)) == NULL ||
15372 15385 (val = scf_value_create(g_hndl)) == NULL)
15373 15386 scfdie();
15374 15387
15375 15388 nbuf = safe_malloc(max_scf_name_len + 1);
15376 15389 tbuf = safe_malloc(max_scf_pg_type_len + 1);
15377 15390
15378 15391 /* Take the "previous" snapshot before we blow away the properties. */
15379 15392 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15380 15393 if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15381 15394 scfdie();
15382 15395 } else {
15383 15396 if (scf_error() != SCF_ERROR_NOT_FOUND)
15384 15397 scfdie();
15385 15398
15386 15399 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15387 15400 scfdie();
15388 15401 }
15389 15402
15390 15403 /* Save general/enabled, since we're probably going to replace it. */
15391 15404 enabled = 2;
15392 15405 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15393 15406 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15394 15407 scf_property_get_value(prop, val) == 0)
15395 15408 (void) scf_value_get_boolean(val, &enabled);
15396 15409
15397 15410 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15398 15411 if (scf_error() != SCF_ERROR_NOT_FOUND)
15399 15412 scfdie();
15400 15413
15401 15414 goto out;
15402 15415 }
15403 15416
15404 15417 for (;;) {
15405 15418 boolean_t isinst;
15406 15419 uint32_t flags;
15407 15420 int r;
15408 15421
15409 15422 /* Clear the properties from the corresponding entity. */
15410 15423 isinst = snaplevel_is_instance(level);
15411 15424
15412 15425 if (!isinst)
15413 15426 r = scf_iter_service_pgs(iter, cur_svc);
15414 15427 else
15415 15428 r = scf_iter_instance_pgs(iter, cur_inst);
15416 15429 if (r != SCF_SUCCESS)
15417 15430 scfdie();
15418 15431
15419 15432 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15420 15433 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15421 15434 scfdie();
15422 15435
15423 15436 /* Skip nonpersistent pgs. */
15424 15437 if (flags & SCF_PG_FLAG_NONPERSISTENT)
15425 15438 continue;
15426 15439
15427 15440 if (scf_pg_delete(pg) != SCF_SUCCESS) {
15428 15441 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15429 15442 scfdie();
15430 15443
15431 15444 semerr(emsg_permission_denied);
15432 15445 goto out;
15433 15446 }
15434 15447 }
15435 15448 if (r == -1)
15436 15449 scfdie();
15437 15450
15438 15451 /* Copy the properties to the corresponding entity. */
15439 15452 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15440 15453 scfdie();
15441 15454
15442 15455 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15443 15456 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15444 15457 scfdie();
15445 15458
15446 15459 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15447 15460 0)
15448 15461 scfdie();
15449 15462
15450 15463 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15451 15464 scfdie();
15452 15465
15453 15466 if (!isinst)
15454 15467 r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15455 15468 flags, npg);
15456 15469 else
15457 15470 r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15458 15471 flags, npg);
15459 15472 if (r != SCF_SUCCESS) {
15460 15473 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15461 15474 scfdie();
15462 15475
15463 15476 semerr(emsg_permission_denied);
15464 15477 goto out;
15465 15478 }
15466 15479
15467 15480 if ((enabled == 0 || enabled == 1) &&
15468 15481 strcmp(nbuf, scf_pg_general) == 0)
15469 15482 r = pg_copy(pg, npg, enabled);
15470 15483 else
15471 15484 r = pg_copy(pg, npg, 2);
15472 15485
15473 15486 switch (r) {
15474 15487 case 0:
15475 15488 break;
15476 15489
15477 15490 case -1:
15478 15491 semerr(emsg_permission_denied);
15479 15492 goto out;
15480 15493
15481 15494 case -2:
15482 15495 semerr(gettext(
15483 15496 "Interrupted by another change.\n"));
15484 15497 goto out;
15485 15498
15486 15499 default:
15487 15500 abort();
15488 15501 }
15489 15502 }
15490 15503 if (r == -1)
15491 15504 scfdie();
15492 15505
15493 15506 /* Get next level. */
15494 15507 nlevel = scf_snaplevel_create(g_hndl);
15495 15508 if (nlevel == NULL)
15496 15509 scfdie();
15497 15510
15498 15511 if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15499 15512 SCF_SUCCESS) {
15500 15513 if (scf_error() != SCF_ERROR_NOT_FOUND)
15501 15514 scfdie();
15502 15515
15503 15516 scf_snaplevel_destroy(nlevel);
15504 15517 break;
15505 15518 }
15506 15519
15507 15520 scf_snaplevel_destroy(level);
15508 15521 level = nlevel;
15509 15522 }
15510 15523
15511 15524 if (snapname == NULL) {
15512 15525 lscf_selectsnap(NULL);
15513 15526 snap = NULL; /* cur_snap has been destroyed */
15514 15527 }
15515 15528
15516 15529 out:
15517 15530 free(tbuf);
15518 15531 free(nbuf);
15519 15532 scf_value_destroy(val);
15520 15533 scf_property_destroy(prop);
15521 15534 scf_pg_destroy(npg);
15522 15535 scf_pg_destroy(pg);
15523 15536 scf_iter_destroy(iter);
15524 15537 scf_snaplevel_destroy(level);
15525 15538 scf_snapshot_destroy(prev);
15526 15539 if (snap != cur_snap)
15527 15540 scf_snapshot_destroy(snap);
15528 15541 }
15529 15542
15530 15543 void
15531 15544 lscf_refresh(void)
15532 15545 {
15533 15546 ssize_t fmrilen;
15534 15547 size_t bufsz;
15535 15548 char *fmribuf;
15536 15549 int r;
15537 15550
15538 15551 lscf_prep_hndl();
15539 15552
15540 15553 if (cur_inst == NULL) {
15541 15554 semerr(gettext("Instance not selected.\n"));
15542 15555 return;
15543 15556 }
15544 15557
15545 15558 bufsz = max_scf_fmri_len + 1;
15546 15559 fmribuf = safe_malloc(bufsz);
15547 15560 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15548 15561 if (fmrilen < 0) {
15549 15562 free(fmribuf);
15550 15563 if (scf_error() != SCF_ERROR_DELETED)
15551 15564 scfdie();
15552 15565 scf_instance_destroy(cur_inst);
15553 15566 cur_inst = NULL;
15554 15567 warn(emsg_deleted);
15555 15568 return;
15556 15569 }
15557 15570 assert(fmrilen < bufsz);
15558 15571
15559 15572 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15560 15573 switch (r) {
15561 15574 case 0:
15562 15575 break;
15563 15576
15564 15577 case ECONNABORTED:
15565 15578 warn(gettext("Could not refresh %s "
15566 15579 "(repository connection broken).\n"), fmribuf);
15567 15580 break;
15568 15581
15569 15582 case ECANCELED:
15570 15583 warn(emsg_deleted);
15571 15584 break;
15572 15585
15573 15586 case EPERM:
15574 15587 warn(gettext("Could not refresh %s "
15575 15588 "(permission denied).\n"), fmribuf);
15576 15589 break;
15577 15590
15578 15591 case ENOSPC:
15579 15592 warn(gettext("Could not refresh %s "
15580 15593 "(repository server out of resources).\n"),
15581 15594 fmribuf);
15582 15595 break;
15583 15596
15584 15597 case EACCES:
15585 15598 default:
15586 15599 bad_error("refresh_entity", scf_error());
15587 15600 }
15588 15601
15589 15602 free(fmribuf);
15590 15603 }
15591 15604
15592 15605 /*
15593 15606 * describe [-v] [-t] [pg/prop]
15594 15607 */
15595 15608 int
15596 15609 lscf_describe(uu_list_t *args, int hasargs)
15597 15610 {
15598 15611 int ret = 0;
15599 15612 size_t i;
15600 15613 int argc;
15601 15614 char **argv = NULL;
15602 15615 string_list_t *slp;
15603 15616 int do_verbose = 0;
15604 15617 int do_templates = 0;
15605 15618 char *pattern = NULL;
15606 15619
15607 15620 lscf_prep_hndl();
15608 15621
15609 15622 if (hasargs != 0) {
15610 15623 argc = uu_list_numnodes(args);
15611 15624 if (argc < 1)
15612 15625 goto usage;
15613 15626
15614 15627 argv = calloc(argc + 1, sizeof (char *));
15615 15628 if (argv == NULL)
15616 15629 uu_die(gettext("Out of memory.\n"));
15617 15630
15618 15631 for (slp = uu_list_first(args), i = 0;
15619 15632 slp != NULL;
15620 15633 slp = uu_list_next(args, slp), ++i)
15621 15634 argv[i] = slp->str;
15622 15635
15623 15636 argv[i] = NULL;
15624 15637
15625 15638 /*
15626 15639 * We start optind = 0 because our list of arguments
15627 15640 * starts at argv[0]
15628 15641 */
15629 15642 optind = 0;
15630 15643 opterr = 0;
15631 15644 for (;;) {
15632 15645 ret = getopt(argc, argv, "vt");
15633 15646 if (ret == -1)
15634 15647 break;
15635 15648
15636 15649 switch (ret) {
15637 15650 case 'v':
15638 15651 do_verbose = 1;
15639 15652 break;
15640 15653
15641 15654 case 't':
15642 15655 do_templates = 1;
15643 15656 break;
15644 15657
15645 15658 case '?':
15646 15659 goto usage;
15647 15660
15648 15661 default:
15649 15662 bad_error("getopt", ret);
15650 15663 }
15651 15664 }
15652 15665
15653 15666 pattern = argv[optind];
15654 15667 }
15655 15668
15656 15669 if (cur_inst == NULL && cur_svc == NULL) {
15657 15670 semerr(emsg_entity_not_selected);
15658 15671 ret = -1;
15659 15672 goto out;
15660 15673 }
15661 15674
15662 15675 /*
15663 15676 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15664 15677 * output if their last parameter is set to 2. Less information is
15665 15678 * produced if the parameter is set to 1.
15666 15679 */
15667 15680 if (pattern == NULL) {
15668 15681 if (do_verbose == 1)
15669 15682 list_entity_tmpl(2);
15670 15683 else
15671 15684 list_entity_tmpl(1);
15672 15685 }
15673 15686
15674 15687 if (do_templates == 0) {
15675 15688 if (do_verbose == 1)
15676 15689 listprop(pattern, 0, 2);
15677 15690 else
15678 15691 listprop(pattern, 0, 1);
15679 15692 } else {
15680 15693 if (do_verbose == 1)
15681 15694 listtmpl(pattern, 2);
15682 15695 else
15683 15696 listtmpl(pattern, 1);
15684 15697 }
15685 15698
15686 15699 ret = 0;
15687 15700 out:
15688 15701 if (argv != NULL)
15689 15702 free(argv);
15690 15703 return (ret);
15691 15704 usage:
15692 15705 ret = -2;
15693 15706 goto out;
15694 15707 }
15695 15708
15696 15709 #define PARAM_ACTIVE ((const char *) "active")
15697 15710 #define PARAM_INACTIVE ((const char *) "inactive")
15698 15711 #define PARAM_SMTP_TO ((const char *) "to")
15699 15712
15700 15713 /*
15701 15714 * tokenize()
15702 15715 * Breaks down the string according to the tokens passed.
15703 15716 * Caller is responsible for freeing array of pointers returned.
15704 15717 * Returns NULL on failure
15705 15718 */
15706 15719 char **
15707 15720 tokenize(char *str, const char *sep)
15708 15721 {
15709 15722 char *token, *lasts;
15710 15723 char **buf;
15711 15724 int n = 0; /* number of elements */
15712 15725 int size = 8; /* size of the array (initial) */
15713 15726
15714 15727 buf = safe_malloc(size * sizeof (char *));
15715 15728
15716 15729 for (token = strtok_r(str, sep, &lasts); token != NULL;
15717 15730 token = strtok_r(NULL, sep, &lasts), ++n) {
15718 15731 if (n + 1 >= size) {
15719 15732 size *= 2;
15720 15733 if ((buf = realloc(buf, size * sizeof (char *))) ==
15721 15734 NULL) {
15722 15735 uu_die(gettext("Out of memory"));
15723 15736 }
15724 15737 }
15725 15738 buf[n] = token;
15726 15739 }
15727 15740 /* NULL terminate the pointer array */
15728 15741 buf[n] = NULL;
15729 15742
15730 15743 return (buf);
15731 15744 }
15732 15745
15733 15746 int32_t
15734 15747 check_tokens(char **p)
15735 15748 {
15736 15749 int32_t smf = 0;
15737 15750 int32_t fma = 0;
15738 15751
15739 15752 while (*p) {
15740 15753 int32_t t = string_to_tset(*p);
15741 15754
15742 15755 if (t == 0) {
15743 15756 if (is_fma_token(*p) == 0)
15744 15757 return (INVALID_TOKENS);
15745 15758 fma = 1; /* this token is an fma event */
15746 15759 } else {
15747 15760 smf |= t;
15748 15761 }
15749 15762
15750 15763 if (smf != 0 && fma == 1)
15751 15764 return (MIXED_TOKENS);
15752 15765 ++p;
15753 15766 }
15754 15767
15755 15768 if (smf > 0)
15756 15769 return (smf);
15757 15770 else if (fma == 1)
15758 15771 return (FMA_TOKENS);
15759 15772
15760 15773 return (INVALID_TOKENS);
15761 15774 }
15762 15775
15763 15776 static int
15764 15777 get_selection_str(char *fmri, size_t sz)
15765 15778 {
15766 15779 if (g_hndl == NULL) {
15767 15780 semerr(emsg_entity_not_selected);
15768 15781 return (-1);
15769 15782 } else if (cur_level != NULL) {
15770 15783 semerr(emsg_invalid_for_snapshot);
15771 15784 return (-1);
15772 15785 } else {
15773 15786 lscf_get_selection_str(fmri, sz);
15774 15787 }
15775 15788
15776 15789 return (0);
15777 15790 }
15778 15791
15779 15792 void
15780 15793 lscf_delnotify(const char *set, int global)
15781 15794 {
15782 15795 char *str = strdup(set);
15783 15796 char **pgs;
15784 15797 char **p;
15785 15798 int32_t tset;
15786 15799 char *fmri = NULL;
15787 15800
15788 15801 if (str == NULL)
15789 15802 uu_die(gettext("Out of memory.\n"));
15790 15803
15791 15804 pgs = tokenize(str, ",");
15792 15805
15793 15806 if ((tset = check_tokens(pgs)) > 0) {
15794 15807 size_t sz = max_scf_fmri_len + 1;
15795 15808
15796 15809 fmri = safe_malloc(sz);
15797 15810 if (global) {
15798 15811 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15799 15812 } else if (get_selection_str(fmri, sz) != 0) {
15800 15813 goto out;
15801 15814 }
15802 15815
15803 15816 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15804 15817 tset) != SCF_SUCCESS) {
15805 15818 uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15806 15819 scf_strerror(scf_error()));
15807 15820 }
15808 15821 } else if (tset == FMA_TOKENS) {
15809 15822 if (global) {
15810 15823 semerr(gettext("Can't use option '-g' with FMA event "
15811 15824 "definitions\n"));
15812 15825 goto out;
15813 15826 }
15814 15827
15815 15828 for (p = pgs; *p; ++p) {
15816 15829 if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15817 15830 SCF_SUCCESS) {
15818 15831 uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15819 15832 scf_strerror(scf_error()));
15820 15833 goto out;
15821 15834 }
15822 15835 }
15823 15836 } else if (tset == MIXED_TOKENS) {
15824 15837 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15825 15838 goto out;
15826 15839 } else {
15827 15840 uu_die(gettext("Invalid input.\n"));
15828 15841 }
15829 15842
15830 15843 out:
15831 15844 free(fmri);
15832 15845 free(pgs);
15833 15846 free(str);
15834 15847 }
15835 15848
15836 15849 void
15837 15850 lscf_listnotify(const char *set, int global)
15838 15851 {
15839 15852 char *str = safe_strdup(set);
15840 15853 char **pgs;
15841 15854 char **p;
15842 15855 int32_t tset;
15843 15856 nvlist_t *nvl;
15844 15857 char *fmri = NULL;
15845 15858
15846 15859 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15847 15860 uu_die(gettext("Out of memory.\n"));
15848 15861
15849 15862 pgs = tokenize(str, ",");
15850 15863
15851 15864 if ((tset = check_tokens(pgs)) > 0) {
15852 15865 size_t sz = max_scf_fmri_len + 1;
15853 15866
15854 15867 fmri = safe_malloc(sz);
15855 15868 if (global) {
15856 15869 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15857 15870 } else if (get_selection_str(fmri, sz) != 0) {
15858 15871 goto out;
15859 15872 }
15860 15873
15861 15874 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15862 15875 SCF_SUCCESS) {
15863 15876 if (scf_error() != SCF_ERROR_NOT_FOUND &&
15864 15877 scf_error() != SCF_ERROR_DELETED)
15865 15878 uu_warn(gettext(
15866 15879 "Failed listnotify: %s\n"),
15867 15880 scf_strerror(scf_error()));
15868 15881 goto out;
15869 15882 }
15870 15883
15871 15884 listnotify_print(nvl, NULL);
15872 15885 } else if (tset == FMA_TOKENS) {
15873 15886 if (global) {
15874 15887 semerr(gettext("Can't use option '-g' with FMA event "
15875 15888 "definitions\n"));
15876 15889 goto out;
15877 15890 }
15878 15891
15879 15892 for (p = pgs; *p; ++p) {
15880 15893 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15881 15894 SCF_SUCCESS) {
15882 15895 /*
15883 15896 * if the preferences have just been deleted
15884 15897 * or does not exist, just skip.
15885 15898 */
15886 15899 if (scf_error() == SCF_ERROR_NOT_FOUND ||
15887 15900 scf_error() == SCF_ERROR_DELETED)
15888 15901 continue;
15889 15902 uu_warn(gettext(
15890 15903 "Failed listnotify: %s\n"),
15891 15904 scf_strerror(scf_error()));
15892 15905 goto out;
15893 15906 }
15894 15907 listnotify_print(nvl, re_tag(*p));
15895 15908 }
15896 15909 } else if (tset == MIXED_TOKENS) {
15897 15910 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15898 15911 goto out;
15899 15912 } else {
15900 15913 semerr(gettext("Invalid input.\n"));
15901 15914 }
15902 15915
15903 15916 out:
15904 15917 nvlist_free(nvl);
15905 15918 free(fmri);
15906 15919 free(pgs);
15907 15920 free(str);
15908 15921 }
15909 15922
15910 15923 static char *
15911 15924 strip_quotes_and_blanks(char *s)
15912 15925 {
15913 15926 char *start = s;
15914 15927 char *end = strrchr(s, '\"');
15915 15928
15916 15929 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15917 15930 start = s + 1;
15918 15931 while (isblank(*start))
15919 15932 start++;
15920 15933 while (isblank(*(end - 1)) && end > start) {
15921 15934 end--;
15922 15935 }
15923 15936 *end = '\0';
15924 15937 }
15925 15938
15926 15939 return (start);
15927 15940 }
15928 15941
15929 15942 static int
15930 15943 set_active(nvlist_t *mech, const char *hier_part)
15931 15944 {
15932 15945 boolean_t b;
15933 15946
15934 15947 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15935 15948 b = B_TRUE;
15936 15949 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15937 15950 b = B_FALSE;
15938 15951 } else {
15939 15952 return (-1);
15940 15953 }
15941 15954
15942 15955 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15943 15956 uu_die(gettext("Out of memory.\n"));
15944 15957
15945 15958 return (0);
15946 15959 }
15947 15960
15948 15961 static int
15949 15962 add_snmp_params(nvlist_t *mech, char *hier_part)
15950 15963 {
15951 15964 return (set_active(mech, hier_part));
15952 15965 }
15953 15966
15954 15967 static int
15955 15968 add_syslog_params(nvlist_t *mech, char *hier_part)
15956 15969 {
15957 15970 return (set_active(mech, hier_part));
15958 15971 }
15959 15972
15960 15973 /*
15961 15974 * add_mailto_paramas()
15962 15975 * parse the hier_part of mailto URI
15963 15976 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15964 15977 * or mailto:{[active]|inactive}
15965 15978 */
15966 15979 static int
15967 15980 add_mailto_params(nvlist_t *mech, char *hier_part)
15968 15981 {
15969 15982 const char *tok = "?&";
15970 15983 char *p;
15971 15984 char *lasts;
15972 15985 char *param;
15973 15986 char *val;
15974 15987
15975 15988 /*
15976 15989 * If the notification parametes are in the form of
15977 15990 *
15978 15991 * malito:{[active]|inactive}
15979 15992 *
15980 15993 * we set the property accordingly and return.
15981 15994 * Otherwise, we make the notification type active and
15982 15995 * process the hier_part.
15983 15996 */
15984 15997 if (set_active(mech, hier_part) == 0)
15985 15998 return (0);
15986 15999 else if (set_active(mech, PARAM_ACTIVE) != 0)
15987 16000 return (-1);
15988 16001
15989 16002 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
15990 16003 /*
15991 16004 * sanity check: we only get here if hier_part = "", but
15992 16005 * that's handled by set_active
15993 16006 */
15994 16007 uu_die("strtok_r");
15995 16008 }
15996 16009
15997 16010 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
15998 16011 uu_die(gettext("Out of memory.\n"));
15999 16012
16000 16013 while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16001 16014 if ((param = strtok_r(p, "=", &val)) != NULL)
16002 16015 if (nvlist_add_string(mech, param, val) != 0)
16003 16016 uu_die(gettext("Out of memory.\n"));
16004 16017
16005 16018 return (0);
16006 16019 }
16007 16020
16008 16021 static int
16009 16022 uri_split(char *uri, char **scheme, char **hier_part)
16010 16023 {
16011 16024 int r = -1;
16012 16025
16013 16026 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16014 16027 *hier_part == NULL) {
16015 16028 semerr(gettext("'%s' is not an URI\n"), uri);
16016 16029 return (r);
16017 16030 }
16018 16031
16019 16032 if ((r = check_uri_scheme(*scheme)) < 0) {
16020 16033 semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16021 16034 return (r);
16022 16035 }
16023 16036
16024 16037 return (r);
16025 16038 }
16026 16039
16027 16040 static int
16028 16041 process_uri(nvlist_t *params, char *uri)
16029 16042 {
16030 16043 char *scheme;
16031 16044 char *hier_part;
16032 16045 nvlist_t *mech;
16033 16046 int index;
16034 16047 int r;
16035 16048
16036 16049 if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16037 16050 return (-1);
16038 16051
16039 16052 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16040 16053 uu_die(gettext("Out of memory.\n"));
16041 16054
16042 16055 switch (index) {
16043 16056 case 0:
16044 16057 /* error messages displayed by called function */
16045 16058 r = add_mailto_params(mech, hier_part);
16046 16059 break;
16047 16060
16048 16061 case 1:
16049 16062 if ((r = add_snmp_params(mech, hier_part)) != 0)
16050 16063 semerr(gettext("Not valid parameters: '%s'\n"),
16051 16064 hier_part);
16052 16065 break;
16053 16066
16054 16067 case 2:
16055 16068 if ((r = add_syslog_params(mech, hier_part)) != 0)
16056 16069 semerr(gettext("Not valid parameters: '%s'\n"),
16057 16070 hier_part);
16058 16071 break;
16059 16072
16060 16073 default:
16061 16074 r = -1;
16062 16075 }
16063 16076
16064 16077 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16065 16078 mech) != 0)
16066 16079 uu_die(gettext("Out of memory.\n"));
16067 16080
16068 16081 nvlist_free(mech);
16069 16082 return (r);
16070 16083 }
16071 16084
16072 16085 static int
16073 16086 set_params(nvlist_t *params, char **p)
16074 16087 {
16075 16088 char *uri;
16076 16089
16077 16090 if (p == NULL)
16078 16091 /* sanity check */
16079 16092 uu_die("set_params");
16080 16093
16081 16094 while (*p) {
16082 16095 uri = strip_quotes_and_blanks(*p);
16083 16096 if (process_uri(params, uri) != 0)
16084 16097 return (-1);
16085 16098
16086 16099 ++p;
16087 16100 }
16088 16101
16089 16102 return (0);
16090 16103 }
16091 16104
16092 16105 static int
16093 16106 setnotify(const char *e, char **p, int global)
16094 16107 {
16095 16108 char *str = safe_strdup(e);
16096 16109 char **events;
16097 16110 int32_t tset;
16098 16111 int r = -1;
16099 16112 nvlist_t *nvl, *params;
16100 16113 char *fmri = NULL;
16101 16114
16102 16115 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16103 16116 nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 ||
16104 16117 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16105 16118 SCF_NOTIFY_PARAMS_VERSION) != 0)
16106 16119 uu_die(gettext("Out of memory.\n"));
16107 16120
16108 16121 events = tokenize(str, ",");
16109 16122
16110 16123 if ((tset = check_tokens(events)) > 0) {
16111 16124 /* SMF state transitions parameters */
16112 16125 size_t sz = max_scf_fmri_len + 1;
16113 16126
16114 16127 fmri = safe_malloc(sz);
16115 16128 if (global) {
16116 16129 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16117 16130 } else if (get_selection_str(fmri, sz) != 0) {
16118 16131 goto out;
16119 16132 }
16120 16133
16121 16134 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16122 16135 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16123 16136 uu_die(gettext("Out of memory.\n"));
16124 16137
16125 16138 if ((r = set_params(params, p)) == 0) {
16126 16139 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16127 16140 params) != 0)
16128 16141 uu_die(gettext("Out of memory.\n"));
16129 16142
16130 16143 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16131 16144 nvl) != SCF_SUCCESS) {
16132 16145 r = -1;
16133 16146 uu_warn(gettext(
16134 16147 "Failed smf_notify_set_params(3SCF): %s\n"),
16135 16148 scf_strerror(scf_error()));
16136 16149 }
16137 16150 }
16138 16151 } else if (tset == FMA_TOKENS) {
16139 16152 /* FMA event parameters */
16140 16153 if (global) {
16141 16154 semerr(gettext("Can't use option '-g' with FMA event "
16142 16155 "definitions\n"));
16143 16156 goto out;
16144 16157 }
16145 16158
16146 16159 if ((r = set_params(params, p)) != 0)
16147 16160 goto out;
16148 16161
16149 16162 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16150 16163 uu_die(gettext("Out of memory.\n"));
16151 16164
16152 16165 while (*events) {
16153 16166 if (smf_notify_set_params(de_tag(*events), nvl) !=
16154 16167 SCF_SUCCESS)
16155 16168 uu_warn(gettext(
16156 16169 "Failed smf_notify_set_params(3SCF) for "
16157 16170 "event %s: %s\n"), *events,
16158 16171 scf_strerror(scf_error()));
16159 16172 events++;
16160 16173 }
16161 16174 } else if (tset == MIXED_TOKENS) {
16162 16175 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16163 16176 } else {
16164 16177 /* Sanity check */
16165 16178 uu_die(gettext("Invalid input.\n"));
16166 16179 }
16167 16180
16168 16181 out:
16169 16182 nvlist_free(nvl);
16170 16183 nvlist_free(params);
16171 16184 free(fmri);
16172 16185 free(str);
16173 16186
16174 16187 return (r);
16175 16188 }
16176 16189
16177 16190 int
16178 16191 lscf_setnotify(uu_list_t *args)
16179 16192 {
16180 16193 int argc;
16181 16194 char **argv = NULL;
16182 16195 string_list_t *slp;
16183 16196 int global;
16184 16197 char *events;
16185 16198 char **p;
16186 16199 int i;
16187 16200 int ret;
16188 16201
16189 16202 if ((argc = uu_list_numnodes(args)) < 2)
16190 16203 goto usage;
16191 16204
16192 16205 argv = calloc(argc + 1, sizeof (char *));
16193 16206 if (argv == NULL)
16194 16207 uu_die(gettext("Out of memory.\n"));
16195 16208
16196 16209 for (slp = uu_list_first(args), i = 0;
16197 16210 slp != NULL;
16198 16211 slp = uu_list_next(args, slp), ++i)
16199 16212 argv[i] = slp->str;
16200 16213
16201 16214 argv[i] = NULL;
16202 16215
16203 16216 if (strcmp(argv[0], "-g") == 0) {
16204 16217 global = 1;
16205 16218 events = argv[1];
16206 16219 p = argv + 2;
16207 16220 } else {
16208 16221 global = 0;
16209 16222 events = argv[0];
16210 16223 p = argv + 1;
16211 16224 }
16212 16225
16213 16226 ret = setnotify(events, p, global);
16214 16227
16215 16228 out:
16216 16229 free(argv);
16217 16230 return (ret);
16218 16231
16219 16232 usage:
16220 16233 ret = -2;
16221 16234 goto out;
16222 16235 }
16223 16236
16224 16237 /*
16225 16238 * Creates a list of instance name strings associated with a service. If
16226 16239 * wohandcrafted flag is set, get only instances that have a last-import
16227 16240 * snapshot, instances that were imported via svccfg.
16228 16241 */
16229 16242 static uu_list_t *
16230 16243 create_instance_list(scf_service_t *svc, int wohandcrafted)
16231 16244 {
16232 16245 scf_snapshot_t *snap = NULL;
16233 16246 scf_instance_t *inst;
16234 16247 scf_iter_t *inst_iter;
16235 16248 uu_list_t *instances;
16236 16249 char *instname;
16237 16250 int r;
16238 16251
16239 16252 inst_iter = scf_iter_create(g_hndl);
16240 16253 inst = scf_instance_create(g_hndl);
16241 16254 if (inst_iter == NULL || inst == NULL) {
16242 16255 uu_warn(gettext("Could not create instance or iterator\n"));
16243 16256 scfdie();
16244 16257 }
16245 16258
16246 16259 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16247 16260 return (instances);
16248 16261
16249 16262 if (scf_iter_service_instances(inst_iter, svc) != 0) {
16250 16263 switch (scf_error()) {
16251 16264 case SCF_ERROR_CONNECTION_BROKEN:
16252 16265 case SCF_ERROR_DELETED:
16253 16266 uu_list_destroy(instances);
16254 16267 instances = NULL;
16255 16268 goto out;
16256 16269
16257 16270 case SCF_ERROR_HANDLE_MISMATCH:
16258 16271 case SCF_ERROR_NOT_BOUND:
16259 16272 case SCF_ERROR_NOT_SET:
16260 16273 default:
16261 16274 bad_error("scf_iter_service_instances", scf_error());
16262 16275 }
16263 16276 }
16264 16277
16265 16278 instname = safe_malloc(max_scf_name_len + 1);
16266 16279 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16267 16280 if (r == -1) {
16268 16281 (void) uu_warn(gettext("Unable to iterate through "
16269 16282 "instances to create instance list : %s\n"),
16270 16283 scf_strerror(scf_error()));
16271 16284
16272 16285 uu_list_destroy(instances);
16273 16286 instances = NULL;
16274 16287 goto out;
16275 16288 }
16276 16289
16277 16290 /*
16278 16291 * If the instance does not have a last-import snapshot
16279 16292 * then do not add it to the list as it is a hand-crafted
16280 16293 * instance that should not be managed.
16281 16294 */
16282 16295 if (wohandcrafted) {
16283 16296 if (snap == NULL &&
16284 16297 (snap = scf_snapshot_create(g_hndl)) == NULL) {
16285 16298 uu_warn(gettext("Unable to create snapshot "
16286 16299 "entity\n"));
16287 16300 scfdie();
16288 16301 }
16289 16302
16290 16303 if (scf_instance_get_snapshot(inst,
16291 16304 snap_lastimport, snap) != 0) {
16292 16305 switch (scf_error()) {
16293 16306 case SCF_ERROR_NOT_FOUND :
16294 16307 case SCF_ERROR_DELETED:
16295 16308 continue;
16296 16309
16297 16310 case SCF_ERROR_CONNECTION_BROKEN:
16298 16311 uu_list_destroy(instances);
16299 16312 instances = NULL;
16300 16313 goto out;
16301 16314
16302 16315 case SCF_ERROR_HANDLE_MISMATCH:
16303 16316 case SCF_ERROR_NOT_BOUND:
16304 16317 case SCF_ERROR_NOT_SET:
16305 16318 default:
16306 16319 bad_error("scf_iter_service_instances",
16307 16320 scf_error());
16308 16321 }
16309 16322 }
16310 16323 }
16311 16324
16312 16325 if (scf_instance_get_name(inst, instname,
16313 16326 max_scf_name_len + 1) < 0) {
16314 16327 switch (scf_error()) {
16315 16328 case SCF_ERROR_NOT_FOUND :
16316 16329 continue;
16317 16330
16318 16331 case SCF_ERROR_CONNECTION_BROKEN:
16319 16332 case SCF_ERROR_DELETED:
16320 16333 uu_list_destroy(instances);
16321 16334 instances = NULL;
16322 16335 goto out;
16323 16336
16324 16337 case SCF_ERROR_HANDLE_MISMATCH:
16325 16338 case SCF_ERROR_NOT_BOUND:
16326 16339 case SCF_ERROR_NOT_SET:
16327 16340 default:
16328 16341 bad_error("scf_iter_service_instances",
16329 16342 scf_error());
16330 16343 }
16331 16344 }
16332 16345
16333 16346 add_string(instances, instname);
16334 16347 }
16335 16348
16336 16349 out:
16337 16350 if (snap)
16338 16351 scf_snapshot_destroy(snap);
16339 16352
16340 16353 scf_instance_destroy(inst);
16341 16354 scf_iter_destroy(inst_iter);
16342 16355 free(instname);
16343 16356 return (instances);
16344 16357 }
16345 16358
16346 16359 /*
16347 16360 * disable an instance but wait for the instance to
16348 16361 * move out of the running state.
16349 16362 *
16350 16363 * Returns 0 : if the instance did not disable
16351 16364 * Returns non-zero : if the instance disabled.
16352 16365 *
16353 16366 */
16354 16367 static int
16355 16368 disable_instance(scf_instance_t *instance)
16356 16369 {
16357 16370 char *fmribuf;
16358 16371 int enabled = 10000;
16359 16372
16360 16373 if (inst_is_running(instance)) {
16361 16374 fmribuf = safe_malloc(max_scf_name_len + 1);
16362 16375 if (scf_instance_to_fmri(instance, fmribuf,
16363 16376 max_scf_name_len + 1) < 0) {
16364 16377 free(fmribuf);
16365 16378 return (0);
16366 16379 }
16367 16380
16368 16381 /*
16369 16382 * If the instance cannot be disabled then return
16370 16383 * failure to disable and let the caller decide
16371 16384 * if that is of importance.
16372 16385 */
16373 16386 if (smf_disable_instance(fmribuf, 0) != 0) {
16374 16387 free(fmribuf);
16375 16388 return (0);
16376 16389 }
16377 16390
16378 16391 while (enabled) {
16379 16392 if (!inst_is_running(instance))
16380 16393 break;
16381 16394
16382 16395 (void) poll(NULL, 0, 5);
16383 16396 enabled = enabled - 5;
16384 16397 }
16385 16398
16386 16399 free(fmribuf);
16387 16400 }
16388 16401
16389 16402 return (enabled);
16390 16403 }
16391 16404
16392 16405 /*
16393 16406 * Function to compare two service_manifest structures.
16394 16407 */
16395 16408 /* ARGSUSED2 */
16396 16409 static int
16397 16410 service_manifest_compare(const void *left, const void *right, void *unused)
16398 16411 {
16399 16412 service_manifest_t *l = (service_manifest_t *)left;
16400 16413 service_manifest_t *r = (service_manifest_t *)right;
16401 16414 int rc;
16402 16415
16403 16416 rc = strcmp(l->servicename, r->servicename);
16404 16417
16405 16418 return (rc);
16406 16419 }
16407 16420
16408 16421 /*
16409 16422 * Look for the provided service in the service to manifest
16410 16423 * tree. If the service exists, and a manifest was provided
16411 16424 * then add the manifest to that service. If the service
16412 16425 * does not exist, then add the service and manifest to the
16413 16426 * list.
16414 16427 *
16415 16428 * If the manifest is NULL, return the element if found. If
16416 16429 * the service is not found return NULL.
16417 16430 */
16418 16431 service_manifest_t *
16419 16432 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16420 16433 {
16421 16434 service_manifest_t elem;
16422 16435 service_manifest_t *fnelem;
16423 16436 uu_avl_index_t marker;
16424 16437
16425 16438 elem.servicename = svnbuf;
16426 16439 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16427 16440
16428 16441 if (mfst) {
16429 16442 if (fnelem) {
16430 16443 add_string(fnelem->mfstlist, strdup(mfst));
16431 16444 } else {
16432 16445 fnelem = safe_malloc(sizeof (*fnelem));
16433 16446 fnelem->servicename = safe_strdup(svnbuf);
16434 16447 if ((fnelem->mfstlist =
16435 16448 uu_list_create(string_pool, NULL, 0)) == NULL)
16436 16449 uu_die(gettext("Could not create property "
16437 16450 "list: %s\n"), uu_strerror(uu_error()));
16438 16451
16439 16452 add_string(fnelem->mfstlist, safe_strdup(mfst));
16440 16453
16441 16454 uu_avl_insert(service_manifest_tree, fnelem, marker);
16442 16455 }
16443 16456 }
16444 16457
16445 16458 return (fnelem);
16446 16459 }
16447 16460
16448 16461 /*
16449 16462 * Create the service to manifest avl tree.
16450 16463 *
16451 16464 * Walk each of the manifests currently installed in the supported
16452 16465 * directories, /lib/svc/manifests and /var/svc/manifests. For
16453 16466 * each of the manifests, inventory the services and add them to
16454 16467 * the tree.
16455 16468 *
16456 16469 * Code that calls this function should make sure fileystem/minimal is online,
16457 16470 * /var is available, since this function walks the /var/svc/manifest directory.
16458 16471 */
16459 16472 static void
16460 16473 create_manifest_tree(void)
16461 16474 {
16462 16475 manifest_info_t **entry;
16463 16476 manifest_info_t **manifests;
16464 16477 uu_list_walk_t *svcs;
16465 16478 bundle_t *b;
16466 16479 entity_t *mfsvc;
16467 16480 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16468 16481 int c, status;
16469 16482
16470 16483 if (service_manifest_pool)
16471 16484 return;
16472 16485
16473 16486 /*
16474 16487 * Create the list pool for the service manifest list
16475 16488 */
16476 16489 service_manifest_pool = uu_avl_pool_create("service_manifest",
16477 16490 sizeof (service_manifest_t),
16478 16491 offsetof(service_manifest_t, svcmfst_node),
16479 16492 service_manifest_compare, UU_DEFAULT);
16480 16493 if (service_manifest_pool == NULL)
16481 16494 uu_die(gettext("service_manifest pool creation failed: %s\n"),
16482 16495 uu_strerror(uu_error()));
16483 16496
16484 16497 /*
16485 16498 * Create the list
16486 16499 */
16487 16500 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16488 16501 UU_DEFAULT);
16489 16502 if (service_manifest_tree == NULL)
16490 16503 uu_die(gettext("service_manifest tree creation failed: %s\n"),
16491 16504 uu_strerror(uu_error()));
16492 16505
16493 16506 /*
16494 16507 * Walk the manifests adding the service(s) from each manifest.
16495 16508 *
16496 16509 * If a service already exists add the manifest to the manifest
16497 16510 * list for that service. This covers the case of a service that
16498 16511 * is supported by multiple manifest files.
16499 16512 */
16500 16513 for (c = 0; dirs[c]; c++) {
16501 16514 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16502 16515 if (status < 0) {
16503 16516 uu_warn(gettext("file tree walk of %s encountered "
16504 16517 "error %s\n"), dirs[c], strerror(errno));
16505 16518
16506 16519 uu_avl_destroy(service_manifest_tree);
16507 16520 service_manifest_tree = NULL;
16508 16521 return;
16509 16522 }
16510 16523
16511 16524 /*
16512 16525 * If a manifest that was in the list is not found
16513 16526 * then skip and go to the next manifest file.
16514 16527 */
16515 16528 if (manifests != NULL) {
16516 16529 for (entry = manifests; *entry != NULL; entry++) {
16517 16530 b = internal_bundle_new();
16518 16531 if (lxml_get_bundle_file(b, (*entry)->mi_path,
16519 16532 SVCCFG_OP_IMPORT) != 0) {
16520 16533 internal_bundle_free(b);
16521 16534 continue;
16522 16535 }
16523 16536
16524 16537 svcs = uu_list_walk_start(b->sc_bundle_services,
16525 16538 0);
16526 16539 if (svcs == NULL) {
16527 16540 internal_bundle_free(b);
16528 16541 continue;
16529 16542 }
16530 16543
16531 16544 while ((mfsvc = uu_list_walk_next(svcs)) !=
16532 16545 NULL) {
16533 16546 /* Add manifest to service */
16534 16547 (void) find_add_svc_mfst(mfsvc->sc_name,
16535 16548 (*entry)->mi_path);
16536 16549 }
16537 16550
16538 16551 uu_list_walk_end(svcs);
16539 16552 internal_bundle_free(b);
16540 16553 }
16541 16554
16542 16555 free_manifest_array(manifests);
16543 16556 }
16544 16557 }
16545 16558 }
16546 16559
16547 16560 /*
16548 16561 * Check the manifest history file to see
16549 16562 * if the service was ever installed from
16550 16563 * one of the supported directories.
16551 16564 *
16552 16565 * Return Values :
16553 16566 * -1 - if there's error reading manifest history file
16554 16567 * 1 - if the service is not found
16555 16568 * 0 - if the service is found
16556 16569 */
16557 16570 static int
16558 16571 check_mfst_history(const char *svcname)
16559 16572 {
16560 16573 struct stat st;
16561 16574 caddr_t mfsthist_start;
16562 16575 char *svnbuf;
16563 16576 int fd;
16564 16577 int r = 1;
16565 16578
16566 16579 fd = open(MFSTHISTFILE, O_RDONLY);
16567 16580 if (fd == -1) {
16568 16581 uu_warn(gettext("Unable to open the history file\n"));
16569 16582 return (-1);
16570 16583 }
16571 16584
16572 16585 if (fstat(fd, &st) == -1) {
16573 16586 uu_warn(gettext("Unable to stat the history file\n"));
16574 16587 return (-1);
16575 16588 }
16576 16589
16577 16590 mfsthist_start = mmap(0, st.st_size, PROT_READ,
16578 16591 MAP_PRIVATE, fd, 0);
16579 16592
16580 16593 (void) close(fd);
16581 16594 if (mfsthist_start == MAP_FAILED ||
16582 16595 *(mfsthist_start + st.st_size) != '\0') {
16583 16596 (void) munmap(mfsthist_start, st.st_size);
16584 16597 return (-1);
16585 16598 }
16586 16599
16587 16600 /*
16588 16601 * The manifest history file is a space delimited list
16589 16602 * of service and instance to manifest linkage. Adding
16590 16603 * a space to the end of the service name so to get only
16591 16604 * the service that is being searched for.
16592 16605 */
16593 16606 svnbuf = uu_msprintf("%s ", svcname);
16594 16607 if (svnbuf == NULL)
16595 16608 uu_die(gettext("Out of memory"));
16596 16609
16597 16610 if (strstr(mfsthist_start, svnbuf) != NULL)
16598 16611 r = 0;
16599 16612
16600 16613 (void) munmap(mfsthist_start, st.st_size);
16601 16614 uu_free(svnbuf);
16602 16615 return (r);
16603 16616 }
16604 16617
16605 16618 /*
16606 16619 * Take down each of the instances in the service
16607 16620 * and remove them, then delete the service.
16608 16621 */
16609 16622 static void
16610 16623 teardown_service(scf_service_t *svc, const char *svnbuf)
16611 16624 {
16612 16625 scf_instance_t *instance;
16613 16626 scf_iter_t *iter;
16614 16627 int r;
16615 16628
16616 16629 safe_printf(gettext("Delete service %s as there are no "
16617 16630 "supporting manifests\n"), svnbuf);
16618 16631
16619 16632 instance = scf_instance_create(g_hndl);
16620 16633 iter = scf_iter_create(g_hndl);
16621 16634 if (iter == NULL || instance == NULL) {
16622 16635 uu_warn(gettext("Unable to create supporting entities to "
16623 16636 "teardown the service\n"));
16624 16637 uu_warn(gettext("scf error is : %s\n"),
16625 16638 scf_strerror(scf_error()));
16626 16639 scfdie();
16627 16640 }
16628 16641
16629 16642 if (scf_iter_service_instances(iter, svc) != 0) {
16630 16643 switch (scf_error()) {
16631 16644 case SCF_ERROR_CONNECTION_BROKEN:
16632 16645 case SCF_ERROR_DELETED:
16633 16646 goto out;
16634 16647
16635 16648 case SCF_ERROR_HANDLE_MISMATCH:
16636 16649 case SCF_ERROR_NOT_BOUND:
16637 16650 case SCF_ERROR_NOT_SET:
16638 16651 default:
16639 16652 bad_error("scf_iter_service_instances",
16640 16653 scf_error());
16641 16654 }
16642 16655 }
16643 16656
16644 16657 while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16645 16658 if (r == -1) {
16646 16659 uu_warn(gettext("Error - %s\n"),
16647 16660 scf_strerror(scf_error()));
16648 16661 goto out;
16649 16662 }
16650 16663
16651 16664 (void) disable_instance(instance);
16652 16665 }
16653 16666
16654 16667 /*
16655 16668 * Delete the service... forcing the deletion in case
16656 16669 * any of the instances did not disable.
16657 16670 */
16658 16671 (void) lscf_service_delete(svc, 1);
16659 16672 out:
16660 16673 scf_instance_destroy(instance);
16661 16674 scf_iter_destroy(iter);
16662 16675 }
16663 16676
16664 16677 /*
16665 16678 * Get the list of instances supported by the manifest
16666 16679 * file.
16667 16680 *
16668 16681 * Return 0 if there are no instances.
16669 16682 *
16670 16683 * Return -1 if there are errors attempting to collect instances.
16671 16684 *
16672 16685 * Return the count of instances found if there are no errors.
16673 16686 *
16674 16687 */
16675 16688 static int
16676 16689 check_instance_support(char *mfstfile, const char *svcname,
16677 16690 uu_list_t *instances)
16678 16691 {
16679 16692 uu_list_walk_t *svcs, *insts;
16680 16693 uu_list_t *ilist;
16681 16694 bundle_t *b;
16682 16695 entity_t *mfsvc, *mfinst;
16683 16696 const char *svcn;
16684 16697 int rminstcnt = 0;
16685 16698
16686 16699
16687 16700 b = internal_bundle_new();
16688 16701
16689 16702 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16690 16703 /*
16691 16704 * Unable to process the manifest file for
16692 16705 * instance support, so just return as
16693 16706 * don't want to remove instances that could
16694 16707 * not be accounted for that might exist here.
16695 16708 */
16696 16709 internal_bundle_free(b);
16697 16710 return (0);
16698 16711 }
16699 16712
16700 16713 svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16701 16714 if (svcs == NULL) {
16702 16715 internal_bundle_free(b);
16703 16716 return (0);
16704 16717 }
16705 16718
16706 16719 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16707 16720 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16708 16721
16709 16722 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16710 16723 if (strcmp(mfsvc->sc_name, svcn) == 0)
16711 16724 break;
16712 16725 }
16713 16726 uu_list_walk_end(svcs);
16714 16727
16715 16728 if (mfsvc == NULL) {
16716 16729 internal_bundle_free(b);
16717 16730 return (-1);
16718 16731 }
16719 16732
16720 16733 ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16721 16734 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16722 16735 internal_bundle_free(b);
16723 16736 return (0);
16724 16737 }
16725 16738
16726 16739 while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16727 16740 /*
16728 16741 * Remove the instance from the instances list.
16729 16742 * The unaccounted for instances will be removed
16730 16743 * from the service once all manifests are
16731 16744 * processed.
16732 16745 */
16733 16746 (void) remove_string(instances,
16734 16747 mfinst->sc_name);
16735 16748 rminstcnt++;
16736 16749 }
16737 16750
16738 16751 uu_list_walk_end(insts);
16739 16752 internal_bundle_free(b);
16740 16753
16741 16754 return (rminstcnt);
16742 16755 }
16743 16756
16744 16757 /*
16745 16758 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16746 16759 * 'false' to indicate there's no manifest file(s) found for the service.
16747 16760 */
16748 16761 static void
16749 16762 svc_add_no_support(scf_service_t *svc)
16750 16763 {
16751 16764 char *pname;
16752 16765
16753 16766 /* Add no support */
16754 16767 cur_svc = svc;
16755 16768 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16756 16769 return;
16757 16770
16758 16771 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16759 16772 if (pname == NULL)
16760 16773 uu_die(gettext("Out of memory.\n"));
16761 16774
16762 16775 (void) lscf_addpropvalue(pname, "boolean:", "0");
16763 16776
16764 16777 uu_free(pname);
16765 16778 cur_svc = NULL;
16766 16779 }
16767 16780
16768 16781 /*
16769 16782 * This function handles all upgrade scenarios for a service that doesn't have
16770 16783 * SCF_PG_MANIFESTFILES pg. The function creates and populates
16771 16784 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16772 16785 * manifest(s) mapping. Manifests under supported directories are inventoried
16773 16786 * and a property is added for each file that delivers configuration to the
16774 16787 * service. A service that has no corresponding manifest files (deleted) are
16775 16788 * removed from repository.
16776 16789 *
16777 16790 * Unsupported services:
16778 16791 *
16779 16792 * A service is considered unsupported if there is no corresponding manifest
16780 16793 * in the supported directories for that service and the service isn't in the
16781 16794 * history file list. The history file, MFSTHISTFILE, contains a list of all
16782 16795 * services and instances that were delivered by Solaris before the introduction
16783 16796 * of the SCF_PG_MANIFESTFILES property group. The history file also contains
16784 16797 * the path to the manifest file that defined the service or instance.
16785 16798 *
16786 16799 * Another type of unsupported services is 'handcrafted' services,
16787 16800 * programmatically created services or services created by dependent entries
16788 16801 * in other manifests. A handcrafted service is identified by its lack of any
16789 16802 * instance containing last-import snapshot which is created during svccfg
16790 16803 * import.
16791 16804 *
16792 16805 * This function sets a flag for unsupported services by setting services'
16793 16806 * SCF_PG_MANIFESTFILES/support property to false.
16794 16807 */
16795 16808 static void
16796 16809 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16797 16810 {
16798 16811 service_manifest_t *elem;
16799 16812 uu_list_walk_t *mfwalk;
16800 16813 string_list_t *mfile;
16801 16814 uu_list_t *instances;
16802 16815 const char *sname;
16803 16816 char *pname;
16804 16817 int r;
16805 16818
16806 16819 /*
16807 16820 * Since there's no guarantee manifests under /var are available during
16808 16821 * early import, don't perform any upgrade during early import.
16809 16822 */
16810 16823 if (IGNORE_VAR)
16811 16824 return;
16812 16825
16813 16826 if (service_manifest_tree == NULL) {
16814 16827 create_manifest_tree();
16815 16828 }
16816 16829
16817 16830 /*
16818 16831 * Find service's supporting manifest(s) after
16819 16832 * stripping off the svc:/ prefix that is part
16820 16833 * of the fmri that is not used in the service
16821 16834 * manifest bundle list.
16822 16835 */
16823 16836 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16824 16837 strlen(SCF_FMRI_SERVICE_PREFIX);
16825 16838 elem = find_add_svc_mfst(sname, NULL);
16826 16839 if (elem == NULL) {
16827 16840
16828 16841 /*
16829 16842 * A handcrafted service, one that has no instance containing
16830 16843 * last-import snapshot, should get unsupported flag.
16831 16844 */
16832 16845 instances = create_instance_list(svc, 1);
16833 16846 if (instances == NULL) {
16834 16847 uu_warn(gettext("Unable to create instance list %s\n"),
16835 16848 svcname);
16836 16849 return;
16837 16850 }
16838 16851
16839 16852 if (uu_list_numnodes(instances) == 0) {
16840 16853 svc_add_no_support(svc);
16841 16854 return;
16842 16855 }
16843 16856
16844 16857 /*
16845 16858 * If the service is in the history file, and its supporting
16846 16859 * manifests are not found, we can safely delete the service
16847 16860 * because its manifests are removed from the system.
16848 16861 *
16849 16862 * Services not found in the history file are not delivered by
16850 16863 * Solaris and/or delivered outside supported directories, set
16851 16864 * unsupported flag for these services.
16852 16865 */
16853 16866 r = check_mfst_history(svcname);
16854 16867 if (r == -1)
16855 16868 return;
16856 16869
16857 16870 if (r) {
16858 16871 /* Set unsupported flag for service */
16859 16872 svc_add_no_support(svc);
16860 16873 } else {
16861 16874 /* Delete the service */
16862 16875 teardown_service(svc, svcname);
16863 16876 }
16864 16877
16865 16878 return;
16866 16879 }
16867 16880
16868 16881 /*
16869 16882 * Walk through the list of manifests and add them
16870 16883 * to the service.
16871 16884 *
16872 16885 * Create a manifestfiles pg and add the property.
16873 16886 */
16874 16887 mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16875 16888 if (mfwalk == NULL)
16876 16889 return;
16877 16890
16878 16891 cur_svc = svc;
16879 16892 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16880 16893 if (r != 0) {
16881 16894 cur_svc = NULL;
16882 16895 return;
16883 16896 }
16884 16897
16885 16898 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16886 16899 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16887 16900 mhash_filename_to_propname(mfile->str, 0));
16888 16901 if (pname == NULL)
16889 16902 uu_die(gettext("Out of memory.\n"));
16890 16903
16891 16904 (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16892 16905 uu_free(pname);
16893 16906 }
16894 16907 uu_list_walk_end(mfwalk);
16895 16908
16896 16909 cur_svc = NULL;
16897 16910 }
16898 16911
16899 16912 /*
16900 16913 * Take a service and process the manifest file entires to see if
16901 16914 * there is continued support for the service and instances. If
16902 16915 * not cleanup as appropriate.
16903 16916 *
16904 16917 * If a service does not have a manifest files entry flag it for
16905 16918 * upgrade and return.
16906 16919 *
16907 16920 * For each manifestfiles property check if the manifest file is
16908 16921 * under the supported /lib/svc/manifest or /var/svc/manifest path
16909 16922 * and if not then return immediately as this service is not supported
16910 16923 * by the cleanup mechanism and should be ignored.
16911 16924 *
16912 16925 * For each manifest file that is supported, check to see if the
16913 16926 * file exists. If not then remove the manifest file property
16914 16927 * from the service and the smf/manifest hash table. If the manifest
16915 16928 * file exists then verify that it supports the instances that are
16916 16929 * part of the service.
16917 16930 *
16918 16931 * Once all manifest files have been accounted for remove any instances
16919 16932 * that are no longer supported in the service.
16920 16933 *
16921 16934 * Return values :
16922 16935 * 0 - Successfully processed the service
16923 16936 * non-zero - failed to process the service
16924 16937 *
16925 16938 * On most errors, will just return to wait and get the next service,
16926 16939 * unless in case of unable to create the needed structures which is
16927 16940 * most likely a fatal error that is not going to be recoverable.
16928 16941 */
16929 16942 int
16930 16943 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16931 16944 {
16932 16945 struct mpg_mfile *mpntov;
16933 16946 struct mpg_mfile **mpvarry = NULL;
16934 16947 scf_service_t *svc;
16935 16948 scf_propertygroup_t *mpg;
16936 16949 scf_property_t *mp;
16937 16950 scf_value_t *mv;
16938 16951 scf_iter_t *mi;
16939 16952 scf_instance_t *instance;
16940 16953 uu_list_walk_t *insts;
16941 16954 uu_list_t *instances = NULL;
16942 16955 boolean_t activity = (boolean_t)act;
16943 16956 char *mpnbuf;
16944 16957 char *mpvbuf;
16945 16958 char *pgpropbuf;
16946 16959 int mfstcnt, rminstct, instct, mfstmax;
16947 16960 int index;
16948 16961 int r = 0;
16949 16962
16950 16963 assert(g_hndl != NULL);
16951 16964 assert(wip->svc != NULL);
16952 16965 assert(wip->fmri != NULL);
16953 16966
16954 16967 svc = wip->svc;
16955 16968
16956 16969 mpg = scf_pg_create(g_hndl);
16957 16970 mp = scf_property_create(g_hndl);
16958 16971 mi = scf_iter_create(g_hndl);
16959 16972 mv = scf_value_create(g_hndl);
16960 16973 instance = scf_instance_create(g_hndl);
16961 16974
16962 16975 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16963 16976 instance == NULL) {
16964 16977 uu_warn(gettext("Unable to create the supporting entities\n"));
16965 16978 uu_warn(gettext("scf error is : %s\n"),
16966 16979 scf_strerror(scf_error()));
16967 16980 scfdie();
16968 16981 }
16969 16982
16970 16983 /*
16971 16984 * Get the manifestfiles property group to be parsed for
16972 16985 * files existence.
16973 16986 */
16974 16987 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16975 16988 switch (scf_error()) {
16976 16989 case SCF_ERROR_NOT_FOUND:
16977 16990 upgrade_svc_mfst_connection(svc, wip->fmri);
16978 16991 break;
16979 16992 case SCF_ERROR_DELETED:
16980 16993 case SCF_ERROR_CONNECTION_BROKEN:
16981 16994 goto out;
16982 16995
16983 16996 case SCF_ERROR_HANDLE_MISMATCH:
16984 16997 case SCF_ERROR_NOT_BOUND:
16985 16998 case SCF_ERROR_NOT_SET:
16986 16999 default:
16987 17000 bad_error("scf_iter_pg_properties",
16988 17001 scf_error());
16989 17002 }
16990 17003
16991 17004 goto out;
16992 17005 }
16993 17006
16994 17007 /*
16995 17008 * Iterate through each of the manifestfiles properties
16996 17009 * to determine what manifestfiles are available.
16997 17010 *
16998 17011 * If a manifest file is supported then increment the
16999 17012 * count and therefore the service is safe.
17000 17013 */
17001 17014 if (scf_iter_pg_properties(mi, mpg) != 0) {
17002 17015 switch (scf_error()) {
17003 17016 case SCF_ERROR_DELETED:
17004 17017 case SCF_ERROR_CONNECTION_BROKEN:
17005 17018 goto out;
17006 17019
17007 17020 case SCF_ERROR_HANDLE_MISMATCH:
17008 17021 case SCF_ERROR_NOT_BOUND:
17009 17022 case SCF_ERROR_NOT_SET:
17010 17023 default:
17011 17024 bad_error("scf_iter_pg_properties",
17012 17025 scf_error());
17013 17026 }
17014 17027 }
17015 17028
17016 17029 mfstcnt = 0;
17017 17030 mfstmax = MFSTFILE_MAX;
17018 17031 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17019 17032 while ((r = scf_iter_next_property(mi, mp)) != 0) {
17020 17033 if (r == -1)
17021 17034 bad_error(gettext("Unable to iterate through "
17022 17035 "manifestfiles properties : %s"),
17023 17036 scf_error());
17024 17037
17025 17038 mpntov = safe_malloc(sizeof (struct mpg_mfile));
17026 17039 mpnbuf = safe_malloc(max_scf_name_len + 1);
17027 17040 mpvbuf = safe_malloc(max_scf_value_len + 1);
17028 17041 mpntov->mpg = mpnbuf;
17029 17042 mpntov->mfile = mpvbuf;
17030 17043 mpntov->access = 1;
17031 17044 if (scf_property_get_name(mp, mpnbuf,
17032 17045 max_scf_name_len + 1) < 0) {
17033 17046 uu_warn(gettext("Unable to get manifest file "
17034 17047 "property : %s\n"),
17035 17048 scf_strerror(scf_error()));
17036 17049
17037 17050 switch (scf_error()) {
17038 17051 case SCF_ERROR_DELETED:
17039 17052 case SCF_ERROR_CONNECTION_BROKEN:
17040 17053 r = scferror2errno(scf_error());
17041 17054 goto out_free;
17042 17055
17043 17056 case SCF_ERROR_HANDLE_MISMATCH:
17044 17057 case SCF_ERROR_NOT_BOUND:
17045 17058 case SCF_ERROR_NOT_SET:
17046 17059 default:
17047 17060 bad_error("scf_iter_pg_properties",
17048 17061 scf_error());
17049 17062 }
17050 17063 }
17051 17064
17052 17065 /*
17053 17066 * The support property is a boolean value that indicates
17054 17067 * if the service is supported for manifest file deletion.
17055 17068 * Currently at this time there is no code that sets this
17056 17069 * value to true. So while we could just let this be caught
17057 17070 * by the support check below, in the future this by be set
17058 17071 * to true and require processing. So for that, go ahead
17059 17072 * and check here, and just return if false. Otherwise,
17060 17073 * fall through expecting that other support checks will
17061 17074 * handle the entries.
17062 17075 */
17063 17076 if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17064 17077 uint8_t support;
17065 17078
17066 17079 if (scf_property_get_value(mp, mv) != 0 ||
17067 17080 scf_value_get_boolean(mv, &support) != 0) {
17068 17081 uu_warn(gettext("Unable to get the manifest "
17069 17082 "support value: %s\n"),
17070 17083 scf_strerror(scf_error()));
17071 17084
17072 17085 switch (scf_error()) {
17073 17086 case SCF_ERROR_DELETED:
17074 17087 case SCF_ERROR_CONNECTION_BROKEN:
17075 17088 r = scferror2errno(scf_error());
17076 17089 goto out_free;
17077 17090
17078 17091 case SCF_ERROR_HANDLE_MISMATCH:
17079 17092 case SCF_ERROR_NOT_BOUND:
17080 17093 case SCF_ERROR_NOT_SET:
17081 17094 default:
17082 17095 bad_error("scf_iter_pg_properties",
17083 17096 scf_error());
17084 17097 }
17085 17098 }
17086 17099
17087 17100 if (support == B_FALSE)
17088 17101 goto out_free;
17089 17102 }
17090 17103
17091 17104 /*
17092 17105 * Anything with a manifest outside of the supported
17093 17106 * directories, immediately bail out because that makes
17094 17107 * this service non-supported. We don't even want
17095 17108 * to do instance processing in this case because the
17096 17109 * instances could be part of the non-supported manifest.
17097 17110 */
17098 17111 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17099 17112 /*
17100 17113 * Manifest is not in /lib/svc, so we need to
17101 17114 * consider the /var/svc case.
17102 17115 */
17103 17116 if (strncmp(mpnbuf, VARSVC_PR,
17104 17117 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17105 17118 /*
17106 17119 * Either the manifest is not in /var/svc or
17107 17120 * /var is not yet mounted. We ignore the
17108 17121 * manifest either because it is not in a
17109 17122 * standard location or because we cannot
17110 17123 * currently access the manifest.
17111 17124 */
17112 17125 goto out_free;
17113 17126 }
17114 17127 }
17115 17128
17116 17129 /*
17117 17130 * Get the value to of the manifest file for this entry
17118 17131 * for access verification and instance support
17119 17132 * verification if it still exists.
17120 17133 *
17121 17134 * During Early Manifest Import if the manifest is in
17122 17135 * /var/svc then it may not yet be available for checking
17123 17136 * so we must determine if /var/svc is available. If not
17124 17137 * then defer until Late Manifest Import to cleanup.
17125 17138 */
17126 17139 if (scf_property_get_value(mp, mv) != 0) {
17127 17140 uu_warn(gettext("Unable to get the manifest file "
17128 17141 "value: %s\n"),
17129 17142 scf_strerror(scf_error()));
17130 17143
17131 17144 switch (scf_error()) {
17132 17145 case SCF_ERROR_DELETED:
17133 17146 case SCF_ERROR_CONNECTION_BROKEN:
17134 17147 r = scferror2errno(scf_error());
17135 17148 goto out_free;
17136 17149
17137 17150 case SCF_ERROR_HANDLE_MISMATCH:
17138 17151 case SCF_ERROR_NOT_BOUND:
17139 17152 case SCF_ERROR_NOT_SET:
17140 17153 default:
17141 17154 bad_error("scf_property_get_value",
17142 17155 scf_error());
17143 17156 }
17144 17157 }
17145 17158
17146 17159 if (scf_value_get_astring(mv, mpvbuf,
17147 17160 max_scf_value_len + 1) < 0) {
17148 17161 uu_warn(gettext("Unable to get the manifest "
17149 17162 "file : %s\n"),
17150 17163 scf_strerror(scf_error()));
17151 17164
17152 17165 switch (scf_error()) {
17153 17166 case SCF_ERROR_DELETED:
17154 17167 case SCF_ERROR_CONNECTION_BROKEN:
17155 17168 r = scferror2errno(scf_error());
17156 17169 goto out_free;
17157 17170
17158 17171 case SCF_ERROR_HANDLE_MISMATCH:
17159 17172 case SCF_ERROR_NOT_BOUND:
17160 17173 case SCF_ERROR_NOT_SET:
17161 17174 default:
17162 17175 bad_error("scf_value_get_astring",
17163 17176 scf_error());
17164 17177 }
17165 17178 }
17166 17179
17167 17180 mpvarry[mfstcnt] = mpntov;
17168 17181 mfstcnt++;
17169 17182
17170 17183 /*
17171 17184 * Check for the need to reallocate array
17172 17185 */
17173 17186 if (mfstcnt >= (mfstmax - 1)) {
17174 17187 struct mpg_mfile **newmpvarry;
17175 17188
17176 17189 mfstmax = mfstmax * 2;
17177 17190 newmpvarry = realloc(mpvarry,
17178 17191 sizeof (struct mpg_mfile *) * mfstmax);
17179 17192
17180 17193 if (newmpvarry == NULL)
17181 17194 goto out_free;
17182 17195
17183 17196 mpvarry = newmpvarry;
17184 17197 }
17185 17198
17186 17199 mpvarry[mfstcnt] = NULL;
17187 17200 }
17188 17201
17189 17202 for (index = 0; mpvarry[index]; index++) {
17190 17203 mpntov = mpvarry[index];
17191 17204
17192 17205 /*
17193 17206 * Check to see if the manifestfile is accessable, if so hand
17194 17207 * this service and manifestfile off to be processed for
17195 17208 * instance support.
17196 17209 */
17197 17210 mpnbuf = mpntov->mpg;
17198 17211 mpvbuf = mpntov->mfile;
17199 17212 if (access(mpvbuf, F_OK) != 0) {
17200 17213 mpntov->access = 0;
17201 17214 activity++;
17202 17215 mfstcnt--;
17203 17216 /* Remove the entry from the service */
17204 17217 cur_svc = svc;
17205 17218 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17206 17219 mpnbuf);
17207 17220 if (pgpropbuf == NULL)
17208 17221 uu_die(gettext("Out of memory.\n"));
17209 17222
17210 17223 lscf_delprop(pgpropbuf);
17211 17224 cur_svc = NULL;
17212 17225
17213 17226 uu_free(pgpropbuf);
17214 17227 }
17215 17228 }
17216 17229
17217 17230 /*
17218 17231 * If mfstcnt is 0, none of the manifests that supported the service
17219 17232 * existed so remove the service.
17220 17233 */
17221 17234 if (mfstcnt == 0) {
17222 17235 teardown_service(svc, wip->fmri);
17223 17236
17224 17237 goto out_free;
17225 17238 }
17226 17239
17227 17240 if (activity) {
17228 17241 int nosvcsupport = 0;
17229 17242
17230 17243 /*
17231 17244 * If the list of service instances is NULL then
17232 17245 * create the list.
17233 17246 */
17234 17247 instances = create_instance_list(svc, 1);
17235 17248 if (instances == NULL) {
17236 17249 uu_warn(gettext("Unable to create instance list %s\n"),
17237 17250 wip->fmri);
17238 17251 goto out_free;
17239 17252 }
17240 17253
17241 17254 rminstct = uu_list_numnodes(instances);
17242 17255 instct = rminstct;
17243 17256
17244 17257 for (index = 0; mpvarry[index]; index++) {
17245 17258 mpntov = mpvarry[index];
17246 17259 if (mpntov->access == 0)
17247 17260 continue;
17248 17261
17249 17262 mpnbuf = mpntov->mpg;
17250 17263 mpvbuf = mpntov->mfile;
17251 17264 r = check_instance_support(mpvbuf, wip->fmri,
17252 17265 instances);
17253 17266 if (r == -1) {
17254 17267 nosvcsupport++;
17255 17268 } else {
17256 17269 rminstct -= r;
17257 17270 }
17258 17271 }
17259 17272
17260 17273 if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17261 17274 teardown_service(svc, wip->fmri);
17262 17275
17263 17276 goto out_free;
17264 17277 }
17265 17278 }
17266 17279
17267 17280 /*
17268 17281 * If there are instances left on the instance list, then
17269 17282 * we must remove them.
17270 17283 */
17271 17284 if (instances != NULL && uu_list_numnodes(instances)) {
17272 17285 string_list_t *sp;
17273 17286
17274 17287 insts = uu_list_walk_start(instances, 0);
17275 17288 while ((sp = uu_list_walk_next(insts)) != NULL) {
17276 17289 /*
17277 17290 * Remove the instance from the instances list.
17278 17291 */
17279 17292 safe_printf(gettext("Delete instance %s from "
17280 17293 "service %s\n"), sp->str, wip->fmri);
17281 17294 if (scf_service_get_instance(svc, sp->str,
17282 17295 instance) != SCF_SUCCESS) {
17283 17296 (void) uu_warn("scf_error - %s\n",
17284 17297 scf_strerror(scf_error()));
17285 17298
17286 17299 continue;
17287 17300 }
17288 17301
17289 17302 (void) disable_instance(instance);
17290 17303
17291 17304 (void) lscf_instance_delete(instance, 1);
17292 17305 }
17293 17306 scf_instance_destroy(instance);
17294 17307 uu_list_walk_end(insts);
17295 17308 }
17296 17309
17297 17310 out_free:
17298 17311 if (mpvarry) {
17299 17312 struct mpg_mfile *fmpntov;
17300 17313
17301 17314 for (index = 0; mpvarry[index]; index++) {
17302 17315 fmpntov = mpvarry[index];
17303 17316 if (fmpntov->mpg == mpnbuf)
17304 17317 mpnbuf = NULL;
17305 17318 free(fmpntov->mpg);
17306 17319
17307 17320 if (fmpntov->mfile == mpvbuf)
17308 17321 mpvbuf = NULL;
17309 17322 free(fmpntov->mfile);
17310 17323
17311 17324 if (fmpntov == mpntov)
17312 17325 mpntov = NULL;
17313 17326 free(fmpntov);
17314 17327 }
17315 17328 if (mpnbuf)
17316 17329 free(mpnbuf);
17317 17330 if (mpvbuf)
17318 17331 free(mpvbuf);
17319 17332 if (mpntov)
17320 17333 free(mpntov);
17321 17334
17322 17335 free(mpvarry);
17323 17336 }
17324 17337 out:
17325 17338 scf_pg_destroy(mpg);
17326 17339 scf_property_destroy(mp);
17327 17340 scf_iter_destroy(mi);
17328 17341 scf_value_destroy(mv);
17329 17342
17330 17343 return (0);
17331 17344 }
17332 17345
17333 17346 /*
17334 17347 * Take the service and search for the manifestfiles property
17335 17348 * in each of the property groups. If the manifest file
17336 17349 * associated with the property does not exist then remove
17337 17350 * the property group.
17338 17351 */
17339 17352 int
17340 17353 lscf_hash_cleanup()
17341 17354 {
17342 17355 scf_service_t *svc;
17343 17356 scf_scope_t *scope;
17344 17357 scf_propertygroup_t *pg;
17345 17358 scf_property_t *prop;
17346 17359 scf_value_t *val;
17347 17360 scf_iter_t *iter;
17348 17361 char *pgname = NULL;
17349 17362 char *mfile = NULL;
17350 17363 int r;
17351 17364
17352 17365 svc = scf_service_create(g_hndl);
17353 17366 scope = scf_scope_create(g_hndl);
17354 17367 pg = scf_pg_create(g_hndl);
17355 17368 prop = scf_property_create(g_hndl);
17356 17369 val = scf_value_create(g_hndl);
17357 17370 iter = scf_iter_create(g_hndl);
17358 17371 if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17359 17372 svc == NULL || scope == NULL) {
17360 17373 uu_warn(gettext("Unable to create a property group, or "
17361 17374 "property\n"));
17362 17375 uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17363 17376 "pg is not NULL");
17364 17377 uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17365 17378 "prop is not NULL");
17366 17379 uu_warn("%s\n", val == NULL ? "val is NULL" :
17367 17380 "val is not NULL");
17368 17381 uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17369 17382 "iter is not NULL");
17370 17383 uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17371 17384 "svc is not NULL");
17372 17385 uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17373 17386 "scope is not NULL");
17374 17387 uu_warn(gettext("scf error is : %s\n"),
17375 17388 scf_strerror(scf_error()));
17376 17389 scfdie();
17377 17390 }
17378 17391
17379 17392 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17380 17393 switch (scf_error()) {
17381 17394 case SCF_ERROR_CONNECTION_BROKEN:
17382 17395 case SCF_ERROR_NOT_FOUND:
17383 17396 goto out;
17384 17397
17385 17398 case SCF_ERROR_HANDLE_MISMATCH:
17386 17399 case SCF_ERROR_NOT_BOUND:
17387 17400 case SCF_ERROR_INVALID_ARGUMENT:
17388 17401 default:
17389 17402 bad_error("scf_handle_get_scope", scf_error());
17390 17403 }
17391 17404 }
17392 17405
17393 17406 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17394 17407 uu_warn(gettext("Unable to process the hash service, %s\n"),
17395 17408 HASH_SVC);
17396 17409 goto out;
17397 17410 }
17398 17411
17399 17412 pgname = safe_malloc(max_scf_name_len + 1);
17400 17413 mfile = safe_malloc(max_scf_value_len + 1);
17401 17414
17402 17415 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17403 17416 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17404 17417 scf_strerror(scf_error()));
17405 17418 goto out;
17406 17419 }
17407 17420
17408 17421 while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17409 17422 if (r == -1)
17410 17423 goto out;
17411 17424
17412 17425 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17413 17426 switch (scf_error()) {
17414 17427 case SCF_ERROR_DELETED:
17415 17428 return (ENODEV);
17416 17429
17417 17430 case SCF_ERROR_CONNECTION_BROKEN:
17418 17431 return (ECONNABORTED);
17419 17432
17420 17433 case SCF_ERROR_NOT_SET:
17421 17434 case SCF_ERROR_NOT_BOUND:
17422 17435 default:
17423 17436 bad_error("scf_pg_get_name", scf_error());
17424 17437 }
17425 17438 }
17426 17439 if (IGNORE_VAR) {
17427 17440 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17428 17441 continue;
17429 17442 }
17430 17443
17431 17444 /*
17432 17445 * If unable to get the property continue as this is an
17433 17446 * entry that has no location to check against.
17434 17447 */
17435 17448 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17436 17449 continue;
17437 17450 }
17438 17451
17439 17452 if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17440 17453 uu_warn(gettext("Unable to get value from %s\n"),
17441 17454 pgname);
17442 17455
17443 17456 switch (scf_error()) {
17444 17457 case SCF_ERROR_DELETED:
17445 17458 case SCF_ERROR_CONSTRAINT_VIOLATED:
17446 17459 case SCF_ERROR_NOT_FOUND:
17447 17460 case SCF_ERROR_NOT_SET:
17448 17461 continue;
17449 17462
17450 17463 case SCF_ERROR_CONNECTION_BROKEN:
17451 17464 r = scferror2errno(scf_error());
17452 17465 goto out;
17453 17466
17454 17467 case SCF_ERROR_HANDLE_MISMATCH:
17455 17468 case SCF_ERROR_NOT_BOUND:
17456 17469 default:
17457 17470 bad_error("scf_property_get_value",
17458 17471 scf_error());
17459 17472 }
17460 17473 }
17461 17474
17462 17475 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17463 17476 == -1) {
17464 17477 uu_warn(gettext("Unable to get astring from %s : %s\n"),
17465 17478 pgname, scf_strerror(scf_error()));
17466 17479
17467 17480 switch (scf_error()) {
17468 17481 case SCF_ERROR_NOT_SET:
17469 17482 case SCF_ERROR_TYPE_MISMATCH:
17470 17483 continue;
17471 17484
17472 17485 default:
17473 17486 bad_error("scf_value_get_astring", scf_error());
17474 17487 }
17475 17488 }
17476 17489
17477 17490 if (access(mfile, F_OK) == 0)
17478 17491 continue;
17479 17492
17480 17493 (void) scf_pg_delete(pg);
17481 17494 }
17482 17495
17483 17496 out:
17484 17497 scf_scope_destroy(scope);
17485 17498 scf_service_destroy(svc);
17486 17499 scf_pg_destroy(pg);
17487 17500 scf_property_destroy(prop);
17488 17501 scf_value_destroy(val);
17489 17502 scf_iter_destroy(iter);
17490 17503 free(pgname);
17491 17504 free(mfile);
17492 17505
17493 17506 return (0);
17494 17507 }
17495 17508
17496 17509 #ifndef NATIVE_BUILD
17497 17510 /* ARGSUSED */
17498 17511 CPL_MATCH_FN(complete_select)
17499 17512 {
17500 17513 const char *arg0, *arg1, *arg1end;
17501 17514 int word_start, err = 0, r;
17502 17515 size_t len;
17503 17516 char *buf;
17504 17517
17505 17518 lscf_prep_hndl();
17506 17519
17507 17520 arg0 = line + strspn(line, " \t");
17508 17521 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17509 17522
17510 17523 arg1 = arg0 + sizeof ("select") - 1;
17511 17524 arg1 += strspn(arg1, " \t");
17512 17525 word_start = arg1 - line;
17513 17526
17514 17527 arg1end = arg1 + strcspn(arg1, " \t");
17515 17528 if (arg1end < line + word_end)
17516 17529 return (0);
17517 17530
17518 17531 len = line + word_end - arg1;
17519 17532
17520 17533 buf = safe_malloc(max_scf_name_len + 1);
17521 17534
17522 17535 if (cur_snap != NULL) {
17523 17536 return (0);
17524 17537 } else if (cur_inst != NULL) {
17525 17538 return (0);
17526 17539 } else if (cur_svc != NULL) {
17527 17540 scf_instance_t *inst;
17528 17541 scf_iter_t *iter;
17529 17542
17530 17543 if ((inst = scf_instance_create(g_hndl)) == NULL ||
17531 17544 (iter = scf_iter_create(g_hndl)) == NULL)
17532 17545 scfdie();
17533 17546
17534 17547 if (scf_iter_service_instances(iter, cur_svc) != 0)
17535 17548 scfdie();
17536 17549
17537 17550 for (;;) {
17538 17551 r = scf_iter_next_instance(iter, inst);
17539 17552 if (r == 0)
17540 17553 break;
17541 17554 if (r != 1)
17542 17555 scfdie();
17543 17556
17544 17557 if (scf_instance_get_name(inst, buf,
17545 17558 max_scf_name_len + 1) < 0)
17546 17559 scfdie();
17547 17560
17548 17561 if (strncmp(buf, arg1, len) == 0) {
17549 17562 err = cpl_add_completion(cpl, line, word_start,
17550 17563 word_end, buf + len, "", " ");
17551 17564 if (err != 0)
17552 17565 break;
17553 17566 }
17554 17567 }
17555 17568
17556 17569 scf_iter_destroy(iter);
17557 17570 scf_instance_destroy(inst);
17558 17571
17559 17572 return (err);
17560 17573 } else {
17561 17574 scf_service_t *svc;
17562 17575 scf_iter_t *iter;
17563 17576
17564 17577 assert(cur_scope != NULL);
17565 17578
17566 17579 if ((svc = scf_service_create(g_hndl)) == NULL ||
17567 17580 (iter = scf_iter_create(g_hndl)) == NULL)
17568 17581 scfdie();
17569 17582
17570 17583 if (scf_iter_scope_services(iter, cur_scope) != 0)
17571 17584 scfdie();
17572 17585
17573 17586 for (;;) {
17574 17587 r = scf_iter_next_service(iter, svc);
17575 17588 if (r == 0)
17576 17589 break;
17577 17590 if (r != 1)
17578 17591 scfdie();
17579 17592
17580 17593 if (scf_service_get_name(svc, buf,
17581 17594 max_scf_name_len + 1) < 0)
17582 17595 scfdie();
17583 17596
17584 17597 if (strncmp(buf, arg1, len) == 0) {
17585 17598 err = cpl_add_completion(cpl, line, word_start,
17586 17599 word_end, buf + len, "", " ");
17587 17600 if (err != 0)
17588 17601 break;
17589 17602 }
17590 17603 }
17591 17604
17592 17605 scf_iter_destroy(iter);
17593 17606 scf_service_destroy(svc);
17594 17607
17595 17608 return (err);
17596 17609 }
17597 17610 }
17598 17611
17599 17612 /* ARGSUSED */
17600 17613 CPL_MATCH_FN(complete_command)
17601 17614 {
17602 17615 uint32_t scope = 0;
17603 17616
17604 17617 if (cur_snap != NULL)
17605 17618 scope = CS_SNAP;
17606 17619 else if (cur_inst != NULL)
17607 17620 scope = CS_INST;
17608 17621 else if (cur_svc != NULL)
17609 17622 scope = CS_SVC;
17610 17623 else
17611 17624 scope = CS_SCOPE;
17612 17625
17613 17626 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17614 17627 }
17615 17628 #endif /* NATIVE_BUILD */
↓ open down ↓ |
7755 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX