dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.sbin / inetadm / inetadm.c
blob531c5a16c9db275104ac6d06a2a7cc67fc23f67b
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * inetadm - administer services controlled by inetd and print out inetd
29 * service related information.
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>
45 #ifndef TEXT_DOMAIN
46 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
47 #endif /* TEXT_DOMAIN */
49 /* Strings for output to the user, and checking user's input */
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"
57 /* String for checking if an instance is under inetd's control. */
59 #define INETADM_INETD_STR "network/inetd"
62 * Used to hold a list of scf_value_t's whilst performing a transaction
63 * to write a proto list back.
65 typedef struct scf_val_el {
66 scf_value_t *val;
67 uu_list_node_t link;
68 } scf_val_el_t;
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().
75 typedef struct arglist {
76 int argc;
77 char **argv;
78 } arglist_t;
80 static scf_handle_t *h;
82 static void
83 scfdie()
85 uu_die(gettext("Unexpected libscf error: %s. Exiting.\n"),
86 scf_strerror(scf_error()));
89 static void
90 usage(boolean_t detailed)
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"));
104 if (!detailed)
105 exit(UU_EXIT_USAGE);
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"));
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.
127 static void
128 add_proto_list(scf_transaction_entry_t *entry, scf_handle_t *hdl,
129 char **plist, uu_list_t **sv_list)
131 scf_val_el_t *sv_el;
132 int i;
134 static uu_list_pool_t *sv_pool = NULL;
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()));
142 if ((*sv_list = uu_list_create(sv_pool, NULL, 0)) == NULL)
143 uu_die(gettext("Error: %s.\n"), uu_strerror(uu_error()));
145 for (i = 0; plist[i] != NULL; i++) {
146 if ((sv_el = malloc(sizeof (scf_val_el_t))) == NULL)
147 uu_die(gettext("Error:"));
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();
154 uu_list_node_init(sv_el, &sv_el->link, sv_pool);
155 (void) uu_list_insert_after(*sv_list, NULL, sv_el);
160 * A counterpart to add_proto_list(), this function removes and frees the
161 * scf_value_t's it added to entry 'entry'.
163 static void
164 remove_proto_list(scf_transaction_entry_t *entry, uu_list_t *sv_list)
166 scf_val_el_t *sv_el;
167 void *cookie = NULL;
169 scf_entry_reset(entry);
171 while ((sv_el = uu_list_teardown(sv_list, &cookie)) != NULL) {
172 scf_value_destroy(sv_el->val);
173 free(sv_el);
176 uu_list_destroy(sv_list);
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.
185 static void
186 modify_prop(const scf_instance_t *inst, const char *pg, const char *prop,
187 scf_type_t type, void *value)
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;
198 if ((gpg = scf_pg_create(h)) == NULL ||
199 (eprop = scf_property_create(h)) == NULL ||
200 (v = scf_value_create(h)) == NULL)
201 scfdie();
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();
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"));
212 if (scf_instance_to_fmri(inst, fmri, max_fmri_len + 1) < 0)
213 scfdie();
215 syslog(LOG_NOTICE, "inetadm: Property group \"%s\" missing "
216 "from \"%s\", attempting to add it.\n", pg, fmri);
217 free(fmri);
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();
232 if (scf_pg_get_property(gpg, prop, eprop) == -1) {
233 if (scf_error() != SCF_ERROR_NOT_FOUND)
234 scfdie();
236 create = 1;
239 if ((tx = scf_transaction_create(h)) == NULL ||
240 (ent = scf_entry_create(h)) == NULL)
241 scfdie();
243 do {
244 uu_list_t *sv_list;
246 if (scf_transaction_start(tx, gpg) == -1) {
247 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
248 scfdie();
250 uu_die(gettext("Error: Permission denied.\n"));
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();
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();
276 break;
277 default:
278 uu_die(gettext("Error: Internal inetadm error"));
281 if ((strcmp(prop, PR_PROTO_NAME) != 0) &&
282 (scf_entry_add_value(ent, v) == -1))
283 scfdie();
285 ret = scf_transaction_commit(tx);
286 if (ret == -1) {
287 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
288 scfdie();
290 uu_die(gettext("Error: Permission denied.\n"));
293 scf_transaction_reset(tx);
295 if (ret == 0) {
296 if (scf_pg_update(gpg) == -1)
297 scfdie();
300 if (strcmp(prop, PR_PROTO_NAME) == 0)
301 remove_proto_list(ent, sv_list);
303 } while (ret == 0);
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);
313 * delete_prop takes an instance, property group name and property, and
314 * deletes the specified property from the repository.
317 static void
318 delete_prop(const scf_instance_t *inst, const char *pg, const char *prop)
320 scf_transaction_t *tx;
321 scf_transaction_entry_t *ent;
322 scf_propertygroup_t *gpg;
323 scf_property_t *eprop;
324 int ret;
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();
332 if (scf_instance_get_pg(inst, pg, gpg) != SCF_SUCCESS) {
333 if (scf_error() != SCF_ERROR_NOT_FOUND)
334 scfdie();
336 uu_die(gettext("Error: \"%s\" property group missing.\n"), pg);
339 do {
340 if (scf_transaction_start(tx, gpg) != SCF_SUCCESS) {
341 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
342 scfdie();
344 uu_die(gettext("Error: Permission denied.\n"));
347 if (scf_transaction_property_delete(tx, ent,
348 prop) != SCF_SUCCESS) {
349 if (scf_error() != SCF_ERROR_NOT_FOUND)
350 scfdie();
352 uu_die(
353 gettext("Error: \"%s\" property does not exist.\n"),
354 prop);
357 ret = scf_transaction_commit(tx);
358 if (ret < 0) {
359 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
360 scfdie();
362 uu_die(gettext("Error: Permission denied.\n"));
364 if (ret == 0) {
365 scf_transaction_reset(tx);
366 if (scf_pg_update(gpg) == -1)
367 scfdie();
369 } while (ret == 0);
371 (void) scf_entry_destroy(ent);
372 scf_transaction_destroy(tx);
373 scf_property_destroy(eprop);
374 scf_pg_destroy(gpg);
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.
383 static void
384 commit_props(const scf_instance_t *inst, inetd_prop_t *mod, boolean_t defaults)
386 int i;
387 uint8_t new_bool;
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;
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;
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.
438 /*ARGSUSED*/
439 static int
440 list_callback(scf_handle_t *hin, scf_instance_t *inst, void *buf)
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;
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"));
453 * Get the FMRI of the instance, and check if its delegated restarter
454 * is inetd.
457 if (scf_instance_to_fmri(inst, inst_name, max_name_length + 1) < 0)
458 return (SCF_FAILED);
460 if ((prop = scf_simple_prop_get(hin, inst_name, SCF_PG_GENERAL,
461 SCF_PROPERTY_RESTARTER)) == NULL)
462 goto out;
464 if ((restart_str = scf_simple_prop_next_ustring(prop)) == NULL)
465 goto out;
467 if (strstr(restart_str, INETADM_INETD_STR) == NULL)
468 goto out;
470 /* Free restarter prop so it can be reused below */
471 scf_simple_prop_free(prop);
474 * We know that this instance is managed by inetd.
475 * Now get the enabled and state properties.
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;
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;
494 /* Print enabled/disabled, state, and FMRI for the instance. */
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);
503 out:
504 free(inst_name);
505 scf_simple_prop_free(prop);
506 scf_simple_prop_free(prop2);
507 return (SCF_SUCCESS);
511 * list_services calls list_callback on every instance on the machine.
514 static void
515 list_services()
517 (void) printf("%-10s%-15s%s\n", "ENABLED", "STATE", "FMRI");
519 if (scf_simple_walk_instances(SCF_STATE_ALL, NULL, list_callback) ==
520 SCF_FAILED)
521 scfdie();
524 static void
525 print_prop_val(inetd_prop_t *prop)
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:
533 int j = 0;
534 char **cpp = prop->ip_value.iv_string_list;
537 * Print string list as comma separated list.
540 (void) printf("\"%s", cpp[j]);
541 while (cpp[++j] != NULL)
542 (void) printf(",%s", cpp[j]);
543 (void) printf("\"\n");
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;
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.
563 /* ARGSUSED0 */
564 static int
565 list_props_cb(void *data, scf_walkinfo_t *wip)
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;
577 if (((h = scf_handle_create(SCF_VERSION)) == NULL) ||
578 (scf_handle_bind(h) == -1))
579 scfdie();
582 * Get the property that holds the name of this instance's
583 * restarter, and make sure that it is inetd.
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);
596 scfdie();
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);
605 scf_simple_prop_free(prop);
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()).
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));
620 scf_handle_destroy(h);
622 (void) printf("%-9s%s\n", "SCOPE", "NAME=VALUE");
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;
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;
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;
643 /* arg0 is non-default, but also doesn't have to be set. */
645 if (i == PT_ARG0_INDEX)
646 continue;
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);
659 free_instance_props(proplist);
660 return (0);
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'.
669 static int
670 set_svc_enable_cb(void *data, scf_walkinfo_t *wip)
672 uint8_t desired = *(uint8_t *)data;
673 const char *instname = wip->fmri;
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);
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();
696 return (0);
700 * list_defaults lists all the default property values being provided by
701 * inetd.
704 static void
705 list_defaults()
707 scf_handle_t *h;
708 scf_error_t err;
709 int i;
710 inetd_prop_t *proptable;
711 size_t numprops;
713 if (((h = scf_handle_create(SCF_VERSION)) == NULL) ||
714 (scf_handle_bind(h) == -1))
715 scfdie();
717 if ((proptable = read_default_props(h, &numprops, &err)) == NULL) {
718 uu_die(gettext("Unexpected libscf error: %s. Exiting.\n"),
719 scf_strerror(err));
722 (void) printf("NAME=VALUE\n");
724 for (i = 0; i < numprops; i++) {
725 if (!proptable[i].ip_default)
726 continue;
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;
734 (void) printf("%s=", proptable[i].ip_name);
735 print_prop_val(&proptable[i]);
738 free_instance_props(proptable);
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.
747 static int
748 modify_inst_props_cb(void *data, scf_walkinfo_t *wip)
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;
761 if ((max_val = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
762 scfdie();
764 prop_table = get_prop_table(&numprops);
766 if ((mod = malloc(numprops * sizeof (inetd_prop_t))) == NULL)
767 uu_die(gettext("Error: Out of memory.\n"));
769 (void) memcpy(mod, prop_table, numprops * sizeof (inetd_prop_t));
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.
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]);
782 *value = '\0';
783 value++;
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;
791 if (mod[j].ip_name == NULL)
792 uu_die(gettext("Error: \"%s\" is not a valid "
793 "property.\n"), argv[i]);
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;
800 /* return the '=' taken out above */
801 *(--value) = '=';
803 continue;
804 } else {
805 uu_die(gettext("\"%s\" is a mandatory "
806 "property and can not be deleted.\n"),
807 argv[i]);
811 switch (mod[j].ip_type) {
812 case INET_TYPE_INTEGER:
813 if (uu_strtoint(value, &new_int, sizeof (new_int), 0,
814 0, 0) == -1)
815 uu_die(gettext("Error: \"%s\" is not a valid "
816 "integer value.\n"), value);
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"));
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);
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);
859 /* mark property for modification */
860 mod[j].ip_error = IVE_VALID;
862 /* return the '=' taken out above */
863 *(--value) = '=';
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);
872 return (0);
876 * modify_defaults takes n name=value pairs for inetd default property values,
877 * parses them, and then modifies the values in the repository.
880 static void
881 modify_defaults(int argc, char *argv[])
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;
891 if ((inst = scf_instance_create(h)) == NULL)
892 scfdie();
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();
904 if ((max_val = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
905 scfdie();
907 prop_table = get_prop_table(&numprops);
909 if ((mod = malloc(numprops * sizeof (inetd_prop_t))) == NULL)
910 uu_die(gettext("Error: Out of memory.\n"));
912 (void) memcpy(mod, prop_table, numprops * sizeof (inetd_prop_t));
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]);
920 *value = '\0';
921 value++;
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;
931 if (mod[j].ip_name == NULL)
932 uu_die(gettext("Error: \"%s\" is not a default inetd "
933 "property.\n"), argv[i]);
935 if (*value == '\0')
936 uu_die(gettext("Cannot accept NULL values for default "
937 "properties.\n"));
939 switch (mod[j].ip_type) {
940 case INET_TYPE_INTEGER:
941 if (uu_strtoint(value, &new_int, sizeof (new_int), 0,
942 0, 0) == -1)
943 uu_die(gettext("Error: \"%s\" is not a valid "
944 "integer value.\n"), value);
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);
965 /* mark property for modification */
966 mod[j].ip_error = IVE_VALID;
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"));
977 main(int argc, char *argv[])
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;
985 (void) setlocale(LC_ALL, "");
986 (void) textdomain(TEXT_DOMAIN);
988 if ((h = scf_handle_create(SCF_VERSION)) == NULL)
989 scfdie();
991 if (scf_handle_bind(h) == -1)
992 uu_die(gettext("Error: Couldn't bind to svc.configd.\n"));
994 if (argc == 1) {
995 list_services();
996 goto out;
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);
1027 default:
1028 usage(B_FALSE);
1033 * All options are mutually exclusive, and we must have an option
1034 * if we reached here.
1036 if (lflag + eflag + dflag + pflag + mflag + Mflag != 1)
1037 usage(B_FALSE);
1039 argv += optind;
1040 argc -= optind;
1041 if ((pflag == 0) && (argc == 0))
1042 usage(B_FALSE);
1044 serr = 0;
1045 if (lflag) {
1046 serr = scf_walk_fmri(h, argc, argv, 0, list_props_cb, NULL,
1047 &exit_status, uu_warn);
1048 } else if (dflag) {
1049 enable = 0;
1050 serr = scf_walk_fmri(h, argc, argv, 0, set_svc_enable_cb,
1051 &enable, &exit_status, uu_warn);
1052 } else if (eflag) {
1053 enable = 1;
1054 serr = scf_walk_fmri(h, argc, argv, 0, set_svc_enable_cb,
1055 &enable, &exit_status, uu_warn);
1056 } else if (mflag) {
1057 arglist_t args;
1058 char **cpp = argv;
1059 uint_t fmri_args = 0;
1061 /* count number of fmri arguments */
1062 while ((fmri_args < argc) && (strchr(*cpp, '=') == NULL)) {
1063 fmri_args++;
1064 cpp++;
1067 /* if no x=y args or no fmri, show usage */
1068 if ((fmri_args == argc) || (fmri_args == 0))
1069 usage(B_FALSE);
1071 /* setup args for modify_inst_props_cb */
1072 args.argc = argc - fmri_args;
1073 args.argv = argv + fmri_args;
1075 serr = scf_walk_fmri(h, fmri_args, argv, 0,
1076 modify_inst_props_cb, &args, &exit_status, uu_warn);
1077 } else if (Mflag) {
1078 modify_defaults(argc, argv);
1079 } else if (pflag) {
1080 /* ensure there's no trailing garbage */
1081 if (argc != 0)
1082 usage(B_FALSE);
1083 list_defaults();
1085 if (serr != 0) {
1086 uu_warn(gettext("failed to iterate over instances: %s"),
1087 scf_strerror(serr));
1088 exit(UU_EXIT_FATAL);
1091 out:
1092 (void) scf_handle_unbind(h);
1093 scf_handle_destroy(h);
1095 return (exit_status);