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