xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/inetadm/inetadm.c (revision 1293:52cb57f230e2)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*1293Smh138676  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * inetadm - administer services controlled by inetd and print out inetd
310Sstevel@tonic-gate  * service related information.
320Sstevel@tonic-gate  */
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #include <locale.h>
350Sstevel@tonic-gate #include <libintl.h>
360Sstevel@tonic-gate #include <libscf.h>
370Sstevel@tonic-gate #include <libscf_priv.h>
380Sstevel@tonic-gate #include <libuutil.h>
390Sstevel@tonic-gate #include <stddef.h>
400Sstevel@tonic-gate #include <stdio.h>
410Sstevel@tonic-gate #include <stdlib.h>
420Sstevel@tonic-gate #include <string.h>
430Sstevel@tonic-gate #include <syslog.h>
440Sstevel@tonic-gate #include <inetsvc.h>
450Sstevel@tonic-gate #include <errno.h>
460Sstevel@tonic-gate 
470Sstevel@tonic-gate #ifndef TEXT_DOMAIN
480Sstevel@tonic-gate #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
490Sstevel@tonic-gate #endif /* TEXT_DOMAIN */
500Sstevel@tonic-gate 
510Sstevel@tonic-gate /* Strings for output to the user, and checking user's input */
520Sstevel@tonic-gate 
530Sstevel@tonic-gate #define	INETADM_TRUE_STR		"TRUE"
540Sstevel@tonic-gate #define	INETADM_FALSE_STR		"FALSE"
550Sstevel@tonic-gate #define	INETADM_ENABLED_STR		"enabled"
560Sstevel@tonic-gate #define	INETADM_DISABLED_STR		"disabled"
570Sstevel@tonic-gate #define	INETADM_DEFAULT_STR		"default"
580Sstevel@tonic-gate 
590Sstevel@tonic-gate /* String for checking if an instance is under inetd's control. */
600Sstevel@tonic-gate 
610Sstevel@tonic-gate #define	INETADM_INETD_STR		"network/inetd"
620Sstevel@tonic-gate 
630Sstevel@tonic-gate /*
640Sstevel@tonic-gate  * Used to hold a list of scf_value_t's whilst performing a transaction
650Sstevel@tonic-gate  * to write a proto list back.
660Sstevel@tonic-gate  */
670Sstevel@tonic-gate typedef struct scf_val_el {
680Sstevel@tonic-gate 	scf_value_t		*val;
690Sstevel@tonic-gate 	uu_list_node_t		link;
700Sstevel@tonic-gate } scf_val_el_t;
710Sstevel@tonic-gate 
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate  * Structure used to encapsulate argc and argv so they can be passed using the
740Sstevel@tonic-gate  * single data argument supplied by scf_walk_fmri() for the consumption of
750Sstevel@tonic-gate  * modify_inst_props_cb().
760Sstevel@tonic-gate  */
770Sstevel@tonic-gate typedef struct arglist {
780Sstevel@tonic-gate 	int	argc;
790Sstevel@tonic-gate 	char	**argv;
800Sstevel@tonic-gate } arglist_t;
810Sstevel@tonic-gate 
820Sstevel@tonic-gate static scf_handle_t *h;
830Sstevel@tonic-gate 
840Sstevel@tonic-gate static void
scfdie()850Sstevel@tonic-gate scfdie()
860Sstevel@tonic-gate {
870Sstevel@tonic-gate 	uu_die(gettext("Unexpected libscf error: %s.  Exiting.\n"),
880Sstevel@tonic-gate 	    scf_strerror(scf_error()));
890Sstevel@tonic-gate }
900Sstevel@tonic-gate 
910Sstevel@tonic-gate static void
usage(boolean_t detailed)920Sstevel@tonic-gate usage(boolean_t detailed)
930Sstevel@tonic-gate {
940Sstevel@tonic-gate 
950Sstevel@tonic-gate 	uu_warn(gettext(
960Sstevel@tonic-gate 	    "Usage:\n"
970Sstevel@tonic-gate 	    "  inetadm\n"
980Sstevel@tonic-gate 	    "  inetadm -?\n"
990Sstevel@tonic-gate 	    "  inetadm -p\n"
1000Sstevel@tonic-gate 	    "  inetadm -l {FMRI | pattern}...\n"
1010Sstevel@tonic-gate 	    "  inetadm -e {FMRI | pattern}...\n"
1020Sstevel@tonic-gate 	    "  inetadm -d {FMRI | pattern}...\n"
1030Sstevel@tonic-gate 	    "  inetadm -m {FMRI | pattern}... {name=value}...\n"
1040Sstevel@tonic-gate 	    "  inetadm -M {name=value}...\n"));
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate 	if (!detailed)
1070Sstevel@tonic-gate 		exit(UU_EXIT_USAGE);
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	(void) fprintf(stdout, gettext(
1100Sstevel@tonic-gate 	    "\n"
1110Sstevel@tonic-gate 	    "Without any options inetadm lists all inetd managed services.\n"
1120Sstevel@tonic-gate 	    "\n"
1130Sstevel@tonic-gate 	    "Options:\n"
1140Sstevel@tonic-gate 	    "  -?	Print help.\n"
1150Sstevel@tonic-gate 	    "  -p	List all default inetd property values.\n"
1160Sstevel@tonic-gate 	    "  -l 	List all inetd property values for the inet "
1170Sstevel@tonic-gate 	    "service(s).\n"
1180Sstevel@tonic-gate 	    "  -e	Enable the inet service(s).\n"
1190Sstevel@tonic-gate 	    "  -d	Disable the inet service(s).\n"
1200Sstevel@tonic-gate 	    "  -m	Modify the inet service(s) inetd property values.\n"
1210Sstevel@tonic-gate 	    "  -M	Modify default inetd property values.\n"));
1220Sstevel@tonic-gate }
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate /*
1250Sstevel@tonic-gate  * Add the proto list contained in array 'plist' to entry 'entry', storing
1260Sstevel@tonic-gate  * aside the scf_value_t's created and added to the entry in a list that the
1270Sstevel@tonic-gate  * pointer referenced by sv_list is made to point at.
1280Sstevel@tonic-gate  */
1290Sstevel@tonic-gate static void
add_proto_list(scf_transaction_entry_t * entry,scf_handle_t * hdl,char ** plist,uu_list_t ** sv_list)1300Sstevel@tonic-gate add_proto_list(scf_transaction_entry_t *entry, scf_handle_t *hdl,
1310Sstevel@tonic-gate     char **plist, uu_list_t **sv_list)
1320Sstevel@tonic-gate {
1330Sstevel@tonic-gate 	scf_val_el_t		*sv_el;
1340Sstevel@tonic-gate 	int			i;
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	static uu_list_pool_t	*sv_pool = NULL;
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	if ((sv_pool == NULL) &&
1390Sstevel@tonic-gate 	    ((sv_pool = uu_list_pool_create("sv_pool",
1400Sstevel@tonic-gate 	    sizeof (scf_val_el_t), offsetof(scf_val_el_t, link), NULL,
1410Sstevel@tonic-gate 	    UU_LIST_POOL_DEBUG)) == NULL))
1420Sstevel@tonic-gate 		uu_die(gettext("Error: %s.\n"), uu_strerror(uu_error()));
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	if ((*sv_list = uu_list_create(sv_pool, NULL, 0)) == NULL)
1450Sstevel@tonic-gate 		uu_die(gettext("Error: %s.\n"), uu_strerror(uu_error()));
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	for (i = 0; plist[i] != NULL; i++) {
1480Sstevel@tonic-gate 		if ((sv_el = malloc(sizeof (scf_val_el_t))) == NULL)
1490Sstevel@tonic-gate 			uu_die(gettext("Error:"));
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 		if (((sv_el->val = scf_value_create(hdl)) == NULL) ||
1520Sstevel@tonic-gate 		    (scf_value_set_astring(sv_el->val, plist[i]) != 0) ||
1530Sstevel@tonic-gate 		    (scf_entry_add_value(entry, sv_el->val) != 0))
1540Sstevel@tonic-gate 			scfdie();
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 		uu_list_node_init(sv_el, &sv_el->link, sv_pool);
1570Sstevel@tonic-gate 		(void) uu_list_insert_after(*sv_list, NULL, sv_el);
1580Sstevel@tonic-gate 	}
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate /*
1620Sstevel@tonic-gate  * A counterpart to add_proto_list(), this function removes and frees the
1630Sstevel@tonic-gate  * scf_value_t's it added to entry 'entry'.
1640Sstevel@tonic-gate  */
1650Sstevel@tonic-gate static void
remove_proto_list(scf_transaction_entry_t * entry,uu_list_t * sv_list)1660Sstevel@tonic-gate remove_proto_list(scf_transaction_entry_t *entry, uu_list_t *sv_list)
1670Sstevel@tonic-gate {
1680Sstevel@tonic-gate 	scf_val_el_t	*sv_el;
1690Sstevel@tonic-gate 	void		*cookie = NULL;
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	scf_entry_reset(entry);
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	while ((sv_el = uu_list_teardown(sv_list, &cookie)) != NULL) {
1740Sstevel@tonic-gate 		scf_value_destroy(sv_el->val);
1750Sstevel@tonic-gate 		free(sv_el);
1760Sstevel@tonic-gate 	}
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	uu_list_destroy(sv_list);
1790Sstevel@tonic-gate }
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate /*
1820Sstevel@tonic-gate  * modify_prop takes an instance, property group, property name, type, and
1830Sstevel@tonic-gate  * value, and modifies the specified property in the repository to the
1840Sstevel@tonic-gate  * submitted value.
1850Sstevel@tonic-gate  */
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate static void
modify_prop(const scf_instance_t * inst,const char * pg,const char * prop,scf_type_t type,void * value)1880Sstevel@tonic-gate modify_prop(const scf_instance_t *inst, const char *pg, const char *prop,
1890Sstevel@tonic-gate     scf_type_t type, void *value)
1900Sstevel@tonic-gate {
1910Sstevel@tonic-gate 	scf_transaction_t		*tx;
1920Sstevel@tonic-gate 	scf_transaction_entry_t		*ent;
1930Sstevel@tonic-gate 	scf_propertygroup_t		*gpg;
1940Sstevel@tonic-gate 	scf_property_t			*eprop;
1950Sstevel@tonic-gate 	scf_value_t			*v;
1960Sstevel@tonic-gate 	int				ret, create = 0;
1970Sstevel@tonic-gate 	char				*fmri;
1980Sstevel@tonic-gate 	ssize_t				max_fmri_len;
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	if ((gpg = scf_pg_create(h)) == NULL ||
2010Sstevel@tonic-gate 	    (eprop = scf_property_create(h)) == NULL ||
2020Sstevel@tonic-gate 	    (v = scf_value_create(h)) == NULL)
2030Sstevel@tonic-gate 		scfdie();
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	/* Get the property group or create it if it is missing. */
2060Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, pg, gpg) == -1) {
2070Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
2080Sstevel@tonic-gate 			scfdie();
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 		max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
2110Sstevel@tonic-gate 		if ((fmri = malloc(max_fmri_len + 1)) == NULL)
2120Sstevel@tonic-gate 			uu_die(gettext("Error: Out of memory.\n"));
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 		if (scf_instance_to_fmri(inst, fmri, max_fmri_len + 1) < 0)
2150Sstevel@tonic-gate 			scfdie();
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 		syslog(LOG_NOTICE, "inetadm: Property group \"%s\" missing "
2180Sstevel@tonic-gate 		    "from \"%s\", attempting to add it.\n", pg, fmri);
2190Sstevel@tonic-gate 		free(fmri);
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 		if (scf_instance_add_pg(inst, pg, SCF_GROUP_FRAMEWORK, 0,
2220Sstevel@tonic-gate 		    gpg) == -1) {
2230Sstevel@tonic-gate 			switch (scf_error()) {
2240Sstevel@tonic-gate 			case SCF_ERROR_EXISTS:
2250Sstevel@tonic-gate 				break;
2260Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
2270Sstevel@tonic-gate 				uu_die(gettext("Error: Permission denied.\n"));
2280Sstevel@tonic-gate 			default:
2290Sstevel@tonic-gate 				scfdie();
2300Sstevel@tonic-gate 			}
2310Sstevel@tonic-gate 		}
2320Sstevel@tonic-gate 	}
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 	if (scf_pg_get_property(gpg, prop, eprop) == -1) {
2350Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
2360Sstevel@tonic-gate 			scfdie();
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 		create = 1;
2390Sstevel@tonic-gate 	}
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	if ((tx = scf_transaction_create(h)) == NULL ||
2420Sstevel@tonic-gate 	    (ent = scf_entry_create(h)) == NULL)
2430Sstevel@tonic-gate 		scfdie();
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	do {
2460Sstevel@tonic-gate 		uu_list_t	*sv_list;
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 		if (scf_transaction_start(tx, gpg) == -1) {
2490Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
2500Sstevel@tonic-gate 				scfdie();
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 			uu_die(gettext("Error: Permission denied.\n"));
2530Sstevel@tonic-gate 		}
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 		/* Modify the property or create it if it is missing */
2560Sstevel@tonic-gate 		if (create)
2570Sstevel@tonic-gate 			ret = scf_transaction_property_new(tx, ent, prop, type);
2580Sstevel@tonic-gate 		else
2590Sstevel@tonic-gate 			ret = scf_transaction_property_change_type(tx, ent,
2600Sstevel@tonic-gate 			    prop, type);
2610Sstevel@tonic-gate 		if (ret == -1)
2620Sstevel@tonic-gate 			scfdie();
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 		switch (type) {
2650Sstevel@tonic-gate 		case SCF_TYPE_BOOLEAN:
2660Sstevel@tonic-gate 			scf_value_set_boolean(v, *(uint8_t *)value);
2670Sstevel@tonic-gate 			break;
2680Sstevel@tonic-gate 		case SCF_TYPE_INTEGER:
2690Sstevel@tonic-gate 			scf_value_set_integer(v, *(int64_t *)value);
2700Sstevel@tonic-gate 			break;
2710Sstevel@tonic-gate 		case SCF_TYPE_ASTRING:
2720Sstevel@tonic-gate 			if (strcmp(prop, PR_PROTO_NAME) == 0) {
2730Sstevel@tonic-gate 				add_proto_list(ent, h, (char **)value,
2740Sstevel@tonic-gate 				    &sv_list);
2750Sstevel@tonic-gate 			} else if (scf_value_set_astring(v, value) == -1) {
2760Sstevel@tonic-gate 				scfdie();
2770Sstevel@tonic-gate 			}
2780Sstevel@tonic-gate 			break;
2790Sstevel@tonic-gate 		default:
2800Sstevel@tonic-gate 			uu_die(gettext("Error: Internal inetadm error"));
2810Sstevel@tonic-gate 		}
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 		if ((strcmp(prop, PR_PROTO_NAME) != 0) &&
2840Sstevel@tonic-gate 		    (scf_entry_add_value(ent, v) == -1))
2850Sstevel@tonic-gate 			scfdie();
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 		ret = scf_transaction_commit(tx);
2880Sstevel@tonic-gate 		if (ret == -1) {
2890Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
2900Sstevel@tonic-gate 				scfdie();
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 			uu_die(gettext("Error: Permission denied.\n"));
2930Sstevel@tonic-gate 		}
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 		scf_transaction_reset(tx);
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 		if (ret == 0) {
2980Sstevel@tonic-gate 			if (scf_pg_update(gpg) == -1)
2990Sstevel@tonic-gate 				scfdie();
3000Sstevel@tonic-gate 		}
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 		if (strcmp(prop, PR_PROTO_NAME) == 0)
3030Sstevel@tonic-gate 			remove_proto_list(ent, sv_list);
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	} while (ret == 0);
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	scf_value_destroy(v);
3080Sstevel@tonic-gate 	scf_entry_destroy(ent);
3090Sstevel@tonic-gate 	scf_transaction_destroy(tx);
3100Sstevel@tonic-gate 	scf_property_destroy(eprop);
3110Sstevel@tonic-gate 	scf_pg_destroy(gpg);
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate /*
3150Sstevel@tonic-gate  * delete_prop takes an instance, property group name and property, and
3160Sstevel@tonic-gate  * deletes the specified property from the repository.
3170Sstevel@tonic-gate  */
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate static void
delete_prop(const scf_instance_t * inst,const char * pg,const char * prop)3200Sstevel@tonic-gate delete_prop(const scf_instance_t *inst, const char *pg, const char *prop)
3210Sstevel@tonic-gate {
3220Sstevel@tonic-gate 	scf_transaction_t		*tx;
3230Sstevel@tonic-gate 	scf_transaction_entry_t		*ent;
3240Sstevel@tonic-gate 	scf_propertygroup_t		*gpg;
3250Sstevel@tonic-gate 	scf_property_t			*eprop;
3260Sstevel@tonic-gate 	int				ret;
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	if ((gpg = scf_pg_create(h)) == NULL ||
3290Sstevel@tonic-gate 	    (eprop = scf_property_create(h)) == NULL ||
3300Sstevel@tonic-gate 	    (tx = scf_transaction_create(h)) == NULL ||
3310Sstevel@tonic-gate 	    (ent = scf_entry_create(h)) == NULL)
3320Sstevel@tonic-gate 		scfdie();
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, pg, gpg) != SCF_SUCCESS) {
3350Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
3360Sstevel@tonic-gate 			scfdie();
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 		uu_die(gettext("Error: \"%s\" property group missing.\n"), pg);
3390Sstevel@tonic-gate 	}
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	do {
3420Sstevel@tonic-gate 		if (scf_transaction_start(tx, gpg) != SCF_SUCCESS) {
3430Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
3440Sstevel@tonic-gate 				scfdie();
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 			uu_die(gettext("Error: Permission denied.\n"));
3470Sstevel@tonic-gate 		}
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 		if (scf_transaction_property_delete(tx, ent,
3500Sstevel@tonic-gate 		    prop) != SCF_SUCCESS) {
3510Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
3520Sstevel@tonic-gate 				scfdie();
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 			uu_die(
3550Sstevel@tonic-gate 			    gettext("Error: \"%s\" property does not exist.\n"),
3560Sstevel@tonic-gate 			    prop);
3570Sstevel@tonic-gate 		}
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 		ret = scf_transaction_commit(tx);
3600Sstevel@tonic-gate 		if (ret < 0) {
3610Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
3620Sstevel@tonic-gate 				scfdie();
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 			uu_die(gettext("Error: Permission denied.\n"));
3650Sstevel@tonic-gate 		}
3660Sstevel@tonic-gate 		if (ret == 0) {
3670Sstevel@tonic-gate 			scf_transaction_reset(tx);
3680Sstevel@tonic-gate 			if (scf_pg_update(gpg) == -1)
3690Sstevel@tonic-gate 				scfdie();
3700Sstevel@tonic-gate 		}
3710Sstevel@tonic-gate 	} while (ret == 0);
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	(void) scf_entry_destroy(ent);
3740Sstevel@tonic-gate 	scf_transaction_destroy(tx);
3750Sstevel@tonic-gate 	scf_property_destroy(eprop);
3760Sstevel@tonic-gate 	scf_pg_destroy(gpg);
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate /*
3800Sstevel@tonic-gate  * commit_props evaluates an entire property list that has been created
3810Sstevel@tonic-gate  * based on command line options, and either deletes or modifies properties
3820Sstevel@tonic-gate  * as requested.
3830Sstevel@tonic-gate  */
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate static void
commit_props(const scf_instance_t * inst,inetd_prop_t * mod,boolean_t defaults)3860Sstevel@tonic-gate commit_props(const scf_instance_t *inst, inetd_prop_t *mod, boolean_t defaults)
3870Sstevel@tonic-gate {
3880Sstevel@tonic-gate 	int			i;
3890Sstevel@tonic-gate 	uint8_t			new_bool;
3900Sstevel@tonic-gate 
391*1293Smh138676 	for (i = 0; mod[i].ip_name != NULL; i++) {
3920Sstevel@tonic-gate 		switch (mod[i].ip_error) {
3930Sstevel@tonic-gate 		case IVE_UNSET:
3940Sstevel@tonic-gate 			break;
3950Sstevel@tonic-gate 		case IVE_INVALID:
3960Sstevel@tonic-gate 			delete_prop(inst, mod[i].ip_pg, mod[i].ip_name);
3970Sstevel@tonic-gate 			break;
3980Sstevel@tonic-gate 		case IVE_VALID:
3990Sstevel@tonic-gate 			switch (mod[i].ip_type) {
400*1293Smh138676 			case INET_TYPE_STRING:
4010Sstevel@tonic-gate 				modify_prop(inst,
4020Sstevel@tonic-gate 				    defaults ? PG_NAME_SERVICE_DEFAULTS :
4030Sstevel@tonic-gate 				    mod[i].ip_pg, mod[i].ip_name,
4040Sstevel@tonic-gate 				    SCF_TYPE_ASTRING,
405*1293Smh138676 				    mod[i].ip_value.iv_string);
4060Sstevel@tonic-gate 				break;
407*1293Smh138676 			case INET_TYPE_STRING_LIST:
408*1293Smh138676 				modify_prop(inst,
409*1293Smh138676 				    defaults ? PG_NAME_SERVICE_DEFAULTS :
410*1293Smh138676 				    mod[i].ip_pg, mod[i].ip_name,
411*1293Smh138676 				    SCF_TYPE_ASTRING,
412*1293Smh138676 				    mod[i].ip_value.iv_string_list);
413*1293Smh138676 				break;
414*1293Smh138676 			case INET_TYPE_INTEGER:
4150Sstevel@tonic-gate 				modify_prop(inst,
4160Sstevel@tonic-gate 				    defaults ? PG_NAME_SERVICE_DEFAULTS :
4170Sstevel@tonic-gate 				    mod[i].ip_pg, mod[i].ip_name,
4180Sstevel@tonic-gate 				    SCF_TYPE_INTEGER, &mod[i].ip_value.iv_int);
4190Sstevel@tonic-gate 				break;
420*1293Smh138676 			case INET_TYPE_BOOLEAN:
4210Sstevel@tonic-gate 				new_bool = (mod[i].ip_value.iv_boolean) ? 1 : 0;
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 				modify_prop(inst,
4240Sstevel@tonic-gate 				    defaults ? PG_NAME_SERVICE_DEFAULTS :
4250Sstevel@tonic-gate 				    mod[i].ip_pg, mod[i].ip_name,
4260Sstevel@tonic-gate 				    SCF_TYPE_BOOLEAN, &new_bool);
4270Sstevel@tonic-gate 				break;
4280Sstevel@tonic-gate 			}
4290Sstevel@tonic-gate 		}
4300Sstevel@tonic-gate 	}
4310Sstevel@tonic-gate }
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate /*
4340Sstevel@tonic-gate  * list_callback is the callback function to be handed to simple_walk_instances
4350Sstevel@tonic-gate  * in list_services.  It is called once on every instance on a machine.  If
4360Sstevel@tonic-gate  * that instance is controlled by inetd, it prints enabled/disabled, state,
4370Sstevel@tonic-gate  * and instance FMRI.
4380Sstevel@tonic-gate  */
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate /*ARGSUSED*/
4410Sstevel@tonic-gate static int
list_callback(scf_handle_t * hin,scf_instance_t * inst,void * buf)4420Sstevel@tonic-gate list_callback(scf_handle_t *hin, scf_instance_t *inst, void *buf)
4430Sstevel@tonic-gate {
4440Sstevel@tonic-gate 	ssize_t			max_name_length;
4450Sstevel@tonic-gate 	char			*inst_name;
4460Sstevel@tonic-gate 	scf_simple_prop_t	*prop = NULL, *prop2 = NULL;
4470Sstevel@tonic-gate 	const uint8_t		*enabled;
4480Sstevel@tonic-gate 	const char		*state, *restart_str;
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	max_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
4510Sstevel@tonic-gate 	if ((inst_name = malloc(max_name_length + 1)) == NULL)
4520Sstevel@tonic-gate 		uu_die(gettext("Error: Out of memory.\n"));
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	/*
4550Sstevel@tonic-gate 	 * Get the FMRI of the instance, and check if its delegated restarter
4560Sstevel@tonic-gate 	 * is inetd.
4570Sstevel@tonic-gate 	 */
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	if (scf_instance_to_fmri(inst, inst_name, max_name_length + 1) < 0)
4600Sstevel@tonic-gate 		return (SCF_FAILED);
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	if ((prop = scf_simple_prop_get(hin, inst_name, SCF_PG_GENERAL,
4630Sstevel@tonic-gate 	    SCF_PROPERTY_RESTARTER)) == NULL)
4640Sstevel@tonic-gate 		goto out;
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	if ((restart_str = scf_simple_prop_next_ustring(prop)) == NULL)
4670Sstevel@tonic-gate 		goto out;
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	if (strstr(restart_str, INETADM_INETD_STR) == NULL)
4700Sstevel@tonic-gate 		goto out;
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	/* Free restarter prop so it can be reused below */
4730Sstevel@tonic-gate 	scf_simple_prop_free(prop);
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	/*
4760Sstevel@tonic-gate 	 * We know that this instance is managed by inetd.
4770Sstevel@tonic-gate 	 * Now get the enabled and state properties.
4780Sstevel@tonic-gate 	 */
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	if (((prop = scf_simple_prop_get(hin, inst_name, SCF_PG_GENERAL,
4810Sstevel@tonic-gate 	    SCF_PROPERTY_ENABLED)) == NULL) ||
4820Sstevel@tonic-gate 	    ((enabled = scf_simple_prop_next_boolean(prop)) == NULL)) {
4830Sstevel@tonic-gate 		(void) uu_warn(gettext("Error: Instance %s is missing enabled "
4840Sstevel@tonic-gate 		    "property.\n"), inst_name);
4850Sstevel@tonic-gate 		goto out;
4860Sstevel@tonic-gate 	}
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	if (((prop2 = scf_simple_prop_get(hin, inst_name, SCF_PG_RESTARTER,
4890Sstevel@tonic-gate 	    SCF_PROPERTY_STATE)) == NULL) ||
4900Sstevel@tonic-gate 	    ((state = scf_simple_prop_next_astring(prop2)) == NULL)) {
4910Sstevel@tonic-gate 		(void) uu_warn(gettext("Error: Instance %s is missing state "
4920Sstevel@tonic-gate 		    "property.\n"), inst_name);
4930Sstevel@tonic-gate 		goto out;
4940Sstevel@tonic-gate 	}
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	/* Print enabled/disabled, state, and FMRI for the instance. */
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	if (*enabled)
4990Sstevel@tonic-gate 		(void) printf("%-10s%-15s%s\n", INETADM_ENABLED_STR, state,
5000Sstevel@tonic-gate 		    inst_name);
5010Sstevel@tonic-gate 	else
5020Sstevel@tonic-gate 		(void) printf("%-10s%-15s%s\n", INETADM_DISABLED_STR, state,
5030Sstevel@tonic-gate 		    inst_name);
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate out:
5060Sstevel@tonic-gate 	free(inst_name);
5070Sstevel@tonic-gate 	scf_simple_prop_free(prop);
5080Sstevel@tonic-gate 	scf_simple_prop_free(prop2);
5090Sstevel@tonic-gate 	return (SCF_SUCCESS);
5100Sstevel@tonic-gate }
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate /*
5130Sstevel@tonic-gate  * list_services calls list_callback on every instance on the machine.
5140Sstevel@tonic-gate  */
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate static void
list_services()5170Sstevel@tonic-gate list_services()
5180Sstevel@tonic-gate {
5190Sstevel@tonic-gate 	(void) printf("%-10s%-15s%s\n", "ENABLED", "STATE", "FMRI");
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	if (scf_simple_walk_instances(SCF_STATE_ALL, NULL, list_callback) ==
5220Sstevel@tonic-gate 	    SCF_FAILED)
5230Sstevel@tonic-gate 		scfdie();
5240Sstevel@tonic-gate }
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate static void
print_prop_val(inetd_prop_t * prop)527*1293Smh138676 print_prop_val(inetd_prop_t *prop)
5280Sstevel@tonic-gate {
5290Sstevel@tonic-gate 	switch (prop->ip_type) {
530*1293Smh138676 	case INET_TYPE_STRING:
531*1293Smh138676 		(void) printf("\"%s\"\n", prop->ip_value.iv_string);
532*1293Smh138676 		break;
533*1293Smh138676 	case INET_TYPE_STRING_LIST:
534*1293Smh138676 		{
5350Sstevel@tonic-gate 			int	j = 0;
536*1293Smh138676 			char	**cpp = prop->ip_value.iv_string_list;
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 			/*
539*1293Smh138676 			 * Print string list as comma separated list.
5400Sstevel@tonic-gate 			 */
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 			(void) printf("\"%s", cpp[j]);
5430Sstevel@tonic-gate 			while (cpp[++j] != NULL)
5440Sstevel@tonic-gate 				(void) printf(",%s", cpp[j]);
5450Sstevel@tonic-gate 			(void) printf("\"\n");
5460Sstevel@tonic-gate 		}
5470Sstevel@tonic-gate 		break;
548*1293Smh138676 	case INET_TYPE_INTEGER:
5490Sstevel@tonic-gate 		(void) printf("%lld\n", prop->ip_value.iv_int);
5500Sstevel@tonic-gate 		break;
551*1293Smh138676 	case INET_TYPE_BOOLEAN:
5520Sstevel@tonic-gate 		if (prop->ip_value.iv_boolean)
5530Sstevel@tonic-gate 			(void) printf("%s\n", INETADM_TRUE_STR);
5540Sstevel@tonic-gate 		else
5550Sstevel@tonic-gate 			(void) printf("%s\n", INETADM_FALSE_STR);
5560Sstevel@tonic-gate 		break;
5570Sstevel@tonic-gate 	}
5580Sstevel@tonic-gate }
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate /*
5610Sstevel@tonic-gate  * list_props_cb is a callback function for scf_walk_fmri that lists all
5620Sstevel@tonic-gate  * relevant inetd properties for an instance managed by inetd.
5630Sstevel@tonic-gate  */
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate /* ARGSUSED0 */
5660Sstevel@tonic-gate static int
list_props_cb(void * data,scf_walkinfo_t * wip)5670Sstevel@tonic-gate list_props_cb(void *data, scf_walkinfo_t *wip)
5680Sstevel@tonic-gate {
5690Sstevel@tonic-gate 	int			i;
5700Sstevel@tonic-gate 	const char		*instname = wip->fmri;
5710Sstevel@tonic-gate 	scf_simple_prop_t	*prop;
5720Sstevel@tonic-gate 	inetd_prop_t		*proplist;
5730Sstevel@tonic-gate 	const char		*restart_str;
5740Sstevel@tonic-gate 	boolean_t		is_rpc = B_FALSE;
5750Sstevel@tonic-gate 	size_t			numprops;
5760Sstevel@tonic-gate 	scf_handle_t		*h;
5770Sstevel@tonic-gate 	scf_error_t		err;
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	if (((h = scf_handle_create(SCF_VERSION)) == NULL) ||
5800Sstevel@tonic-gate 	    (scf_handle_bind(h) == -1))
5810Sstevel@tonic-gate 		scfdie();
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	/*
5840Sstevel@tonic-gate 	 * Get the property that holds the name of this instance's
5850Sstevel@tonic-gate 	 * restarter, and make sure that it is inetd.
5860Sstevel@tonic-gate 	 */
5870Sstevel@tonic-gate 	if ((prop = scf_simple_prop_get(h, instname, SCF_PG_GENERAL,
5880Sstevel@tonic-gate 	    SCF_PROPERTY_RESTARTER)) == NULL) {
5890Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_NOT_FOUND)
5900Sstevel@tonic-gate 			uu_die(gettext("Error: Specified service instance "
5910Sstevel@tonic-gate 			    "\"%s\" has no restarter property.  inetd is not "
5920Sstevel@tonic-gate 			    "the delegated restarter of this instance.\n"),
5930Sstevel@tonic-gate 			    instname);
5940Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_INVALID_ARGUMENT)
5950Sstevel@tonic-gate 			uu_die(gettext("Error: \"%s\" is not a valid service "
5960Sstevel@tonic-gate 			    "instance.\n"), instname);
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 		scfdie();
5990Sstevel@tonic-gate 	}
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	if (((restart_str = scf_simple_prop_next_ustring(prop)) == NULL) ||
6020Sstevel@tonic-gate 	    (strstr(restart_str, INETADM_INETD_STR) == NULL)) {
6030Sstevel@tonic-gate 		uu_die(gettext("Error: inetd is not the delegated restarter of "
6040Sstevel@tonic-gate 		    "specified service instance \"%s\".\n"), instname);
6050Sstevel@tonic-gate 	}
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	scf_simple_prop_free(prop);
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	/*
6100Sstevel@tonic-gate 	 * This instance is controlled by inetd, so now we display all
6110Sstevel@tonic-gate 	 * of its properties.  First the mandatory properties, and then
6120Sstevel@tonic-gate 	 * the properties that have default values, substituting the
6130Sstevel@tonic-gate 	 * default values inherited from inetd as necessary (this is done
6140Sstevel@tonic-gate 	 * for us by read_instance_props()).
6150Sstevel@tonic-gate 	 */
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	if ((proplist = read_instance_props(h, instname, &numprops, &err)) ==
6180Sstevel@tonic-gate 	    NULL) {
6190Sstevel@tonic-gate 		uu_die(gettext("Unexpected libscf error: %s.  Exiting.\n"),
6200Sstevel@tonic-gate 		    scf_strerror(err));
6210Sstevel@tonic-gate 	}
6220Sstevel@tonic-gate 	scf_handle_destroy(h);
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	(void) printf("%-9s%s\n", "SCOPE", "NAME=VALUE");
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	for (i = 0; i < numprops; i++) {
6270Sstevel@tonic-gate 		/* Skip rpc version properties if it's not an RPC service */
6280Sstevel@tonic-gate 		if ((strcmp(PR_RPC_LW_VER_NAME, proplist[i].ip_name) == 0) ||
6290Sstevel@tonic-gate 		    (strcmp(PR_RPC_HI_VER_NAME, proplist[i].ip_name) == 0))
6300Sstevel@tonic-gate 			if (!is_rpc)
6310Sstevel@tonic-gate 				continue;
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 		/* If it's not an unset property, print it out. */
6340Sstevel@tonic-gate 		if (proplist[i].ip_error != IVE_UNSET) {
6350Sstevel@tonic-gate 			if (strcmp(PR_ISRPC_NAME, proplist[i].ip_name) == 0)
6360Sstevel@tonic-gate 				is_rpc = proplist[i].ip_value.iv_boolean;
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 			(void) printf("%-9s%s=",
6390Sstevel@tonic-gate 			    proplist[i].from_inetd ? INETADM_DEFAULT_STR : "",
6400Sstevel@tonic-gate 			    proplist[i].ip_name);
641*1293Smh138676 			print_prop_val(&proplist[i]);
6420Sstevel@tonic-gate 			continue;
6430Sstevel@tonic-gate 		}
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 		/* arg0 is non-default, but also doesn't have to be set. */
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 		if (i == PT_ARG0_INDEX)
6480Sstevel@tonic-gate 			continue;
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 		/* all other properties should have values. */
6510Sstevel@tonic-gate 		if (proplist[i].ip_default) {
6520Sstevel@tonic-gate 			(void) uu_warn(gettext("Error: Property %s is missing "
6530Sstevel@tonic-gate 			    "and has no defined default value.\n"),
6540Sstevel@tonic-gate 			    proplist[i].ip_name);
6550Sstevel@tonic-gate 		} else {
6560Sstevel@tonic-gate 			(void) uu_warn(gettext("Error: Required property %s is "
6570Sstevel@tonic-gate 			    "missing.\n"), proplist[i].ip_name);
6580Sstevel@tonic-gate 		}
6590Sstevel@tonic-gate 	}
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 	free_instance_props(proplist);
6620Sstevel@tonic-gate 	return (0);
6630Sstevel@tonic-gate }
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate /*
6660Sstevel@tonic-gate  * set_svc_enable_cb is a callback function for scf_walk_fmri that sets the
6670Sstevel@tonic-gate  * enabled property in the repository for an instance based on the value given
6680Sstevel@tonic-gate  * by 'data'.
6690Sstevel@tonic-gate  */
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate static int
set_svc_enable_cb(void * data,scf_walkinfo_t * wip)6720Sstevel@tonic-gate set_svc_enable_cb(void *data, scf_walkinfo_t *wip)
6730Sstevel@tonic-gate {
6740Sstevel@tonic-gate 	uint8_t			desired = *(uint8_t *)data;
6750Sstevel@tonic-gate 	const char		*instname = wip->fmri;
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	if (desired) {
6780Sstevel@tonic-gate 		if (smf_enable_instance(instname, 0) == 0)
6790Sstevel@tonic-gate 			return (0);
6800Sstevel@tonic-gate 	} else {
6810Sstevel@tonic-gate 		if (smf_disable_instance(instname, 0) == 0)
6820Sstevel@tonic-gate 			return (0);
6830Sstevel@tonic-gate 	}
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	switch (scf_error()) {
6860Sstevel@tonic-gate 	case SCF_ERROR_INVALID_ARGUMENT:
6870Sstevel@tonic-gate 		uu_die(gettext("Error: \"%s\" is not a valid service "
6880Sstevel@tonic-gate 		    "instance.\n"), instname);
6890Sstevel@tonic-gate 		break;
6900Sstevel@tonic-gate 	case SCF_ERROR_NOT_FOUND:
6910Sstevel@tonic-gate 		uu_die(gettext("Error: Service instance \"%s\" not found.\n"),
6920Sstevel@tonic-gate 		    instname);
6930Sstevel@tonic-gate 		break;
6940Sstevel@tonic-gate 	default:
6950Sstevel@tonic-gate 		scfdie();
6960Sstevel@tonic-gate 	}
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	return (0);
6990Sstevel@tonic-gate }
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate /*
7020Sstevel@tonic-gate  * list_defaults lists all the default property values being provided by
7030Sstevel@tonic-gate  * inetd.
7040Sstevel@tonic-gate  */
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate static void
list_defaults()7070Sstevel@tonic-gate list_defaults()
7080Sstevel@tonic-gate {
7090Sstevel@tonic-gate 	scf_handle_t		*h;
7100Sstevel@tonic-gate 	scf_error_t		err;
7110Sstevel@tonic-gate 	int			i;
7120Sstevel@tonic-gate 	inetd_prop_t		*proptable;
7130Sstevel@tonic-gate 	size_t			numprops;
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	if (((h = scf_handle_create(SCF_VERSION)) == NULL) ||
7160Sstevel@tonic-gate 	    (scf_handle_bind(h) == -1))
7170Sstevel@tonic-gate 		scfdie();
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 	if ((proptable = read_default_props(h, &numprops, &err)) == NULL) {
7200Sstevel@tonic-gate 		uu_die(gettext("Unexpected libscf error: %s.  Exiting.\n"),
7210Sstevel@tonic-gate 		    scf_strerror(err));
7220Sstevel@tonic-gate 	}
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	(void) printf("NAME=VALUE\n");
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	for (i = 0; i < numprops; i++) {
7270Sstevel@tonic-gate 		if (!proptable[i].ip_default)
7280Sstevel@tonic-gate 			continue;
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 		if (proptable[i].ip_error == IVE_UNSET) {
7310Sstevel@tonic-gate 			(void) uu_warn(gettext("Error: Default property %s "
7320Sstevel@tonic-gate 			    "missing.\n"), proptable[i].ip_name);
7330Sstevel@tonic-gate 			continue;
7340Sstevel@tonic-gate 		}
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 		(void) printf("%s=", proptable[i].ip_name);
737*1293Smh138676 		print_prop_val(&proptable[i]);
7380Sstevel@tonic-gate 	}
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	free_instance_props(proptable);
7410Sstevel@tonic-gate }
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate /*
7440Sstevel@tonic-gate  * modify_inst_props_cb is a callback function for scf_walk_fmri that modifies
7450Sstevel@tonic-gate  * the properties that are given as name=value pairs on the command line
7460Sstevel@tonic-gate  * to the requested value.
7470Sstevel@tonic-gate  */
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate static int
modify_inst_props_cb(void * data,scf_walkinfo_t * wip)7500Sstevel@tonic-gate modify_inst_props_cb(void *data, scf_walkinfo_t *wip)
7510Sstevel@tonic-gate {
7520Sstevel@tonic-gate 	int			i, j;
7530Sstevel@tonic-gate 	char			*value;
7540Sstevel@tonic-gate 	const char		*fmri = wip->fmri;
7550Sstevel@tonic-gate 	scf_instance_t		*inst = wip->inst;
7560Sstevel@tonic-gate 	inetd_prop_t		*mod, *prop_table;
7570Sstevel@tonic-gate 	size_t			numprops;
7580Sstevel@tonic-gate 	ssize_t			max_val;
7590Sstevel@tonic-gate 	int64_t			new_int;
7600Sstevel@tonic-gate 	int			argc = ((arglist_t *)data)->argc;
7610Sstevel@tonic-gate 	char			**argv = ((arglist_t *)data)->argv;
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	if ((max_val = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
7640Sstevel@tonic-gate 		scfdie();
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 	prop_table = get_prop_table(&numprops);
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	if ((mod = malloc(numprops * sizeof (inetd_prop_t))) == NULL)
7690Sstevel@tonic-gate 		uu_die(gettext("Error: Out of memory.\n"));
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 	(void) memcpy(mod, prop_table, numprops * sizeof (inetd_prop_t));
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 	/*
7740Sstevel@tonic-gate 	 * For each property to be changed, look up the property name in the
7750Sstevel@tonic-gate 	 * property table.  Change each property in the mod array, and then
7760Sstevel@tonic-gate 	 * write the entire thing back.
7770Sstevel@tonic-gate 	 */
7780Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
7790Sstevel@tonic-gate 		/* Separate argument into name and value pair */
7800Sstevel@tonic-gate 		if ((value = strchr(argv[i], '=')) == NULL)
7810Sstevel@tonic-gate 			uu_die(gettext("Error: Malformed name=value pair "
7820Sstevel@tonic-gate 			    "\"%s\"\n"), argv[i]);
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 		*value = '\0';
7850Sstevel@tonic-gate 		value++;
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 		/* Find property name in array of properties */
788*1293Smh138676 		for (j = 0; mod[j].ip_name != NULL; j++) {
7890Sstevel@tonic-gate 			if (strcmp(mod[j].ip_name, argv[i]) == 0)
7900Sstevel@tonic-gate 				break;
7910Sstevel@tonic-gate 		}
7920Sstevel@tonic-gate 
793*1293Smh138676 		if (mod[j].ip_name == NULL)
7940Sstevel@tonic-gate 			uu_die(gettext("Error: \"%s\" is not a valid "
7950Sstevel@tonic-gate 			    "property.\n"), argv[i]);
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 		if (*value == '\0') {
7980Sstevel@tonic-gate 			if ((mod[j].ip_default) || (j == PT_ARG0_INDEX)) {
7990Sstevel@tonic-gate 				/* mark property for deletion */
8000Sstevel@tonic-gate 				mod[j].ip_error = IVE_INVALID;
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 				/* return the '=' taken out above */
8030Sstevel@tonic-gate 				*(--value) = '=';
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 				continue;
8060Sstevel@tonic-gate 			} else {
8070Sstevel@tonic-gate 				uu_die(gettext("\"%s\" is a mandatory "
8080Sstevel@tonic-gate 				    "property and can not be deleted.\n"),
8090Sstevel@tonic-gate 				    argv[i]);
8100Sstevel@tonic-gate 			}
8110Sstevel@tonic-gate 		}
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 		switch (mod[j].ip_type) {
814*1293Smh138676 		case INET_TYPE_INTEGER:
8150Sstevel@tonic-gate 			if (uu_strtoint(value, &new_int, sizeof (new_int), NULL,
8160Sstevel@tonic-gate 			    NULL, NULL) == -1)
8170Sstevel@tonic-gate 				uu_die(gettext("Error: \"%s\" is not a valid "
8180Sstevel@tonic-gate 				    "integer value.\n"), value);
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 			mod[j].ip_value.iv_int = new_int;
8210Sstevel@tonic-gate 			break;
822*1293Smh138676 		case INET_TYPE_STRING:
823*1293Smh138676 			if (strlen(value) >= max_val) {
8240Sstevel@tonic-gate 				uu_die(gettext("Error: String value is longer "
8250Sstevel@tonic-gate 				    "than %l characters.\n"), max_val);
826*1293Smh138676 			} else if ((mod[j].ip_value.iv_string = strdup(value))
8270Sstevel@tonic-gate 			    == NULL) {
8280Sstevel@tonic-gate 				uu_die(gettext("Error: Out of memory.\n"));
8290Sstevel@tonic-gate 			}
8300Sstevel@tonic-gate 			break;
831*1293Smh138676 		case INET_TYPE_STRING_LIST:
832*1293Smh138676 			if ((mod[j].ip_value.iv_string_list =
833*1293Smh138676 			    get_protos(value)) == NULL) {
834*1293Smh138676 				if (errno == ENOMEM) {
835*1293Smh138676 					uu_die(gettext(
836*1293Smh138676 					    "Error: Out of memory.\n"));
837*1293Smh138676 				} else if (errno == E2BIG) {
838*1293Smh138676 					uu_die(gettext(
839*1293Smh138676 					    "Error: String value in "
840*1293Smh138676 					    "%s property longer than "
841*1293Smh138676 					    "%l characters.\n"),
842*1293Smh138676 					    PR_PROTO_NAME, max_val);
843*1293Smh138676 				} else {
844*1293Smh138676 					uu_die(gettext(
845*1293Smh138676 					    "Error: No values "
846*1293Smh138676 					    "specified for %s "
847*1293Smh138676 					    "property.\n"),
848*1293Smh138676 					    PR_PROTO_NAME);
849*1293Smh138676 				}
850*1293Smh138676 			}
851*1293Smh138676 			break;
852*1293Smh138676 		case INET_TYPE_BOOLEAN:
8530Sstevel@tonic-gate 			if (strcasecmp(value, INETADM_TRUE_STR) == 0)
8540Sstevel@tonic-gate 				mod[j].ip_value.iv_boolean = B_TRUE;
8550Sstevel@tonic-gate 			else if (strcasecmp(value, INETADM_FALSE_STR) == 0)
8560Sstevel@tonic-gate 				mod[j].ip_value.iv_boolean = B_FALSE;
8570Sstevel@tonic-gate 			else
8580Sstevel@tonic-gate 				uu_die(gettext("Error: \"%s\" is not a valid "
8590Sstevel@tonic-gate 				    "boolean value. (TRUE or FALSE)\n"), value);
8600Sstevel@tonic-gate 		}
8610Sstevel@tonic-gate 		/* mark property for modification */
8620Sstevel@tonic-gate 		mod[j].ip_error = IVE_VALID;
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 		/* return the '=' taken out above */
8650Sstevel@tonic-gate 		*(--value) = '=';
8660Sstevel@tonic-gate 	}
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	commit_props(inst, mod, B_FALSE);
8690Sstevel@tonic-gate 	free(mod);
8700Sstevel@tonic-gate 	if (smf_refresh_instance(fmri) != 0)
8710Sstevel@tonic-gate 		uu_die(gettext("Error: Unable to refresh instance %s.\n"),
8720Sstevel@tonic-gate 		    fmri);
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	return (0);
8750Sstevel@tonic-gate }
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate /*
8780Sstevel@tonic-gate  * modify_defaults takes n name=value pairs for inetd default property values,
8790Sstevel@tonic-gate  * parses them, and then modifies the values in the repository.
8800Sstevel@tonic-gate  */
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate static void
modify_defaults(int argc,char * argv[])8830Sstevel@tonic-gate modify_defaults(int argc, char *argv[])
8840Sstevel@tonic-gate {
8850Sstevel@tonic-gate 	int			i, j;
8860Sstevel@tonic-gate 	char			*value;
8870Sstevel@tonic-gate 	scf_instance_t		*inst;
8880Sstevel@tonic-gate 	inetd_prop_t		*mod, *prop_table;
8890Sstevel@tonic-gate 	size_t			numprops;
8900Sstevel@tonic-gate 	ssize_t			max_val;
8910Sstevel@tonic-gate 	int64_t			new_int;
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 	if ((inst = scf_instance_create(h)) == NULL)
8940Sstevel@tonic-gate 		scfdie();
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 	if (scf_handle_decode_fmri(h, INETD_INSTANCE_FMRI, NULL, NULL,
8970Sstevel@tonic-gate 	    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
8980Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
8990Sstevel@tonic-gate 			uu_die(gettext("inetd instance missing in repository."
9000Sstevel@tonic-gate 			    "\n"));
9010Sstevel@tonic-gate 		} else {
9020Sstevel@tonic-gate 			scfdie();
9030Sstevel@tonic-gate 		}
9040Sstevel@tonic-gate 	}
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	if ((max_val = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
9070Sstevel@tonic-gate 		scfdie();
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	prop_table = get_prop_table(&numprops);
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 	if ((mod = malloc(numprops * sizeof (inetd_prop_t))) == NULL)
9120Sstevel@tonic-gate 		uu_die(gettext("Error: Out of memory.\n"));
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 	(void) memcpy(mod, prop_table, numprops * sizeof (inetd_prop_t));
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
9170Sstevel@tonic-gate 		/* Separate argument into name and value pair */
9180Sstevel@tonic-gate 		if ((value = strchr(argv[i], '=')) == NULL)
9190Sstevel@tonic-gate 			uu_die(gettext("Error: Malformed name=value pair \"%s"
9200Sstevel@tonic-gate 			    "\"\n"), argv[i]);
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 		*value = '\0';
9230Sstevel@tonic-gate 		value++;
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 		/* Find property name in array of defaults */
926*1293Smh138676 		for (j = 0; mod[j].ip_name != NULL; j++) {
9270Sstevel@tonic-gate 			if (!mod[j].ip_default)
9280Sstevel@tonic-gate 				continue;
9290Sstevel@tonic-gate 			if (strcmp(mod[j].ip_name, argv[i]) == 0)
9300Sstevel@tonic-gate 				break;
9310Sstevel@tonic-gate 		}
9320Sstevel@tonic-gate 
933*1293Smh138676 		if (mod[j].ip_name == NULL)
9340Sstevel@tonic-gate 			uu_die(gettext("Error: \"%s\" is not a default inetd "
9350Sstevel@tonic-gate 			    "property.\n"), argv[i]);
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 		if (*value == '\0')
9380Sstevel@tonic-gate 			uu_die(gettext("Cannot accept NULL values for default "
9390Sstevel@tonic-gate 			    "properties.\n"));
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 		switch (mod[j].ip_type) {
942*1293Smh138676 		case INET_TYPE_INTEGER:
9430Sstevel@tonic-gate 			if (uu_strtoint(value, &new_int, sizeof (new_int), NULL,
9440Sstevel@tonic-gate 			    NULL, NULL) == -1)
9450Sstevel@tonic-gate 				uu_die(gettext("Error: \"%s\" is not a valid "
9460Sstevel@tonic-gate 				    "integer value.\n"), value);
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 			mod[j].ip_value.iv_int = new_int;
9490Sstevel@tonic-gate 			break;
950*1293Smh138676 		case INET_TYPE_STRING:
9510Sstevel@tonic-gate 			if (strlen(value) >= max_val)
9520Sstevel@tonic-gate 				uu_die(gettext("Error: String value is longer "
9530Sstevel@tonic-gate 				    "than %l characters.\n"), max_val);
954*1293Smh138676 			if ((mod[j].ip_value.iv_string = strdup(value))
9550Sstevel@tonic-gate 			    == NULL)
9560Sstevel@tonic-gate 				uu_die(gettext("Error: Out of memory.\n"));
9570Sstevel@tonic-gate 			break;
958*1293Smh138676 		case INET_TYPE_BOOLEAN:
9590Sstevel@tonic-gate 			if (strcasecmp(value, INETADM_TRUE_STR) == 0)
9600Sstevel@tonic-gate 				mod[j].ip_value.iv_boolean = B_TRUE;
9610Sstevel@tonic-gate 			else if (strcasecmp(value, INETADM_FALSE_STR) == 0)
9620Sstevel@tonic-gate 				mod[j].ip_value.iv_boolean = B_FALSE;
9630Sstevel@tonic-gate 			else
9640Sstevel@tonic-gate 				uu_die(gettext("Error: \"%s\" is not a valid "
9650Sstevel@tonic-gate 				    "boolean value. (TRUE or FALSE)\n"), value);
9660Sstevel@tonic-gate 		}
9670Sstevel@tonic-gate 		/* mark property for modification */
9680Sstevel@tonic-gate 		mod[j].ip_error = IVE_VALID;
9690Sstevel@tonic-gate 	}
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	commit_props(inst, mod, B_TRUE);
9720Sstevel@tonic-gate 	free(mod);
9730Sstevel@tonic-gate 	scf_instance_destroy(inst);
9740Sstevel@tonic-gate 	if (refresh_inetd() != 0)
9750Sstevel@tonic-gate 		uu_warn(gettext("Warning: Unable to refresh inetd.\n"));
9760Sstevel@tonic-gate }
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate int
main(int argc,char * argv[])9790Sstevel@tonic-gate main(int argc, char *argv[])
9800Sstevel@tonic-gate {
9810Sstevel@tonic-gate 	int		opt;
9820Sstevel@tonic-gate 	uint_t		lflag, eflag, dflag, pflag, mflag, Mflag;
9830Sstevel@tonic-gate 	uint8_t		enable;
9840Sstevel@tonic-gate 	scf_error_t	serr;
9850Sstevel@tonic-gate 	int		exit_status = 0;
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
9880Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 	if ((h = scf_handle_create(SCF_VERSION)) == NULL)
9910Sstevel@tonic-gate 		scfdie();
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate 	if (scf_handle_bind(h) == -1)
9940Sstevel@tonic-gate 		uu_die(gettext("Error: Couldn't bind to svc.configd.\n"));
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 	if (argc == 1) {
9970Sstevel@tonic-gate 		list_services();
9980Sstevel@tonic-gate 		goto out;
9990Sstevel@tonic-gate 	}
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 	lflag = eflag = dflag = pflag = mflag = Mflag = 0;
10020Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "ledpMm?")) != -1) {
10030Sstevel@tonic-gate 		switch (opt) {
10040Sstevel@tonic-gate 		case 'l':
10050Sstevel@tonic-gate 			lflag = 1;
10060Sstevel@tonic-gate 			break;
10070Sstevel@tonic-gate 		case 'e':
10080Sstevel@tonic-gate 			eflag = 1;
10090Sstevel@tonic-gate 			break;
10100Sstevel@tonic-gate 		case 'd':
10110Sstevel@tonic-gate 			dflag = 1;
10120Sstevel@tonic-gate 			break;
10130Sstevel@tonic-gate 		case 'p':
10140Sstevel@tonic-gate 			pflag = 1;
10150Sstevel@tonic-gate 			break;
10160Sstevel@tonic-gate 		case 'M':
10170Sstevel@tonic-gate 			Mflag = 1;
10180Sstevel@tonic-gate 			break;
10190Sstevel@tonic-gate 		case 'm':
10200Sstevel@tonic-gate 			mflag = 1;
10210Sstevel@tonic-gate 			break;
10220Sstevel@tonic-gate 		case '?':
10230Sstevel@tonic-gate 			if (optopt == '?') {
10240Sstevel@tonic-gate 				usage(B_TRUE);
10250Sstevel@tonic-gate 				goto out;
10260Sstevel@tonic-gate 			} else {
10270Sstevel@tonic-gate 				usage(B_FALSE);
10280Sstevel@tonic-gate 			}
10290Sstevel@tonic-gate 		default:
10300Sstevel@tonic-gate 			usage(B_FALSE);
10310Sstevel@tonic-gate 		}
10320Sstevel@tonic-gate 	}
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	/*
10350Sstevel@tonic-gate 	 * All options are mutually exclusive, and we must have an option
10360Sstevel@tonic-gate 	 * if we reached here.
10370Sstevel@tonic-gate 	 */
10380Sstevel@tonic-gate 	if (lflag + eflag + dflag + pflag + mflag + Mflag != 1)
10390Sstevel@tonic-gate 		usage(B_FALSE);
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 	argv += optind;
10420Sstevel@tonic-gate 	argc -= optind;
10430Sstevel@tonic-gate 	if ((pflag == 0) && (argc == 0))
10440Sstevel@tonic-gate 		usage(B_FALSE);
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate 	serr = 0;
10470Sstevel@tonic-gate 	if (lflag) {
10480Sstevel@tonic-gate 		serr = scf_walk_fmri(h, argc, argv, 0, list_props_cb, NULL,
10490Sstevel@tonic-gate 		    &exit_status, uu_warn);
10500Sstevel@tonic-gate 	} else if (dflag) {
10510Sstevel@tonic-gate 		enable = 0;
10520Sstevel@tonic-gate 		serr = scf_walk_fmri(h, argc, argv, 0, set_svc_enable_cb,
10530Sstevel@tonic-gate 		    &enable, &exit_status, uu_warn);
10540Sstevel@tonic-gate 	} else if (eflag) {
10550Sstevel@tonic-gate 		enable = 1;
10560Sstevel@tonic-gate 		serr = scf_walk_fmri(h, argc, argv, 0, set_svc_enable_cb,
10570Sstevel@tonic-gate 		    &enable, &exit_status, uu_warn);
10580Sstevel@tonic-gate 	} else if (mflag) {
10590Sstevel@tonic-gate 		arglist_t	args;
10600Sstevel@tonic-gate 		char		**cpp = argv;
10610Sstevel@tonic-gate 		uint_t		fmri_args = 0;
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 		/* count number of fmri arguments */
10640Sstevel@tonic-gate 		while ((fmri_args < argc) && (strchr(*cpp, '=') == NULL)) {
10650Sstevel@tonic-gate 			fmri_args++;
10660Sstevel@tonic-gate 			cpp++;
10670Sstevel@tonic-gate 		}
10680Sstevel@tonic-gate 
10690Sstevel@tonic-gate 		/* if no x=y args or no fmri, show usage */
10700Sstevel@tonic-gate 		if ((fmri_args == argc) || (fmri_args == 0))
10710Sstevel@tonic-gate 			usage(B_FALSE);
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate 		/* setup args for modify_inst_props_cb */
10740Sstevel@tonic-gate 		args.argc = argc - fmri_args;
10750Sstevel@tonic-gate 		args.argv = argv + fmri_args;
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate 		serr = scf_walk_fmri(h, fmri_args, argv, 0,
10780Sstevel@tonic-gate 		    modify_inst_props_cb, &args, &exit_status, uu_warn);
10790Sstevel@tonic-gate 	} else if (Mflag) {
10800Sstevel@tonic-gate 		modify_defaults(argc, argv);
10810Sstevel@tonic-gate 	} else if (pflag) {
10820Sstevel@tonic-gate 		/* ensure there's no trailing garbage */
10830Sstevel@tonic-gate 		if (argc != 0)
10840Sstevel@tonic-gate 			usage(B_FALSE);
10850Sstevel@tonic-gate 		list_defaults();
10860Sstevel@tonic-gate 	}
10870Sstevel@tonic-gate 	if (serr != 0) {
10880Sstevel@tonic-gate 		uu_warn(gettext("failed to iterate over instances: %s"),
10890Sstevel@tonic-gate 		    scf_strerror(serr));
10900Sstevel@tonic-gate 		exit(UU_EXIT_FATAL);
10910Sstevel@tonic-gate 	}
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate out:
10940Sstevel@tonic-gate 	(void) scf_handle_unbind(h);
10950Sstevel@tonic-gate 	scf_handle_destroy(h);
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	return (exit_status);
10980Sstevel@tonic-gate }
1099