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 2004 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 size_t numprops; 391 392 (void) get_prop_table(&numprops); 393 394 for (i = 0; i < numprops; i++) { 395 switch (mod[i].ip_error) { 396 case IVE_UNSET: 397 break; 398 case IVE_INVALID: 399 delete_prop(inst, mod[i].ip_pg, mod[i].ip_name); 400 break; 401 case IVE_VALID: 402 switch (mod[i].ip_type) { 403 case SCF_TYPE_ASTRING: 404 modify_prop(inst, 405 defaults ? PG_NAME_SERVICE_DEFAULTS : 406 mod[i].ip_pg, mod[i].ip_name, 407 SCF_TYPE_ASTRING, 408 (i == PT_PROTO_INDEX) ? 409 (void *)mod[i].ip_value.iv_proto_list : 410 (void *)mod[i].ip_value.iv_astring); 411 break; 412 case SCF_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 SCF_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(int index, inetd_prop_t *prop) 526 { 527 switch (prop->ip_type) { 528 case SCF_TYPE_ASTRING: 529 if (index == PT_PROTO_INDEX) { 530 int j = 0; 531 char **cpp = prop->ip_value.iv_proto_list; 532 533 /* 534 * Print proto string array as comma separated list. 535 */ 536 537 (void) printf("\"%s", cpp[j]); 538 while (cpp[++j] != NULL) 539 (void) printf(",%s", cpp[j]); 540 (void) printf("\"\n"); 541 } else { 542 (void) printf("\"%s\"\n", 543 prop->ip_value.iv_astring); 544 } 545 break; 546 case SCF_TYPE_INTEGER: 547 (void) printf("%lld\n", prop->ip_value.iv_int); 548 break; 549 case SCF_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(i, &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(i, &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; j < numprops; j++) { 787 if (strcmp(mod[j].ip_name, argv[i]) == 0) 788 break; 789 } 790 791 if (j >= numprops) 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 SCF_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 SCF_TYPE_ASTRING: 821 if (j == PT_PROTO_INDEX) { 822 if ((mod[j].ip_value.iv_proto_list = 823 get_protos(value)) == NULL) { 824 if (errno == ENOMEM) { 825 uu_die(gettext( 826 "Error: Out of memory.\n")); 827 } else if (errno == E2BIG) { 828 uu_die(gettext( 829 "Error: String value in " 830 "%s property longer than " 831 "%l characters.\n"), 832 PR_PROTO_NAME, max_val); 833 } else { 834 uu_die(gettext( 835 "Error: No values " 836 "specified for %s " 837 "property.\n"), 838 PR_PROTO_NAME); 839 } 840 } 841 } else if (strlen(value) >= max_val) { 842 uu_die(gettext("Error: String value is longer " 843 "than %l characters.\n"), max_val); 844 } else if ((mod[j].ip_value.iv_astring = strdup(value)) 845 == NULL) { 846 uu_die(gettext("Error: Out of memory.\n")); 847 } 848 break; 849 case SCF_TYPE_BOOLEAN: 850 if (strcasecmp(value, INETADM_TRUE_STR) == 0) 851 mod[j].ip_value.iv_boolean = B_TRUE; 852 else if (strcasecmp(value, INETADM_FALSE_STR) == 0) 853 mod[j].ip_value.iv_boolean = B_FALSE; 854 else 855 uu_die(gettext("Error: \"%s\" is not a valid " 856 "boolean value. (TRUE or FALSE)\n"), value); 857 } 858 /* mark property for modification */ 859 mod[j].ip_error = IVE_VALID; 860 861 /* return the '=' taken out above */ 862 *(--value) = '='; 863 } 864 865 commit_props(inst, mod, B_FALSE); 866 free(mod); 867 if (smf_refresh_instance(fmri) != 0) 868 uu_die(gettext("Error: Unable to refresh instance %s.\n"), 869 fmri); 870 871 return (0); 872 } 873 874 /* 875 * modify_defaults takes n name=value pairs for inetd default property values, 876 * parses them, and then modifies the values in the repository. 877 */ 878 879 static void 880 modify_defaults(int argc, char *argv[]) 881 { 882 int i, j; 883 char *value; 884 scf_instance_t *inst; 885 inetd_prop_t *mod, *prop_table; 886 size_t numprops; 887 ssize_t max_val; 888 int64_t new_int; 889 890 if ((inst = scf_instance_create(h)) == NULL) 891 scfdie(); 892 893 if (scf_handle_decode_fmri(h, INETD_INSTANCE_FMRI, NULL, NULL, 894 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) { 895 if (scf_error() == SCF_ERROR_NOT_FOUND) { 896 uu_die(gettext("inetd instance missing in repository." 897 "\n")); 898 } else { 899 scfdie(); 900 } 901 } 902 903 if ((max_val = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0) 904 scfdie(); 905 906 prop_table = get_prop_table(&numprops); 907 908 if ((mod = malloc(numprops * sizeof (inetd_prop_t))) == NULL) 909 uu_die(gettext("Error: Out of memory.\n")); 910 911 (void) memcpy(mod, prop_table, numprops * sizeof (inetd_prop_t)); 912 913 for (i = 0; i < argc; i++) { 914 /* Separate argument into name and value pair */ 915 if ((value = strchr(argv[i], '=')) == NULL) 916 uu_die(gettext("Error: Malformed name=value pair \"%s" 917 "\"\n"), argv[i]); 918 919 *value = '\0'; 920 value++; 921 922 /* Find property name in array of defaults */ 923 for (j = 0; j < numprops; j++) { 924 if (!mod[j].ip_default) 925 continue; 926 if (strcmp(mod[j].ip_name, argv[i]) == 0) 927 break; 928 } 929 930 if (j >= numprops) 931 uu_die(gettext("Error: \"%s\" is not a default inetd " 932 "property.\n"), argv[i]); 933 934 if (*value == '\0') 935 uu_die(gettext("Cannot accept NULL values for default " 936 "properties.\n")); 937 938 switch (mod[j].ip_type) { 939 case SCF_TYPE_INTEGER: 940 if (uu_strtoint(value, &new_int, sizeof (new_int), NULL, 941 NULL, NULL) == -1) 942 uu_die(gettext("Error: \"%s\" is not a valid " 943 "integer value.\n"), value); 944 945 mod[j].ip_value.iv_int = new_int; 946 break; 947 case SCF_TYPE_ASTRING: 948 if (strlen(value) >= max_val) 949 uu_die(gettext("Error: String value is longer " 950 "than %l characters.\n"), max_val); 951 if ((mod[j].ip_value.iv_astring = strdup(value)) 952 == NULL) 953 uu_die(gettext("Error: Out of memory.\n")); 954 break; 955 case SCF_TYPE_BOOLEAN: 956 if (strcasecmp(value, INETADM_TRUE_STR) == 0) 957 mod[j].ip_value.iv_boolean = B_TRUE; 958 else if (strcasecmp(value, INETADM_FALSE_STR) == 0) 959 mod[j].ip_value.iv_boolean = B_FALSE; 960 else 961 uu_die(gettext("Error: \"%s\" is not a valid " 962 "boolean value. (TRUE or FALSE)\n"), value); 963 } 964 /* mark property for modification */ 965 mod[j].ip_error = IVE_VALID; 966 } 967 968 commit_props(inst, mod, B_TRUE); 969 free(mod); 970 scf_instance_destroy(inst); 971 if (refresh_inetd() != 0) 972 uu_warn(gettext("Warning: Unable to refresh inetd.\n")); 973 } 974 975 int 976 main(int argc, char *argv[]) 977 { 978 int opt; 979 uint_t lflag, eflag, dflag, pflag, mflag, Mflag; 980 uint8_t enable; 981 scf_error_t serr; 982 int exit_status = 0; 983 984 (void) setlocale(LC_ALL, ""); 985 (void) textdomain(TEXT_DOMAIN); 986 987 if ((h = scf_handle_create(SCF_VERSION)) == NULL) 988 scfdie(); 989 990 if (scf_handle_bind(h) == -1) 991 uu_die(gettext("Error: Couldn't bind to svc.configd.\n")); 992 993 if (argc == 1) { 994 list_services(); 995 goto out; 996 } 997 998 lflag = eflag = dflag = pflag = mflag = Mflag = 0; 999 while ((opt = getopt(argc, argv, "ledpMm?")) != -1) { 1000 switch (opt) { 1001 case 'l': 1002 lflag = 1; 1003 break; 1004 case 'e': 1005 eflag = 1; 1006 break; 1007 case 'd': 1008 dflag = 1; 1009 break; 1010 case 'p': 1011 pflag = 1; 1012 break; 1013 case 'M': 1014 Mflag = 1; 1015 break; 1016 case 'm': 1017 mflag = 1; 1018 break; 1019 case '?': 1020 if (optopt == '?') { 1021 usage(B_TRUE); 1022 goto out; 1023 } else { 1024 usage(B_FALSE); 1025 } 1026 default: 1027 usage(B_FALSE); 1028 } 1029 } 1030 1031 /* 1032 * All options are mutually exclusive, and we must have an option 1033 * if we reached here. 1034 */ 1035 if (lflag + eflag + dflag + pflag + mflag + Mflag != 1) 1036 usage(B_FALSE); 1037 1038 argv += optind; 1039 argc -= optind; 1040 if ((pflag == 0) && (argc == 0)) 1041 usage(B_FALSE); 1042 1043 serr = 0; 1044 if (lflag) { 1045 serr = scf_walk_fmri(h, argc, argv, 0, list_props_cb, NULL, 1046 &exit_status, uu_warn); 1047 } else if (dflag) { 1048 enable = 0; 1049 serr = scf_walk_fmri(h, argc, argv, 0, set_svc_enable_cb, 1050 &enable, &exit_status, uu_warn); 1051 } else if (eflag) { 1052 enable = 1; 1053 serr = scf_walk_fmri(h, argc, argv, 0, set_svc_enable_cb, 1054 &enable, &exit_status, uu_warn); 1055 } else if (mflag) { 1056 arglist_t args; 1057 char **cpp = argv; 1058 uint_t fmri_args = 0; 1059 1060 /* count number of fmri arguments */ 1061 while ((fmri_args < argc) && (strchr(*cpp, '=') == NULL)) { 1062 fmri_args++; 1063 cpp++; 1064 } 1065 1066 /* if no x=y args or no fmri, show usage */ 1067 if ((fmri_args == argc) || (fmri_args == 0)) 1068 usage(B_FALSE); 1069 1070 /* setup args for modify_inst_props_cb */ 1071 args.argc = argc - fmri_args; 1072 args.argv = argv + fmri_args; 1073 1074 serr = scf_walk_fmri(h, fmri_args, argv, 0, 1075 modify_inst_props_cb, &args, &exit_status, uu_warn); 1076 } else if (Mflag) { 1077 modify_defaults(argc, argv); 1078 } else if (pflag) { 1079 /* ensure there's no trailing garbage */ 1080 if (argc != 0) 1081 usage(B_FALSE); 1082 list_defaults(); 1083 } 1084 if (serr != 0) { 1085 uu_warn(gettext("failed to iterate over instances: %s"), 1086 scf_strerror(serr)); 1087 exit(UU_EXIT_FATAL); 1088 } 1089 1090 out: 1091 (void) scf_handle_unbind(h); 1092 scf_handle_destroy(h); 1093 1094 return (exit_status); 1095 } 1096