1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Service Control Manager (SCM) for SVCCTL service. 28 * 29 * This routine maintains a list of SMF service and their states. A list 30 * of Solaris SMF service are displayed on the Server/Connection Manager 31 * Windows client. 32 */ 33 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <stdarg.h> 37 #include <strings.h> 38 #include <assert.h> 39 #include <errno.h> 40 #include <libscf.h> 41 #include <libscf_priv.h> 42 #include <time.h> 43 #include <sys/types.h> 44 45 #include "svcctl_scm.h" 46 47 #define LEGACY_UNKNOWN "unknown" 48 #define SVC_NAME_PROP "name" 49 50 /* Flags for svcctl_scm_pg_get_val() */ 51 #define EMPTY_OK 0x01 52 #define MULTI_OK 0x02 53 54 /* 55 * svcctl_scm_avl_nodecmp 56 * 57 * Comparision function for nodes in an AVL tree of services. 58 */ 59 /* ARGSUSED */ 60 static int 61 svcctl_scm_avl_nodecmp(const void *l_arg, const void *r_arg, void *m_name_len) 62 { 63 const svcctl_svc_node_t *l = l_arg; 64 const svcctl_svc_node_t *r = r_arg; 65 int *max_name_len = m_name_len; 66 int ret = 0; 67 68 ret = strncasecmp(l->sn_name, r->sn_name, *max_name_len); 69 70 if (ret > 0) 71 return (1); 72 if (ret < 0) 73 return (-1); 74 return (0); 75 } 76 77 /* 78 * svcctl_scm_pg_get_val 79 * 80 * Get the single value of the named property in the given property group, 81 * which must have type ty, and put it in *vp. If ty is SCF_TYPE_ASTRING, vp 82 * is taken to be a char **, and sz is the size of the buffer. sz is unused 83 * otherwise. Return 0 on success, -1 if the property doesn't exist, has the 84 * wrong type, or doesn't have a single value. If flags has EMPTY_OK, don't 85 * complain if the property has no values (but return nonzero). If flags has 86 * MULTI_OK and the property has multiple values, succeed with E2BIG. 87 */ 88 static int 89 svcctl_scm_pg_get_val(svcctl_manager_context_t *mgr_ctx, 90 scf_propertygroup_t *pg, const char *propname, scf_type_t ty, void *vp, 91 size_t sz, uint_t flags) 92 { 93 int ret = -1, r; 94 boolean_t multi = B_FALSE; 95 96 assert((flags & ~(EMPTY_OK | MULTI_OK)) == 0); 97 98 if (scf_pg_get_property(pg, propname, mgr_ctx->mc_scf_gprop) == -1) 99 return (ret); 100 101 if (scf_property_is_type(mgr_ctx->mc_scf_gprop, ty) != SCF_SUCCESS) 102 return (ret); 103 104 if (scf_property_get_value(mgr_ctx->mc_scf_gprop, 105 mgr_ctx->mc_scf_gval) != SCF_SUCCESS) { 106 switch (scf_error()) { 107 case SCF_ERROR_NOT_FOUND: 108 return (ret); 109 110 case SCF_ERROR_CONSTRAINT_VIOLATED: 111 if (flags & MULTI_OK) { 112 multi = B_TRUE; 113 break; 114 } 115 return (ret); 116 117 case SCF_ERROR_PERMISSION_DENIED: 118 default: 119 return (ret); 120 } 121 } 122 123 switch (ty) { 124 case SCF_TYPE_ASTRING: 125 r = scf_value_get_astring 126 (mgr_ctx->mc_scf_gval, vp, sz) > 0 ? SCF_SUCCESS : -1; 127 break; 128 129 case SCF_TYPE_BOOLEAN: 130 r = scf_value_get_boolean(mgr_ctx->mc_scf_gval, (uint8_t *)vp); 131 break; 132 133 case SCF_TYPE_COUNT: 134 r = scf_value_get_count(mgr_ctx->mc_scf_gval, (uint64_t *)vp); 135 break; 136 137 case SCF_TYPE_INTEGER: 138 r = scf_value_get_integer(mgr_ctx->mc_scf_gval, (int64_t *)vp); 139 break; 140 141 case SCF_TYPE_TIME: { 142 int64_t sec; 143 int32_t ns; 144 r = scf_value_get_time(mgr_ctx->mc_scf_gval, &sec, &ns); 145 ((struct timeval *)vp)->tv_sec = sec; 146 ((struct timeval *)vp)->tv_usec = ns / 1000; 147 break; 148 } 149 150 case SCF_TYPE_USTRING: 151 r = scf_value_get_ustring(mgr_ctx->mc_scf_gval, vp, sz) > 0 ? 152 SCF_SUCCESS : -1; 153 break; 154 155 default: 156 return (ret); 157 } 158 159 if (r != SCF_SUCCESS) 160 return (ret); 161 162 ret = multi ? E2BIG : 0; 163 164 return (ret); 165 } 166 167 /* 168 * svcctl_scm_get_running_snapshot 169 * 170 * Get running snapshot of a service instance. 171 */ 172 static scf_snapshot_t * 173 svcctl_scm_get_running_snapshot(svcctl_manager_context_t *mgr_ctx, 174 scf_instance_t *inst) 175 { 176 scf_snapshot_t *snap; 177 178 snap = scf_snapshot_create(mgr_ctx->mc_scf_hdl); 179 if (snap == NULL) 180 return (NULL); 181 182 if (scf_instance_get_snapshot(inst, "running", snap) == 0) 183 return (snap); 184 185 if (scf_error() != SCF_ERROR_NOT_FOUND) 186 return (NULL); 187 188 scf_snapshot_destroy(snap); 189 return (NULL); 190 } 191 192 /* 193 * svcctl_scm_inst_get_val 194 * 195 * As svcctl_scm_pg_get_val(), except look the property group up in an 196 * instance. If "use_running" is set, and the running snapshot exists, 197 * do a composed lookup there. Otherwise, do an (optionally composed) 198 * lookup on the current values. Note that lookups using snapshots are 199 * always composed. 200 */ 201 static int 202 svcctl_scm_inst_get_val(svcctl_manager_context_t *mgr_ctx, scf_instance_t *inst, 203 const char *pgname, const char *propname, scf_type_t ty, void *vp, 204 size_t sz, uint_t flags, int use_running, int composed) 205 { 206 scf_snapshot_t *snap = NULL; 207 int r; 208 209 if (use_running) 210 snap = svcctl_scm_get_running_snapshot(mgr_ctx, inst); 211 if (composed || use_running) 212 r = scf_instance_get_pg_composed(inst, snap, pgname, 213 mgr_ctx->mc_scf_gpg); 214 else 215 r = scf_instance_get_pg(inst, pgname, mgr_ctx->mc_scf_gpg); 216 if (snap) 217 scf_snapshot_destroy(snap); 218 if (r == -1) 219 return (-1); 220 221 r = svcctl_scm_pg_get_val(mgr_ctx, mgr_ctx->mc_scf_gpg, propname, ty, 222 vp, sz, flags); 223 224 return (r); 225 } 226 227 /* 228 * svcctl_scm_get_restarter_string_prop 229 * 230 * Get a string property from the restarter property group of the given 231 * instance. Return an empty string on normal problems. 232 */ 233 static void 234 svcctl_scm_get_restarter_string_prop(svcctl_manager_context_t *mgr_ctx, 235 scf_instance_t *inst, const char *pname, char *buf, size_t buf_sz) 236 { 237 if (svcctl_scm_inst_get_val(mgr_ctx, inst, SCF_PG_RESTARTER, pname, 238 SCF_TYPE_ASTRING, buf, buf_sz, 0, 0, 1) != 0) 239 *buf = '\0'; 240 } 241 242 /* 243 * svcctl_scm_svc_transitioning 244 * 245 * Return true if a service instance is transitioning. 246 */ 247 static int 248 svcctl_scm_svc_transitioning(svcctl_manager_context_t *mgr_ctx, 249 scf_instance_t *inst) 250 { 251 char nstate_name[MAX_SCF_STATE_STRING_SZ]; 252 253 bzero(nstate_name, MAX_SCF_STATE_STRING_SZ); 254 svcctl_scm_get_restarter_string_prop(mgr_ctx, inst, 255 SCF_PROPERTY_NEXT_STATE, nstate_name, sizeof (nstate_name)); 256 257 return ((*nstate_name == '\0')); 258 } 259 260 /* 261 * svcctl_scm_get_svcstate 262 * 263 * Gets the state of an SMF service. 264 */ 265 static int 266 svcctl_scm_get_svcstate(svcctl_manager_context_t *mgr_ctx, 267 char **buf, scf_walkinfo_t *wip) 268 { 269 char *state_name; 270 size_t max_state_size; 271 272 max_state_size = MAX_SCF_STATE_STRING_SZ + 1; 273 274 if ((state_name = malloc(max_state_size)) == NULL) 275 return (-1); 276 277 if (wip->pg == NULL) { 278 svcctl_scm_get_restarter_string_prop(mgr_ctx, wip->inst, 279 SCF_PROPERTY_STATE, state_name, max_state_size); 280 281 /* Don't print blank fields, to ease parsing. */ 282 if (state_name[0] == '\0') { 283 state_name[0] = '-'; 284 state_name[1] = '\0'; 285 } 286 287 if (svcctl_scm_svc_transitioning(mgr_ctx, wip->inst)) 288 /* Append an asterisk if new state is valid. */ 289 (void) strlcat(state_name, "*", max_state_size); 290 291 } else 292 (void) strlcpy(state_name, SCF_STATE_STRING_LEGACY, 293 max_state_size); 294 295 *buf = state_name; 296 return (0); 297 } 298 299 /* 300 * svcctl_scm_get_svcdesc 301 * 302 * Gets the description of an SMF service. 303 */ 304 static int 305 svcctl_scm_get_svcdesc(svcctl_manager_context_t *mgr_ctx, 306 char **buf, scf_walkinfo_t *wip) 307 { 308 char *x; 309 size_t newsize; 310 char *newbuf; 311 char *desc_buf = NULL; 312 313 if ((desc_buf = malloc(mgr_ctx->mc_scf_max_value_len + 1)) == NULL) 314 return (-1); 315 316 bzero(desc_buf, mgr_ctx->mc_scf_max_value_len + 1); 317 if (wip->pg != NULL) 318 desc_buf[0] = '-'; 319 else if (svcctl_scm_inst_get_val(mgr_ctx, wip->inst, 320 SCF_PG_TM_COMMON_NAME, "C", SCF_TYPE_USTRING, desc_buf, 321 mgr_ctx->mc_scf_max_value_len, 0, 1, 1) == -1) 322 desc_buf[0] = '-'; 323 324 /* 325 * Collapse multi-line tm_common_name values into a single line. 326 */ 327 for (x = desc_buf; *x != '\0'; x++) 328 if (*x == '\n') 329 *x = ' '; 330 331 newsize = strlen(desc_buf) + 1; 332 if ((newbuf = malloc(newsize)) == NULL) { 333 free(desc_buf); 334 return (-1); 335 } 336 337 (void) snprintf(newbuf, newsize, "%s", desc_buf); 338 free(desc_buf); 339 340 *buf = newbuf; 341 return (0); 342 } 343 344 /* 345 * svcctl_scm_get_svcfmri 346 * 347 * Gets the FMRI of an SMF service. 348 */ 349 static int 350 svcctl_scm_get_svcfmri(svcctl_manager_context_t *mgr_ctx, 351 char **buf, scf_walkinfo_t *wip) 352 { 353 size_t newsize; 354 char *newbuf; 355 char *fmri_buf = NULL; 356 void *fmri_p = NULL; 357 size_t fmri_size; 358 359 if ((fmri_buf = malloc(mgr_ctx->mc_scf_max_fmri_len + 1)) == NULL) 360 return (-1); 361 362 if (wip->pg == NULL) { 363 if (scf_instance_to_fmri(wip->inst, fmri_buf, 364 mgr_ctx->mc_scf_max_fmri_len + 1) == -1) { 365 free(fmri_buf); 366 return (-1); 367 } 368 } else { 369 (void) strlcpy(fmri_buf, SCF_FMRI_LEGACY_PREFIX, 370 mgr_ctx->mc_scf_max_fmri_len + 1); 371 372 fmri_p = fmri_buf + sizeof (SCF_FMRI_LEGACY_PREFIX) - 1; 373 fmri_size = mgr_ctx->mc_scf_max_fmri_len + 1 - \ 374 (sizeof (SCF_FMRI_LEGACY_PREFIX) - 1); 375 376 if (svcctl_scm_pg_get_val(mgr_ctx, wip->pg, 377 SCF_LEGACY_PROPERTY_NAME, SCF_TYPE_ASTRING, 378 fmri_p, fmri_size, 0) != 0) 379 (void) strlcat(fmri_buf, LEGACY_UNKNOWN, 380 mgr_ctx->mc_scf_max_fmri_len + 1); 381 } 382 383 newsize = strlen(fmri_buf) + 1; 384 if ((newbuf = malloc(newsize)) == NULL) { 385 free(fmri_buf); 386 return (-1); 387 } 388 389 (void) snprintf(newbuf, newsize, "%s", fmri_buf); 390 free(fmri_buf); 391 392 *buf = newbuf; 393 return (0); 394 } 395 396 /* 397 * svcctl_scm_get_svcname 398 * 399 * Gets the FMRI of an SMF service. 400 */ 401 static int 402 svcctl_scm_get_svcname(char **buf, char *fmri) 403 { 404 char *nm_buf = NULL; 405 char *newbuf; 406 size_t newsize; 407 408 if (fmri == NULL) 409 return (-1); 410 411 newsize = strlen(fmri); 412 if ((newbuf = malloc(newsize)) == NULL) 413 return (-1); 414 415 if ((nm_buf = strchr(fmri, '/')) == NULL) 416 return (-1); 417 418 (void) snprintf(newbuf, newsize, "%s", ++nm_buf); 419 *buf = newbuf; 420 return (0); 421 } 422 423 /* 424 * svcctl_scm_cb_list_svcinst 425 * 426 * Callback function to walk all the services in an SCF repository. 427 */ 428 static int 429 svcctl_scm_cb_list_svcinst(void *context, scf_walkinfo_t *wip) 430 { 431 svcctl_svc_node_t *node = NULL; 432 uu_avl_index_t idx; 433 svcctl_manager_context_t *mgr_ctx = (svcctl_manager_context_t *)context; 434 435 node = malloc(sizeof (*node)); 436 if (node == NULL) 437 return (-1); 438 439 node->sn_fmri = NULL; 440 if (svcctl_scm_get_svcfmri(mgr_ctx, &node->sn_fmri, wip) != 0) 441 return (-1); 442 443 node->sn_name = NULL; 444 if (svcctl_scm_get_svcname(&node->sn_name, node->sn_fmri) != 0) 445 return (-1); 446 447 node->sn_desc = NULL; 448 if (svcctl_scm_get_svcdesc(mgr_ctx, &node->sn_desc, wip) != 0) 449 return (-1); 450 451 node->sn_state = NULL; 452 if (svcctl_scm_get_svcstate(mgr_ctx, &node->sn_state, wip) != 0) 453 return (-1); 454 455 /* Insert into AVL tree. */ 456 uu_avl_node_init(node, &node->sn_node, mgr_ctx->mc_svcs_pool); 457 (void) uu_avl_find(mgr_ctx->mc_svcs, node, 458 &mgr_ctx->mc_scf_max_fmri_len, &idx); 459 uu_avl_insert(mgr_ctx->mc_svcs, node, idx); 460 461 return (0); 462 } 463 464 /* 465 * svcctl_scm_map_status 466 * 467 * Report the service status. 468 * 469 * The mapping between the Microsoft service states and SMF service states 470 * are as follows. 471 * 472 * SMF service states 473 * ================== 474 * SCF_STATE_UNINIT 0x00000001 475 * SCF_STATE_MAINT 0x00000002 476 * SCF_STATE_OFFLINE 0x00000004 477 * SCF_STATE_DISABLED 0x00000008 478 * SCF_STATE_ONLINE 0x00000010 479 * SCF_STATE_DEGRADED 0x00000020 480 * SCF_STATE_ALL 0x0000003F 481 * 482 * Microsoft service states 483 * ======================== 484 * SERVICE_CONTINUE_PENDING 0x00000005 485 * SERVICE_PAUSE_PENDING 0x00000006 486 * SERVICE_PAUSED 0x00000007 487 * SERVICE_RUNNING 0x00000004 488 * SERVICE_START_PENDING 0x00000002 489 * SERVICE_STOP_PENDING 0x00000003 490 * SERVICE_STOPPED 0x00000001 491 * 492 * Mapping 493 * ======= 494 * 495 * SCF_STATE_ONLINE <-> SERVICE_RUNNING 496 * SCF_STATE_OFFLINE <-> SERVICE_PAUSED 497 * SCF_STATE_DISABLED <-> SERVICE_STOPPED 498 * SCF_STATE_UNINIT <-> SERVICE_START_PENDING 499 * SCF_STATE_DEGRADED <-> SERVICE_STOP_PENDING 500 * SCF_STATE_MAINT <-> SERVICE_PAUSE_PENDING 501 * SCF_STATE_STRING_LEGACY <-> SERVICE_RUNNING 502 * Service Transitioning <-> SERVICE_STOP_PENDING 503 */ 504 uint32_t 505 svcctl_scm_map_status(const char *state) 506 { 507 int i; 508 509 struct { 510 const char *scf_state; 511 uint32_t scm_state; 512 } state_map[] = { 513 { SCF_STATE_STRING_ONLINE, SERVICE_RUNNING }, 514 { SCF_STATE_STRING_OFFLINE, SERVICE_PAUSED }, 515 { SCF_STATE_STRING_DISABLED, SERVICE_STOPPED }, 516 { SCF_STATE_STRING_UNINIT, SERVICE_START_PENDING }, 517 { SCF_STATE_STRING_DEGRADED, SERVICE_STOP_PENDING }, 518 { SCF_STATE_STRING_MAINT, SERVICE_PAUSE_PENDING }, 519 { SCF_STATE_STRING_LEGACY, SERVICE_RUNNING } 520 }; 521 522 for (i = 0; i < (sizeof (state_map)/sizeof (state_map[0])); ++i) { 523 if (strcmp(state, state_map[i].scf_state) == 0) 524 return (state_map[i].scm_state); 525 } 526 527 if (strrchr(state, '*') != 0) /* State Transitioning */ 528 return (SERVICE_STOP_PENDING); 529 530 return (SERVICE_RUNNING); 531 } 532 533 /* 534 * svcctl_scm_enum_services 535 * 536 * Enumerates SMF services: handles wide-char or ascii requests. 537 * 538 * Returns the number of services written to buf. 539 */ 540 uint32_t 541 svcctl_scm_enum_services(svcctl_manager_context_t *mgr_ctx, uint8_t *buf, 542 size_t buflen, uint32_t *resume_handle, boolean_t use_wchar) 543 { 544 svcctl_svc_node_t *node; 545 int base_offset, offset; 546 mts_wchar_t *w_name; 547 char *a_name; 548 char *node_name; 549 size_t namelen; 550 uint32_t numsvcs = mgr_ctx->mc_scf_numsvcs; 551 uint32_t ns; 552 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 553 svc_enum_status_t *svc = (svc_enum_status_t *)buf; 554 555 if (buf == NULL || buflen == 0 || *resume_handle >= numsvcs) { 556 *resume_handle = 0; 557 return (0); 558 } 559 560 base_offset = numsvcs * sizeof (svc_enum_status_t); 561 if (buflen < mgr_ctx->mc_bytes_needed) { 562 while (base_offset > (buflen / 4)) { 563 --numsvcs; 564 base_offset = numsvcs * sizeof (svc_enum_status_t); 565 } 566 } 567 568 offset = base_offset; 569 node = uu_avl_first(mgr_ctx->mc_svcs); 570 571 for (ns = 0; ((ns < *resume_handle) && (node != NULL)); ++ns) 572 node = uu_avl_next(mgr_ctx->mc_svcs, node); 573 574 if (node == NULL) { 575 *resume_handle = 0; 576 return (0); 577 } 578 579 for (ns = 0; ((ns < numsvcs) && (node != NULL)); ++ns) { 580 node_name = node->sn_name; 581 namelen = strlen(node_name) + 1; 582 svc[ns].svc_name = offset; 583 584 if (use_wchar) { 585 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 586 w_name = (mts_wchar_t *)&buf[offset]; 587 (void) mts_mbstowcs(w_name, node_name, namelen); 588 offset += SVCCTL_WNSTRLEN(node_name); 589 } else { 590 a_name = (char *)&buf[offset]; 591 (void) strlcpy(a_name, node_name, namelen); 592 offset += namelen; 593 } 594 595 if (offset >= buflen) 596 break; 597 598 node_name = node->sn_fmri; 599 namelen = strlen(node_name) + 1; 600 svc[ns].display_name = offset; 601 602 if (use_wchar) { 603 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 604 w_name = (mts_wchar_t *)&buf[offset]; 605 (void) mts_mbstowcs(w_name, node_name, namelen); 606 offset += SVCCTL_WNSTRLEN(node_name); 607 } else { 608 a_name = (char *)&buf[offset]; 609 (void) strlcpy(a_name, node_name, namelen); 610 offset += namelen; 611 } 612 613 if (offset >= buflen) 614 break; 615 616 svc[ns].svc_status.cur_state = 617 svcctl_scm_map_status(node->sn_state); 618 svc[ns].svc_status.service_type = SERVICE_WIN32_SHARE_PROCESS; 619 svc[ns].svc_status.ctrl_accepted = 0; 620 svc[ns].svc_status.w32_exitcode = 0; 621 svc[ns].svc_status.svc_specified_exitcode = 0; 622 svc[ns].svc_status.check_point = 0; 623 svc[ns].svc_status.wait_hint = 0; 624 625 node = uu_avl_next(mgr_ctx->mc_svcs, node); 626 } 627 628 if (node == NULL) { 629 *resume_handle = 0; 630 } else { 631 *resume_handle += ns; 632 633 if (*resume_handle >= mgr_ctx->mc_scf_numsvcs) 634 *resume_handle = 0; 635 } 636 637 return (ns); 638 } 639 640 /* 641 * svcctl_scm_cb_bytes_needed 642 * 643 * Callback function to calculate bytes needed to enumerate SMF services. 644 */ 645 static int 646 svcctl_scm_cb_bytes_needed(void *svc_node, void *byte_cnt) 647 { 648 svcctl_svc_node_t *node = svc_node; 649 int *cnt = byte_cnt; 650 651 *cnt += (strlen(node->sn_fmri) + 1) * sizeof (mts_wchar_t); 652 *cnt += (strlen(node->sn_name) + 1) * sizeof (mts_wchar_t); 653 654 return (UU_WALK_NEXT); 655 } 656 657 /* 658 * svcctl_scm_bytes_needed 659 * 660 * Calculates bytes needed to enumerate SMF services. 661 */ 662 void 663 svcctl_scm_bytes_needed(svcctl_manager_context_t *mgr_ctx) 664 { 665 int bytes_needed = 0, svc_enum_status_size = 0; 666 667 (void) uu_avl_walk(mgr_ctx->mc_svcs, svcctl_scm_cb_bytes_needed, 668 &bytes_needed, 0); 669 670 svc_enum_status_size = 671 mgr_ctx->mc_scf_numsvcs * sizeof (svc_enum_status_t); 672 bytes_needed += svc_enum_status_size; 673 674 mgr_ctx->mc_bytes_needed = bytes_needed; 675 } 676 677 /* 678 * svcctl_scm_validate_service 679 * 680 * Check to see whether or not a service is supported. 681 * 682 * Returns: 683 * ERROR_SUCCESS 684 * ERROR_SERVICE_DOES_NOT_EXIST 685 */ 686 uint32_t 687 svcctl_scm_validate_service(svcctl_manager_context_t *mgr_ctx, char *svc_name) 688 { 689 if (svcctl_scm_find_service(mgr_ctx, svc_name) != NULL) 690 return (ERROR_SUCCESS); 691 692 return (ERROR_SERVICE_DOES_NOT_EXIST); 693 } 694 695 /* 696 * svcctl_scm_map_windows_svc 697 * 698 * Windows client send windows service name. This method maps windows 699 * service names to Solaris service names. 700 */ 701 static char * 702 svcctl_scm_map_windows_svc(char *svc_name) 703 { 704 int i, size = 0; 705 struct { 706 char *win_svc_name; 707 char *solaris_svc_name; 708 } win2solaris_svc_map[] = { 709 { "eventlog", "system/system-log:default" }, 710 { "RemoteRegistry", "system/svc/restarter:default" }, 711 { "spooler", "application/print/ppd-cache-update:default" } 712 }; 713 714 size = sizeof (win2solaris_svc_map)/sizeof (win2solaris_svc_map[0]); 715 for (i = 0; i < size; ++i) { 716 if (strcasecmp(svc_name, 717 win2solaris_svc_map[i].win_svc_name) == 0) 718 return (win2solaris_svc_map[i].solaris_svc_name); 719 } 720 721 return (NULL); 722 } 723 724 /* 725 * svcctl_scm_find_service 726 * 727 * Lookup a service. 728 */ 729 svcctl_svc_node_t * 730 svcctl_scm_find_service(svcctl_manager_context_t *mgr_ctx, char *svc_name) 731 { 732 svcctl_svc_node_t node; 733 uu_avl_index_t idx; 734 svcctl_svc_node_t *f_node = NULL; 735 736 if (svc_name == NULL) 737 return (NULL); 738 739 bzero(&node, sizeof (svcctl_svc_node_t)); 740 node.sn_name = svc_name; 741 f_node = uu_avl_find(mgr_ctx->mc_svcs, &node, 742 &mgr_ctx->mc_scf_max_fmri_len, &idx); 743 if (f_node != NULL) 744 return (f_node); 745 746 bzero(&node, sizeof (svcctl_svc_node_t)); 747 node.sn_name = svcctl_scm_map_windows_svc(svc_name); 748 if (node.sn_name != NULL) 749 f_node = uu_avl_find(mgr_ctx->mc_svcs, &node, 750 &mgr_ctx->mc_scf_max_fmri_len, &idx); 751 752 return (f_node); 753 } 754 755 /* 756 * svcctl_scm_refresh 757 * 758 * Refresh SCM services per context. 759 */ 760 int 761 svcctl_scm_refresh(svcctl_manager_context_t *mgr_ctx) 762 { 763 svcctl_scm_fini(mgr_ctx); 764 return (svcctl_scm_init(mgr_ctx)); 765 } 766 767 /* 768 * svcctl_scm_scf_handle_init 769 * 770 * Initialize SCF handle per context. 771 */ 772 int 773 svcctl_scm_scf_handle_init(svcctl_manager_context_t *mgr_ctx) 774 { 775 mgr_ctx->mc_scf_hdl = scf_handle_create(SCF_VERSION); 776 if (mgr_ctx->mc_scf_hdl == NULL) 777 return (-1); 778 779 if (scf_handle_bind(mgr_ctx->mc_scf_hdl) == -1) { 780 scf_handle_destroy(mgr_ctx->mc_scf_hdl); 781 return (-1); 782 } 783 784 mgr_ctx->mc_scf_gpg = scf_pg_create(mgr_ctx->mc_scf_hdl); 785 mgr_ctx->mc_scf_gprop = scf_property_create(mgr_ctx->mc_scf_hdl); 786 mgr_ctx->mc_scf_gval = scf_value_create(mgr_ctx->mc_scf_hdl); 787 788 if ((mgr_ctx->mc_scf_gpg == NULL) || 789 (mgr_ctx->mc_scf_gprop == NULL) || 790 (mgr_ctx->mc_scf_gval == NULL)) { 791 (void) scf_handle_unbind(mgr_ctx->mc_scf_hdl); 792 scf_handle_destroy(mgr_ctx->mc_scf_hdl); 793 return (-1); 794 } 795 796 mgr_ctx->mc_scf_max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); 797 mgr_ctx->mc_scf_max_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 798 799 return (0); 800 } 801 802 /* 803 * svcctl_scm_scf_handle_init 804 * 805 * Destroy SCF handle per context. 806 */ 807 void 808 svcctl_scm_scf_handle_fini(svcctl_manager_context_t *mgr_ctx) 809 { 810 scf_value_destroy(mgr_ctx->mc_scf_gval); 811 scf_property_destroy(mgr_ctx->mc_scf_gprop); 812 scf_pg_destroy(mgr_ctx->mc_scf_gpg); 813 (void) scf_handle_unbind(mgr_ctx->mc_scf_hdl); 814 scf_handle_destroy(mgr_ctx->mc_scf_hdl); 815 } 816 817 /* 818 * svcctl_scm_init 819 * 820 * Initialize SCM repository per context. 821 * SCM repository holds a list of SMF services. 822 * Each SMF service node contains state, description and FMRI. 823 */ 824 int 825 svcctl_scm_init(svcctl_manager_context_t *mgr_ctx) 826 { 827 int exit_status = 0; 828 829 assert(mgr_ctx->mc_svcs_pool == NULL); 830 assert(mgr_ctx->mc_svcs == NULL); 831 832 mgr_ctx->mc_svcs_pool = uu_avl_pool_create("smf_svcs_pool", 833 sizeof (svcctl_svc_node_t), offsetof(svcctl_svc_node_t, sn_node), 834 svcctl_scm_avl_nodecmp, UU_AVL_DEBUG); 835 836 if (mgr_ctx->mc_svcs_pool == NULL) 837 return (-1); 838 839 mgr_ctx->mc_svcs = uu_avl_create(mgr_ctx->mc_svcs_pool, NULL, 0); 840 if (mgr_ctx->mc_svcs == NULL) { 841 uu_avl_pool_destroy(mgr_ctx->mc_svcs_pool); 842 return (-1); 843 } 844 845 if (scf_walk_fmri(mgr_ctx->mc_scf_hdl, 0, NULL, 846 SCF_WALK_MULTIPLE | SCF_WALK_LEGACY, 847 svcctl_scm_cb_list_svcinst, mgr_ctx, &exit_status, NULL) != 0) { 848 uu_avl_destroy(mgr_ctx->mc_svcs); 849 uu_avl_pool_destroy(mgr_ctx->mc_svcs_pool); 850 return (-1); 851 } 852 853 mgr_ctx->mc_scf_numsvcs = uu_avl_numnodes(mgr_ctx->mc_svcs); 854 if (mgr_ctx->mc_scf_numsvcs > 0) 855 svcctl_scm_bytes_needed(mgr_ctx); 856 857 return (0); 858 } 859 860 /* 861 * svcctl_scm_fini 862 * 863 * Destroy SCM repository per context. 864 */ 865 void 866 svcctl_scm_fini(svcctl_manager_context_t *mgr_ctx) 867 { 868 uu_avl_walk_t *walk; 869 svcctl_svc_node_t *node; 870 871 if ((mgr_ctx == NULL) || (mgr_ctx->mc_svcs_pool == NULL) || 872 (mgr_ctx->mc_svcs == NULL)) 873 return; 874 875 if ((walk = 876 uu_avl_walk_start(mgr_ctx->mc_svcs, UU_WALK_ROBUST)) == NULL) 877 return; 878 879 while ((node = uu_avl_walk_next(walk)) != NULL) { 880 uu_avl_remove(mgr_ctx->mc_svcs, node); 881 free(node->sn_name); 882 free(node->sn_fmri); 883 free(node->sn_desc); 884 free(node->sn_state); 885 free(node); 886 } 887 uu_avl_walk_end(walk); 888 uu_avl_destroy(mgr_ctx->mc_svcs); 889 uu_avl_pool_destroy(mgr_ctx->mc_svcs_pool); 890 mgr_ctx->mc_svcs_pool = NULL; 891 mgr_ctx->mc_svcs = NULL; 892 } 893