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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * inetadm - administer services controlled by inetd and print out inetd 29 * service related information. 30 */ 31 32 #include <locale.h> 33 #include <libintl.h> 34 #include <libscf.h> 35 #include <libscf_priv.h> 36 #include <libuutil.h> 37 #include <stddef.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <syslog.h> 42 #include <inetsvc.h> 43 #include <errno.h> 44 45 #ifndef TEXT_DOMAIN 46 #define TEXT_DOMAIN "SUNW_OST_OSCMD" 47 #endif /* TEXT_DOMAIN */ 48 49 /* Strings for output to the user, and checking user's input */ 50 51 #define INETADM_TRUE_STR "TRUE" 52 #define INETADM_FALSE_STR "FALSE" 53 #define INETADM_ENABLED_STR "enabled" 54 #define INETADM_DISABLED_STR "disabled" 55 #define INETADM_DEFAULT_STR "default" 56 57 /* String for checking if an instance is under inetd's control. */ 58 59 #define INETADM_INETD_STR "network/inetd" 60 61 /* 62 * Used to hold a list of scf_value_t's whilst performing a transaction 63 * to write a proto list back. 64 */ 65 typedef struct scf_val_el { 66 scf_value_t *val; 67 uu_list_node_t link; 68 } scf_val_el_t; 69 70 /* 71 * Structure used to encapsulate argc and argv so they can be passed using the 72 * single data argument supplied by scf_walk_fmri() for the consumption of 73 * modify_inst_props_cb(). 74 */ 75 typedef struct arglist { 76 int argc; 77 char **argv; 78 } arglist_t; 79 80 static scf_handle_t *h; 81 82 static void 83 scfdie() 84 { 85 uu_die(gettext("Unexpected libscf error: %s. Exiting.\n"), 86 scf_strerror(scf_error())); 87 } 88 89 static void 90 usage(boolean_t detailed) 91 { 92 93 uu_warn(gettext( 94 "Usage:\n" 95 " inetadm\n" 96 " inetadm -?\n" 97 " inetadm -p\n" 98 " inetadm -l {FMRI | pattern}...\n" 99 " inetadm -e {FMRI | pattern}...\n" 100 " inetadm -d {FMRI | pattern}...\n" 101 " inetadm -m {FMRI | pattern}... {name=value}...\n" 102 " inetadm -M {name=value}...\n")); 103 104 if (!detailed) 105 exit(UU_EXIT_USAGE); 106 107 (void) fprintf(stdout, gettext( 108 "\n" 109 "Without any options inetadm lists all inetd managed services.\n" 110 "\n" 111 "Options:\n" 112 " -? Print help.\n" 113 " -p List all default inetd property values.\n" 114 " -l List all inetd property values for the inet " 115 "service(s).\n" 116 " -e Enable the inet service(s).\n" 117 " -d Disable the inet service(s).\n" 118 " -m Modify the inet service(s) inetd property values.\n" 119 " -M Modify default inetd property values.\n")); 120 } 121 122 /* 123 * Add the proto list contained in array 'plist' to entry 'entry', storing 124 * aside the scf_value_t's created and added to the entry in a list that the 125 * pointer referenced by sv_list is made to point at. 126 */ 127 static void 128 add_proto_list(scf_transaction_entry_t *entry, scf_handle_t *hdl, 129 char **plist, uu_list_t **sv_list) 130 { 131 scf_val_el_t *sv_el; 132 int i; 133 134 static uu_list_pool_t *sv_pool = NULL; 135 136 if ((sv_pool == NULL) && 137 ((sv_pool = uu_list_pool_create("sv_pool", 138 sizeof (scf_val_el_t), offsetof(scf_val_el_t, link), NULL, 139 UU_LIST_POOL_DEBUG)) == NULL)) 140 uu_die(gettext("Error: %s.\n"), uu_strerror(uu_error())); 141 142 if ((*sv_list = uu_list_create(sv_pool, NULL, 0)) == NULL) 143 uu_die(gettext("Error: %s.\n"), uu_strerror(uu_error())); 144 145 for (i = 0; plist[i] != NULL; i++) { 146 if ((sv_el = malloc(sizeof (scf_val_el_t))) == NULL) 147 uu_die(gettext("Error:")); 148 149 if (((sv_el->val = scf_value_create(hdl)) == NULL) || 150 (scf_value_set_astring(sv_el->val, plist[i]) != 0) || 151 (scf_entry_add_value(entry, sv_el->val) != 0)) 152 scfdie(); 153 154 uu_list_node_init(sv_el, &sv_el->link, sv_pool); 155 (void) uu_list_insert_after(*sv_list, NULL, sv_el); 156 } 157 } 158 159 /* 160 * A counterpart to add_proto_list(), this function removes and frees the 161 * scf_value_t's it added to entry 'entry'. 162 */ 163 static void 164 remove_proto_list(scf_transaction_entry_t *entry, uu_list_t *sv_list) 165 { 166 scf_val_el_t *sv_el; 167 void *cookie = NULL; 168 169 scf_entry_reset(entry); 170 171 while ((sv_el = uu_list_teardown(sv_list, &cookie)) != NULL) { 172 scf_value_destroy(sv_el->val); 173 free(sv_el); 174 } 175 176 uu_list_destroy(sv_list); 177 } 178 179 /* 180 * modify_prop takes an instance, property group, property name, type, and 181 * value, and modifies the specified property in the repository to the 182 * submitted value. 183 */ 184 185 static void 186 modify_prop(const scf_instance_t *inst, const char *pg, const char *prop, 187 scf_type_t type, void *value) 188 { 189 scf_transaction_t *tx; 190 scf_transaction_entry_t *ent; 191 scf_propertygroup_t *gpg; 192 scf_property_t *eprop; 193 scf_value_t *v; 194 int ret, create = 0; 195 char *fmri; 196 ssize_t max_fmri_len; 197 198 if ((gpg = scf_pg_create(h)) == NULL || 199 (eprop = scf_property_create(h)) == NULL || 200 (v = scf_value_create(h)) == NULL) 201 scfdie(); 202 203 /* Get the property group or create it if it is missing. */ 204 if (scf_instance_get_pg(inst, pg, gpg) == -1) { 205 if (scf_error() != SCF_ERROR_NOT_FOUND) 206 scfdie(); 207 208 max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); 209 if ((fmri = malloc(max_fmri_len + 1)) == NULL) 210 uu_die(gettext("Error: Out of memory.\n")); 211 212 if (scf_instance_to_fmri(inst, fmri, max_fmri_len + 1) < 0) 213 scfdie(); 214 215 syslog(LOG_NOTICE, "inetadm: Property group \"%s\" missing " 216 "from \"%s\", attempting to add it.\n", pg, fmri); 217 free(fmri); 218 219 if (scf_instance_add_pg(inst, pg, SCF_GROUP_FRAMEWORK, 0, 220 gpg) == -1) { 221 switch (scf_error()) { 222 case SCF_ERROR_EXISTS: 223 break; 224 case SCF_ERROR_PERMISSION_DENIED: 225 uu_die(gettext("Error: Permission denied.\n")); 226 default: 227 scfdie(); 228 } 229 } 230 } 231 232 if (scf_pg_get_property(gpg, prop, eprop) == -1) { 233 if (scf_error() != SCF_ERROR_NOT_FOUND) 234 scfdie(); 235 236 create = 1; 237 } 238 239 if ((tx = scf_transaction_create(h)) == NULL || 240 (ent = scf_entry_create(h)) == NULL) 241 scfdie(); 242 243 do { 244 uu_list_t *sv_list; 245 246 if (scf_transaction_start(tx, gpg) == -1) { 247 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 248 scfdie(); 249 250 uu_die(gettext("Error: Permission denied.\n")); 251 } 252 253 /* Modify the property or create it if it is missing */ 254 if (create) 255 ret = scf_transaction_property_new(tx, ent, prop, type); 256 else 257 ret = scf_transaction_property_change_type(tx, ent, 258 prop, type); 259 if (ret == -1) 260 scfdie(); 261 262 switch (type) { 263 case SCF_TYPE_BOOLEAN: 264 scf_value_set_boolean(v, *(uint8_t *)value); 265 break; 266 case SCF_TYPE_INTEGER: 267 scf_value_set_integer(v, *(int64_t *)value); 268 break; 269 case SCF_TYPE_ASTRING: 270 if (strcmp(prop, PR_PROTO_NAME) == 0) { 271 add_proto_list(ent, h, (char **)value, 272 &sv_list); 273 } else if (scf_value_set_astring(v, value) == -1) { 274 scfdie(); 275 } 276 break; 277 default: 278 uu_die(gettext("Error: Internal inetadm error")); 279 } 280 281 if ((strcmp(prop, PR_PROTO_NAME) != 0) && 282 (scf_entry_add_value(ent, v) == -1)) 283 scfdie(); 284 285 ret = scf_transaction_commit(tx); 286 if (ret == -1) { 287 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 288 scfdie(); 289 290 uu_die(gettext("Error: Permission denied.\n")); 291 } 292 293 scf_transaction_reset(tx); 294 295 if (ret == 0) { 296 if (scf_pg_update(gpg) == -1) 297 scfdie(); 298 } 299 300 if (strcmp(prop, PR_PROTO_NAME) == 0) 301 remove_proto_list(ent, sv_list); 302 303 } while (ret == 0); 304 305 scf_value_destroy(v); 306 scf_entry_destroy(ent); 307 scf_transaction_destroy(tx); 308 scf_property_destroy(eprop); 309 scf_pg_destroy(gpg); 310 } 311 312 /* 313 * delete_prop takes an instance, property group name and property, and 314 * deletes the specified property from the repository. 315 */ 316 317 static void 318 delete_prop(const scf_instance_t *inst, const char *pg, const char *prop) 319 { 320 scf_transaction_t *tx; 321 scf_transaction_entry_t *ent; 322 scf_propertygroup_t *gpg; 323 scf_property_t *eprop; 324 int ret; 325 326 if ((gpg = scf_pg_create(h)) == NULL || 327 (eprop = scf_property_create(h)) == NULL || 328 (tx = scf_transaction_create(h)) == NULL || 329 (ent = scf_entry_create(h)) == NULL) 330 scfdie(); 331 332 if (scf_instance_get_pg(inst, pg, gpg) != SCF_SUCCESS) { 333 if (scf_error() != SCF_ERROR_NOT_FOUND) 334 scfdie(); 335 336 uu_die(gettext("Error: \"%s\" property group missing.\n"), pg); 337 } 338 339 do { 340 if (scf_transaction_start(tx, gpg) != SCF_SUCCESS) { 341 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 342 scfdie(); 343 344 uu_die(gettext("Error: Permission denied.\n")); 345 } 346 347 if (scf_transaction_property_delete(tx, ent, 348 prop) != SCF_SUCCESS) { 349 if (scf_error() != SCF_ERROR_NOT_FOUND) 350 scfdie(); 351 352 uu_die( 353 gettext("Error: \"%s\" property does not exist.\n"), 354 prop); 355 } 356 357 ret = scf_transaction_commit(tx); 358 if (ret < 0) { 359 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 360 scfdie(); 361 362 uu_die(gettext("Error: Permission denied.\n")); 363 } 364 if (ret == 0) { 365 scf_transaction_reset(tx); 366 if (scf_pg_update(gpg) == -1) 367 scfdie(); 368 } 369 } while (ret == 0); 370 371 (void) scf_entry_destroy(ent); 372 scf_transaction_destroy(tx); 373 scf_property_destroy(eprop); 374 scf_pg_destroy(gpg); 375 } 376 377 /* 378 * commit_props evaluates an entire property list that has been created 379 * based on command line options, and either deletes or modifies properties 380 * as requested. 381 */ 382 383 static void 384 commit_props(const scf_instance_t *inst, inetd_prop_t *mod, boolean_t defaults) 385 { 386 int i; 387 uint8_t new_bool; 388 389 for (i = 0; mod[i].ip_name != NULL; i++) { 390 switch (mod[i].ip_error) { 391 case IVE_UNSET: 392 break; 393 case IVE_INVALID: 394 delete_prop(inst, mod[i].ip_pg, mod[i].ip_name); 395 break; 396 case IVE_VALID: 397 switch (mod[i].ip_type) { 398 case INET_TYPE_STRING: 399 modify_prop(inst, 400 defaults ? PG_NAME_SERVICE_DEFAULTS : 401 mod[i].ip_pg, mod[i].ip_name, 402 SCF_TYPE_ASTRING, 403 mod[i].ip_value.iv_string); 404 break; 405 case INET_TYPE_STRING_LIST: 406 modify_prop(inst, 407 defaults ? PG_NAME_SERVICE_DEFAULTS : 408 mod[i].ip_pg, mod[i].ip_name, 409 SCF_TYPE_ASTRING, 410 mod[i].ip_value.iv_string_list); 411 break; 412 case INET_TYPE_INTEGER: 413 modify_prop(inst, 414 defaults ? PG_NAME_SERVICE_DEFAULTS : 415 mod[i].ip_pg, mod[i].ip_name, 416 SCF_TYPE_INTEGER, &mod[i].ip_value.iv_int); 417 break; 418 case INET_TYPE_BOOLEAN: 419 new_bool = (mod[i].ip_value.iv_boolean) ? 1 : 0; 420 421 modify_prop(inst, 422 defaults ? PG_NAME_SERVICE_DEFAULTS : 423 mod[i].ip_pg, mod[i].ip_name, 424 SCF_TYPE_BOOLEAN, &new_bool); 425 break; 426 } 427 } 428 } 429 } 430 431 /* 432 * list_callback is the callback function to be handed to simple_walk_instances 433 * in list_services. It is called once on every instance on a machine. If 434 * that instance is controlled by inetd, it prints enabled/disabled, state, 435 * and instance FMRI. 436 */ 437 438 /*ARGSUSED*/ 439 static int 440 list_callback(scf_handle_t *hin, scf_instance_t *inst, void *buf) 441 { 442 ssize_t max_name_length; 443 char *inst_name; 444 scf_simple_prop_t *prop = NULL, *prop2 = NULL; 445 const uint8_t *enabled; 446 const char *state, *restart_str; 447 448 max_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 449 if ((inst_name = malloc(max_name_length + 1)) == NULL) 450 uu_die(gettext("Error: Out of memory.\n")); 451 452 /* 453 * Get the FMRI of the instance, and check if its delegated restarter 454 * is inetd. 455 */ 456 457 if (scf_instance_to_fmri(inst, inst_name, max_name_length + 1) < 0) 458 return (SCF_FAILED); 459 460 if ((prop = scf_simple_prop_get(hin, inst_name, SCF_PG_GENERAL, 461 SCF_PROPERTY_RESTARTER)) == NULL) 462 goto out; 463 464 if ((restart_str = scf_simple_prop_next_ustring(prop)) == NULL) 465 goto out; 466 467 if (strstr(restart_str, INETADM_INETD_STR) == NULL) 468 goto out; 469 470 /* Free restarter prop so it can be reused below */ 471 scf_simple_prop_free(prop); 472 473 /* 474 * We know that this instance is managed by inetd. 475 * Now get the enabled and state properties. 476 */ 477 478 if (((prop = scf_simple_prop_get(hin, inst_name, SCF_PG_GENERAL, 479 SCF_PROPERTY_ENABLED)) == NULL) || 480 ((enabled = scf_simple_prop_next_boolean(prop)) == NULL)) { 481 (void) uu_warn(gettext("Error: Instance %s is missing enabled " 482 "property.\n"), inst_name); 483 goto out; 484 } 485 486 if (((prop2 = scf_simple_prop_get(hin, inst_name, SCF_PG_RESTARTER, 487 SCF_PROPERTY_STATE)) == NULL) || 488 ((state = scf_simple_prop_next_astring(prop2)) == NULL)) { 489 (void) uu_warn(gettext("Error: Instance %s is missing state " 490 "property.\n"), inst_name); 491 goto out; 492 } 493 494 /* Print enabled/disabled, state, and FMRI for the instance. */ 495 496 if (*enabled) 497 (void) printf("%-10s%-15s%s\n", INETADM_ENABLED_STR, state, 498 inst_name); 499 else 500 (void) printf("%-10s%-15s%s\n", INETADM_DISABLED_STR, state, 501 inst_name); 502 503 out: 504 free(inst_name); 505 scf_simple_prop_free(prop); 506 scf_simple_prop_free(prop2); 507 return (SCF_SUCCESS); 508 } 509 510 /* 511 * list_services calls list_callback on every instance on the machine. 512 */ 513 514 static void 515 list_services() 516 { 517 (void) printf("%-10s%-15s%s\n", "ENABLED", "STATE", "FMRI"); 518 519 if (scf_simple_walk_instances(SCF_STATE_ALL, NULL, list_callback) == 520 SCF_FAILED) 521 scfdie(); 522 } 523 524 static void 525 print_prop_val(inetd_prop_t *prop) 526 { 527 switch (prop->ip_type) { 528 case INET_TYPE_STRING: 529 (void) printf("\"%s\"\n", prop->ip_value.iv_string); 530 break; 531 case INET_TYPE_STRING_LIST: 532 { 533 int j = 0; 534 char **cpp = prop->ip_value.iv_string_list; 535 536 /* 537 * Print string list as comma separated list. 538 */ 539 540 (void) printf("\"%s", cpp[j]); 541 while (cpp[++j] != NULL) 542 (void) printf(",%s", cpp[j]); 543 (void) printf("\"\n"); 544 } 545 break; 546 case INET_TYPE_INTEGER: 547 (void) printf("%lld\n", prop->ip_value.iv_int); 548 break; 549 case INET_TYPE_BOOLEAN: 550 if (prop->ip_value.iv_boolean) 551 (void) printf("%s\n", INETADM_TRUE_STR); 552 else 553 (void) printf("%s\n", INETADM_FALSE_STR); 554 break; 555 } 556 } 557 558 /* 559 * list_props_cb is a callback function for scf_walk_fmri that lists all 560 * relevant inetd properties for an instance managed by inetd. 561 */ 562 563 /* ARGSUSED0 */ 564 static int 565 list_props_cb(void *data, scf_walkinfo_t *wip) 566 { 567 int i; 568 const char *instname = wip->fmri; 569 scf_simple_prop_t *prop; 570 inetd_prop_t *proplist; 571 const char *restart_str; 572 boolean_t is_rpc = B_FALSE; 573 size_t numprops; 574 scf_handle_t *h; 575 scf_error_t err; 576 577 if (((h = scf_handle_create(SCF_VERSION)) == NULL) || 578 (scf_handle_bind(h) == -1)) 579 scfdie(); 580 581 /* 582 * Get the property that holds the name of this instance's 583 * restarter, and make sure that it is inetd. 584 */ 585 if ((prop = scf_simple_prop_get(h, instname, SCF_PG_GENERAL, 586 SCF_PROPERTY_RESTARTER)) == NULL) { 587 if (scf_error() == SCF_ERROR_NOT_FOUND) 588 uu_die(gettext("Error: Specified service instance " 589 "\"%s\" has no restarter property. inetd is not " 590 "the delegated restarter of this instance.\n"), 591 instname); 592 if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) 593 uu_die(gettext("Error: \"%s\" is not a valid service " 594 "instance.\n"), instname); 595 596 scfdie(); 597 } 598 599 if (((restart_str = scf_simple_prop_next_ustring(prop)) == NULL) || 600 (strstr(restart_str, INETADM_INETD_STR) == NULL)) { 601 uu_die(gettext("Error: inetd is not the delegated restarter of " 602 "specified service instance \"%s\".\n"), instname); 603 } 604 605 scf_simple_prop_free(prop); 606 607 /* 608 * This instance is controlled by inetd, so now we display all 609 * of its properties. First the mandatory properties, and then 610 * the properties that have default values, substituting the 611 * default values inherited from inetd as necessary (this is done 612 * for us by read_instance_props()). 613 */ 614 615 if ((proplist = read_instance_props(h, instname, &numprops, &err)) == 616 NULL) { 617 uu_die(gettext("Unexpected libscf error: %s. Exiting.\n"), 618 scf_strerror(err)); 619 } 620 scf_handle_destroy(h); 621 622 (void) printf("%-9s%s\n", "SCOPE", "NAME=VALUE"); 623 624 for (i = 0; i < numprops; i++) { 625 /* Skip rpc version properties if it's not an RPC service */ 626 if ((strcmp(PR_RPC_LW_VER_NAME, proplist[i].ip_name) == 0) || 627 (strcmp(PR_RPC_HI_VER_NAME, proplist[i].ip_name) == 0)) 628 if (!is_rpc) 629 continue; 630 631 /* If it's not an unset property, print it out. */ 632 if (proplist[i].ip_error != IVE_UNSET) { 633 if (strcmp(PR_ISRPC_NAME, proplist[i].ip_name) == 0) 634 is_rpc = proplist[i].ip_value.iv_boolean; 635 636 (void) printf("%-9s%s=", 637 proplist[i].from_inetd ? INETADM_DEFAULT_STR : "", 638 proplist[i].ip_name); 639 print_prop_val(&proplist[i]); 640 continue; 641 } 642 643 /* arg0 is non-default, but also doesn't have to be set. */ 644 645 if (i == PT_ARG0_INDEX) 646 continue; 647 648 /* all other properties should have values. */ 649 if (proplist[i].ip_default) { 650 (void) uu_warn(gettext("Error: Property %s is missing " 651 "and has no defined default value.\n"), 652 proplist[i].ip_name); 653 } else { 654 (void) uu_warn(gettext("Error: Required property %s is " 655 "missing.\n"), proplist[i].ip_name); 656 } 657 } 658 659 free_instance_props(proplist); 660 return (0); 661 } 662 663 /* 664 * set_svc_enable_cb is a callback function for scf_walk_fmri that sets the 665 * enabled property in the repository for an instance based on the value given 666 * by 'data'. 667 */ 668 669 static int 670 set_svc_enable_cb(void *data, scf_walkinfo_t *wip) 671 { 672 uint8_t desired = *(uint8_t *)data; 673 const char *instname = wip->fmri; 674 675 if (desired) { 676 if (smf_enable_instance(instname, 0) == 0) 677 return (0); 678 } else { 679 if (smf_disable_instance(instname, 0) == 0) 680 return (0); 681 } 682 683 switch (scf_error()) { 684 case SCF_ERROR_INVALID_ARGUMENT: 685 uu_die(gettext("Error: \"%s\" is not a valid service " 686 "instance.\n"), instname); 687 break; 688 case SCF_ERROR_NOT_FOUND: 689 uu_die(gettext("Error: Service instance \"%s\" not found.\n"), 690 instname); 691 break; 692 default: 693 scfdie(); 694 } 695 696 return (0); 697 } 698 699 /* 700 * list_defaults lists all the default property values being provided by 701 * inetd. 702 */ 703 704 static void 705 list_defaults() 706 { 707 scf_handle_t *h; 708 scf_error_t err; 709 int i; 710 inetd_prop_t *proptable; 711 size_t numprops; 712 713 if (((h = scf_handle_create(SCF_VERSION)) == NULL) || 714 (scf_handle_bind(h) == -1)) 715 scfdie(); 716 717 if ((proptable = read_default_props(h, &numprops, &err)) == NULL) { 718 uu_die(gettext("Unexpected libscf error: %s. Exiting.\n"), 719 scf_strerror(err)); 720 } 721 722 (void) printf("NAME=VALUE\n"); 723 724 for (i = 0; i < numprops; i++) { 725 if (!proptable[i].ip_default) 726 continue; 727 728 if (proptable[i].ip_error == IVE_UNSET) { 729 (void) uu_warn(gettext("Error: Default property %s " 730 "missing.\n"), proptable[i].ip_name); 731 continue; 732 } 733 734 (void) printf("%s=", proptable[i].ip_name); 735 print_prop_val(&proptable[i]); 736 } 737 738 free_instance_props(proptable); 739 } 740 741 /* 742 * modify_inst_props_cb is a callback function for scf_walk_fmri that modifies 743 * the properties that are given as name=value pairs on the command line 744 * to the requested value. 745 */ 746 747 static int 748 modify_inst_props_cb(void *data, scf_walkinfo_t *wip) 749 { 750 int i, j; 751 char *value; 752 const char *fmri = wip->fmri; 753 scf_instance_t *inst = wip->inst; 754 inetd_prop_t *mod, *prop_table; 755 size_t numprops; 756 ssize_t max_val; 757 int64_t new_int; 758 int argc = ((arglist_t *)data)->argc; 759 char **argv = ((arglist_t *)data)->argv; 760 761 if ((max_val = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0) 762 scfdie(); 763 764 prop_table = get_prop_table(&numprops); 765 766 if ((mod = malloc(numprops * sizeof (inetd_prop_t))) == NULL) 767 uu_die(gettext("Error: Out of memory.\n")); 768 769 (void) memcpy(mod, prop_table, numprops * sizeof (inetd_prop_t)); 770 771 /* 772 * For each property to be changed, look up the property name in the 773 * property table. Change each property in the mod array, and then 774 * write the entire thing back. 775 */ 776 for (i = 0; i < argc; i++) { 777 /* Separate argument into name and value pair */ 778 if ((value = strchr(argv[i], '=')) == NULL) 779 uu_die(gettext("Error: Malformed name=value pair " 780 "\"%s\"\n"), argv[i]); 781 782 *value = '\0'; 783 value++; 784 785 /* Find property name in array of properties */ 786 for (j = 0; mod[j].ip_name != NULL; j++) { 787 if (strcmp(mod[j].ip_name, argv[i]) == 0) 788 break; 789 } 790 791 if (mod[j].ip_name == NULL) 792 uu_die(gettext("Error: \"%s\" is not a valid " 793 "property.\n"), argv[i]); 794 795 if (*value == '\0') { 796 if ((mod[j].ip_default) || (j == PT_ARG0_INDEX)) { 797 /* mark property for deletion */ 798 mod[j].ip_error = IVE_INVALID; 799 800 /* return the '=' taken out above */ 801 *(--value) = '='; 802 803 continue; 804 } else { 805 uu_die(gettext("\"%s\" is a mandatory " 806 "property and can not be deleted.\n"), 807 argv[i]); 808 } 809 } 810 811 switch (mod[j].ip_type) { 812 case INET_TYPE_INTEGER: 813 if (uu_strtoint(value, &new_int, sizeof (new_int), NULL, 814 NULL, NULL) == -1) 815 uu_die(gettext("Error: \"%s\" is not a valid " 816 "integer value.\n"), value); 817 818 mod[j].ip_value.iv_int = new_int; 819 break; 820 case INET_TYPE_STRING: 821 if (strlen(value) >= max_val) { 822 uu_die(gettext("Error: String value is longer " 823 "than %l characters.\n"), max_val); 824 } else if ((mod[j].ip_value.iv_string = strdup(value)) 825 == NULL) { 826 uu_die(gettext("Error: Out of memory.\n")); 827 } 828 break; 829 case INET_TYPE_STRING_LIST: 830 if ((mod[j].ip_value.iv_string_list = 831 get_protos(value)) == NULL) { 832 if (errno == ENOMEM) { 833 uu_die(gettext( 834 "Error: Out of memory.\n")); 835 } else if (errno == E2BIG) { 836 uu_die(gettext( 837 "Error: String value in " 838 "%s property longer than " 839 "%l characters.\n"), 840 PR_PROTO_NAME, max_val); 841 } else { 842 uu_die(gettext( 843 "Error: No values " 844 "specified for %s " 845 "property.\n"), 846 PR_PROTO_NAME); 847 } 848 } 849 break; 850 case INET_TYPE_BOOLEAN: 851 if (strcasecmp(value, INETADM_TRUE_STR) == 0) 852 mod[j].ip_value.iv_boolean = B_TRUE; 853 else if (strcasecmp(value, INETADM_FALSE_STR) == 0) 854 mod[j].ip_value.iv_boolean = B_FALSE; 855 else 856 uu_die(gettext("Error: \"%s\" is not a valid " 857 "boolean value. (TRUE or FALSE)\n"), value); 858 } 859 /* mark property for modification */ 860 mod[j].ip_error = IVE_VALID; 861 862 /* return the '=' taken out above */ 863 *(--value) = '='; 864 } 865 866 commit_props(inst, mod, B_FALSE); 867 free(mod); 868 if (smf_refresh_instance(fmri) != 0) 869 uu_die(gettext("Error: Unable to refresh instance %s.\n"), 870 fmri); 871 872 return (0); 873 } 874 875 /* 876 * modify_defaults takes n name=value pairs for inetd default property values, 877 * parses them, and then modifies the values in the repository. 878 */ 879 880 static void 881 modify_defaults(int argc, char *argv[]) 882 { 883 int i, j; 884 char *value; 885 scf_instance_t *inst; 886 inetd_prop_t *mod, *prop_table; 887 size_t numprops; 888 ssize_t max_val; 889 int64_t new_int; 890 891 if ((inst = scf_instance_create(h)) == NULL) 892 scfdie(); 893 894 if (scf_handle_decode_fmri(h, INETD_INSTANCE_FMRI, NULL, NULL, 895 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) { 896 if (scf_error() == SCF_ERROR_NOT_FOUND) { 897 uu_die(gettext("inetd instance missing in repository." 898 "\n")); 899 } else { 900 scfdie(); 901 } 902 } 903 904 if ((max_val = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0) 905 scfdie(); 906 907 prop_table = get_prop_table(&numprops); 908 909 if ((mod = malloc(numprops * sizeof (inetd_prop_t))) == NULL) 910 uu_die(gettext("Error: Out of memory.\n")); 911 912 (void) memcpy(mod, prop_table, numprops * sizeof (inetd_prop_t)); 913 914 for (i = 0; i < argc; i++) { 915 /* Separate argument into name and value pair */ 916 if ((value = strchr(argv[i], '=')) == NULL) 917 uu_die(gettext("Error: Malformed name=value pair \"%s" 918 "\"\n"), argv[i]); 919 920 *value = '\0'; 921 value++; 922 923 /* Find property name in array of defaults */ 924 for (j = 0; mod[j].ip_name != NULL; j++) { 925 if (!mod[j].ip_default) 926 continue; 927 if (strcmp(mod[j].ip_name, argv[i]) == 0) 928 break; 929 } 930 931 if (mod[j].ip_name == NULL) 932 uu_die(gettext("Error: \"%s\" is not a default inetd " 933 "property.\n"), argv[i]); 934 935 if (*value == '\0') 936 uu_die(gettext("Cannot accept NULL values for default " 937 "properties.\n")); 938 939 switch (mod[j].ip_type) { 940 case INET_TYPE_INTEGER: 941 if (uu_strtoint(value, &new_int, sizeof (new_int), NULL, 942 NULL, NULL) == -1) 943 uu_die(gettext("Error: \"%s\" is not a valid " 944 "integer value.\n"), value); 945 946 mod[j].ip_value.iv_int = new_int; 947 break; 948 case INET_TYPE_STRING: 949 if (strlen(value) >= max_val) 950 uu_die(gettext("Error: String value is longer " 951 "than %l characters.\n"), max_val); 952 if ((mod[j].ip_value.iv_string = strdup(value)) 953 == NULL) 954 uu_die(gettext("Error: Out of memory.\n")); 955 break; 956 case INET_TYPE_BOOLEAN: 957 if (strcasecmp(value, INETADM_TRUE_STR) == 0) 958 mod[j].ip_value.iv_boolean = B_TRUE; 959 else if (strcasecmp(value, INETADM_FALSE_STR) == 0) 960 mod[j].ip_value.iv_boolean = B_FALSE; 961 else 962 uu_die(gettext("Error: \"%s\" is not a valid " 963 "boolean value. (TRUE or FALSE)\n"), value); 964 } 965 /* mark property for modification */ 966 mod[j].ip_error = IVE_VALID; 967 } 968 969 commit_props(inst, mod, B_TRUE); 970 free(mod); 971 scf_instance_destroy(inst); 972 if (refresh_inetd() != 0) 973 uu_warn(gettext("Warning: Unable to refresh inetd.\n")); 974 } 975 976 int 977 main(int argc, char *argv[]) 978 { 979 int opt; 980 uint_t lflag, eflag, dflag, pflag, mflag, Mflag; 981 uint8_t enable; 982 scf_error_t serr; 983 int exit_status = 0; 984 985 (void) setlocale(LC_ALL, ""); 986 (void) textdomain(TEXT_DOMAIN); 987 988 if ((h = scf_handle_create(SCF_VERSION)) == NULL) 989 scfdie(); 990 991 if (scf_handle_bind(h) == -1) 992 uu_die(gettext("Error: Couldn't bind to svc.configd.\n")); 993 994 if (argc == 1) { 995 list_services(); 996 goto out; 997 } 998 999 lflag = eflag = dflag = pflag = mflag = Mflag = 0; 1000 while ((opt = getopt(argc, argv, "ledpMm?")) != -1) { 1001 switch (opt) { 1002 case 'l': 1003 lflag = 1; 1004 break; 1005 case 'e': 1006 eflag = 1; 1007 break; 1008 case 'd': 1009 dflag = 1; 1010 break; 1011 case 'p': 1012 pflag = 1; 1013 break; 1014 case 'M': 1015 Mflag = 1; 1016 break; 1017 case 'm': 1018 mflag = 1; 1019 break; 1020 case '?': 1021 if (optopt == '?') { 1022 usage(B_TRUE); 1023 goto out; 1024 } else { 1025 usage(B_FALSE); 1026 } 1027 break; 1028 default: 1029 usage(B_FALSE); 1030 } 1031 } 1032 1033 /* 1034 * All options are mutually exclusive, and we must have an option 1035 * if we reached here. 1036 */ 1037 if (lflag + eflag + dflag + pflag + mflag + Mflag != 1) 1038 usage(B_FALSE); 1039 1040 argv += optind; 1041 argc -= optind; 1042 if ((pflag == 0) && (argc == 0)) 1043 usage(B_FALSE); 1044 1045 serr = 0; 1046 if (lflag) { 1047 serr = scf_walk_fmri(h, argc, argv, 0, list_props_cb, NULL, 1048 &exit_status, uu_warn); 1049 } else if (dflag) { 1050 enable = 0; 1051 serr = scf_walk_fmri(h, argc, argv, 0, set_svc_enable_cb, 1052 &enable, &exit_status, uu_warn); 1053 } else if (eflag) { 1054 enable = 1; 1055 serr = scf_walk_fmri(h, argc, argv, 0, set_svc_enable_cb, 1056 &enable, &exit_status, uu_warn); 1057 } else if (mflag) { 1058 arglist_t args; 1059 char **cpp = argv; 1060 uint_t fmri_args = 0; 1061 1062 /* count number of fmri arguments */ 1063 while ((fmri_args < argc) && (strchr(*cpp, '=') == NULL)) { 1064 fmri_args++; 1065 cpp++; 1066 } 1067 1068 /* if no x=y args or no fmri, show usage */ 1069 if ((fmri_args == argc) || (fmri_args == 0)) 1070 usage(B_FALSE); 1071 1072 /* setup args for modify_inst_props_cb */ 1073 args.argc = argc - fmri_args; 1074 args.argv = argv + fmri_args; 1075 1076 serr = scf_walk_fmri(h, fmri_args, argv, 0, 1077 modify_inst_props_cb, &args, &exit_status, uu_warn); 1078 } else if (Mflag) { 1079 modify_defaults(argc, argv); 1080 } else if (pflag) { 1081 /* ensure there's no trailing garbage */ 1082 if (argc != 0) 1083 usage(B_FALSE); 1084 list_defaults(); 1085 } 1086 if (serr != 0) { 1087 uu_warn(gettext("failed to iterate over instances: %s"), 1088 scf_strerror(serr)); 1089 exit(UU_EXIT_FATAL); 1090 } 1091 1092 out: 1093 (void) scf_handle_unbind(h); 1094 scf_handle_destroy(h); 1095 1096 return (exit_status); 1097 } 1098