xref: /titanic_51/usr/src/cmd/cmd-inet/usr.sbin/inetconv/inetconv.c (revision 9444c26f4faabda140242c3986089704c4073ced)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54421e676Stn143363  * Common Development and Distribution License (the "License").
64421e676Stn143363  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*9444c26fSTom Whitten  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * inetconv - convert inetd.conf entries into smf(5) service manifests,
287c478bd9Sstevel@tonic-gate  *            import them into smf(5) repository
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #include <sys/param.h>
337c478bd9Sstevel@tonic-gate #include <sys/stat.h>
347c478bd9Sstevel@tonic-gate #include <sys/wait.h>
357c478bd9Sstevel@tonic-gate #include <stdio.h>
367c478bd9Sstevel@tonic-gate #include <stdlib.h>
377c478bd9Sstevel@tonic-gate #include <string.h>
387c478bd9Sstevel@tonic-gate #include <unistd.h>
397c478bd9Sstevel@tonic-gate #include <fcntl.h>
407c478bd9Sstevel@tonic-gate #include <pwd.h>
417c478bd9Sstevel@tonic-gate #include <grp.h>
427c478bd9Sstevel@tonic-gate #include <errno.h>
437c478bd9Sstevel@tonic-gate #include <limits.h>
447c478bd9Sstevel@tonic-gate #include <locale.h>
457c478bd9Sstevel@tonic-gate #include <libintl.h>
467c478bd9Sstevel@tonic-gate #include <libscf.h>
477c478bd9Sstevel@tonic-gate #include <inetsvc.h>
487c478bd9Sstevel@tonic-gate #include <rpc/nettype.h>
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /* exit codes */
517c478bd9Sstevel@tonic-gate #define	EXIT_SUCCESS	0	/* succeeded */
527c478bd9Sstevel@tonic-gate #define	EXIT_USAGE	1	/* bad options */
537c478bd9Sstevel@tonic-gate #define	EXIT_ERROR_CONV 2	/* error(s) coverting inetd.conf entries */
547c478bd9Sstevel@tonic-gate #define	EXIT_ERROR_IMP	3	/* error(s) importing manifests */
557c478bd9Sstevel@tonic-gate #define	EXIT_ERROR_SYS	4	/* system error */
567c478bd9Sstevel@tonic-gate #define	EXIT_ERROR_ENBL 5	/* error(s) enabling services */
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #ifndef TEXT_DOMAIN
597c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN		"SUNW_OST_OSCMD"
607c478bd9Sstevel@tonic-gate #endif
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate #define	MAIN_CONFIG		"/etc/inet/inetd.conf"
637c478bd9Sstevel@tonic-gate #define	ALT_CONFIG		"/etc/inetd.conf"
647c478bd9Sstevel@tonic-gate 
65*9444c26fSTom Whitten #define	MANIFEST_DIR		"/lib/svc/manifest/network"
66cdc89861Sdstaff #define	MANIFEST_RPC_DIR	MANIFEST_DIR  "/rpc"
677c478bd9Sstevel@tonic-gate #define	SVCCFG_PATH		"/usr/sbin/svccfg"
687c478bd9Sstevel@tonic-gate 
69cdc89861Sdstaff #define	RPCBIND_FMRI		"svc:/network/rpc/bind"
70cdc89861Sdstaff 
717c478bd9Sstevel@tonic-gate /* maximum allowed length of an inetd.conf format line */
727c478bd9Sstevel@tonic-gate #define	MAX_SRC_LINELEN		32768
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /* Version of inetconv, used as a marker in services we generate */
757c478bd9Sstevel@tonic-gate #define	INETCONV_VERSION	1
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate struct inetconfent {
787c478bd9Sstevel@tonic-gate 	/* fields as read from inetd.conf format line */
797c478bd9Sstevel@tonic-gate 	char *service;
807c478bd9Sstevel@tonic-gate 	char *endpoint;
817c478bd9Sstevel@tonic-gate 	char *protocol;
827c478bd9Sstevel@tonic-gate 	char *wait_status;
837c478bd9Sstevel@tonic-gate 	char *username;
847c478bd9Sstevel@tonic-gate 	char *server_program;
857c478bd9Sstevel@tonic-gate 	char *server_args;
867c478bd9Sstevel@tonic-gate 	/* information derived from above fields */
877c478bd9Sstevel@tonic-gate 	boolean_t wait;
887c478bd9Sstevel@tonic-gate 	boolean_t isrpc;
897c478bd9Sstevel@tonic-gate 	int rpc_low_version;
907c478bd9Sstevel@tonic-gate 	int rpc_high_version;
917c478bd9Sstevel@tonic-gate 	char *rpc_prog;
927c478bd9Sstevel@tonic-gate 	char *groupname;
937c478bd9Sstevel@tonic-gate 	char *exec;
947c478bd9Sstevel@tonic-gate 	char *arg0;
957c478bd9Sstevel@tonic-gate };
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate struct fileinfo {
987c478bd9Sstevel@tonic-gate 	FILE *fp;
997c478bd9Sstevel@tonic-gate 	char *filename;
1007c478bd9Sstevel@tonic-gate 	int lineno;
1017c478bd9Sstevel@tonic-gate 	int failcnt;
1027c478bd9Sstevel@tonic-gate };
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate static char *progname;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate static boolean_t import = B_TRUE;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate /* start of manifest XML template strings */
1097c478bd9Sstevel@tonic-gate static const char xml_header[] =
1107c478bd9Sstevel@tonic-gate "<?xml version='1.0'?>\n"
1117c478bd9Sstevel@tonic-gate "<!DOCTYPE service_bundle SYSTEM "
1127c478bd9Sstevel@tonic-gate "'/usr/share/lib/xml/dtd/service_bundle.dtd.1'>\n";
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate static const char xml_comment[] =
1157c478bd9Sstevel@tonic-gate "<!--\n"
1167c478bd9Sstevel@tonic-gate "    Service manifest for the %s service.\n"
1177c478bd9Sstevel@tonic-gate "\n"
1187c478bd9Sstevel@tonic-gate "    Generated by inetconv(1M) from inetd.conf(4).\n"
1197c478bd9Sstevel@tonic-gate "-->\n\n";
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate static const char xml_service_bundle[] =
1227c478bd9Sstevel@tonic-gate "<service_bundle type='manifest' name='inetconv:%s'>\n\n";
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate static const char xml_service_name[] =
1257c478bd9Sstevel@tonic-gate "<service\n"
1267c478bd9Sstevel@tonic-gate "	name='network/%s'\n"
1277c478bd9Sstevel@tonic-gate "	type='service'\n"
1287c478bd9Sstevel@tonic-gate "	version='1'>\n\n";
1297c478bd9Sstevel@tonic-gate 
130cdc89861Sdstaff static const char xml_dependency[] =
131cdc89861Sdstaff "	<dependency\n"
132cdc89861Sdstaff "		name='%s'\n"
133cdc89861Sdstaff "		grouping='require_all'\n"
134cdc89861Sdstaff "		restart_on='restart'\n"
135cdc89861Sdstaff "		type='service'>\n"
136cdc89861Sdstaff "		<service_fmri value='%s' />\n"
137cdc89861Sdstaff "	</dependency>\n\n";
138cdc89861Sdstaff 
1397c478bd9Sstevel@tonic-gate static const char xml_instance[] =
1407c478bd9Sstevel@tonic-gate "	<create_default_instance enabled='true'/>\n\n";
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate static const char xml_restarter[] =
1437c478bd9Sstevel@tonic-gate "	<restarter>\n"
1447c478bd9Sstevel@tonic-gate "		<service_fmri value='%s' />\n"
1457c478bd9Sstevel@tonic-gate "	</restarter>\n\n";
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate static const char xml_exec_method_start[] =
1487c478bd9Sstevel@tonic-gate "	<!--\n"
1497c478bd9Sstevel@tonic-gate "	    Set a timeout of 0 to signify to inetd that we don't want to\n"
1507c478bd9Sstevel@tonic-gate "	    timeout this service, since the forked process is the one that\n"
1517c478bd9Sstevel@tonic-gate "	    does the service's work. This is the case for most/all legacy\n"
1527c478bd9Sstevel@tonic-gate "	    inetd services; for services written to take advantage of SMF\n"
1537c478bd9Sstevel@tonic-gate "	    capabilities, the start method should fork off a process to\n"
1547c478bd9Sstevel@tonic-gate "	    handle the request and return a success code.\n"
1557c478bd9Sstevel@tonic-gate "	-->\n"
1567c478bd9Sstevel@tonic-gate "	<exec_method\n"
1577c478bd9Sstevel@tonic-gate "		type='method'\n"
1587c478bd9Sstevel@tonic-gate "		name='%s'\n"
1597c478bd9Sstevel@tonic-gate "		%s='%s'\n"
1607c478bd9Sstevel@tonic-gate "		timeout_seconds='0'>\n"
1617c478bd9Sstevel@tonic-gate "		<method_context>\n"
1627c478bd9Sstevel@tonic-gate "			<method_credential %s='%s' group='%s' />\n"
1637c478bd9Sstevel@tonic-gate "		</method_context>\n";
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate static const char xml_arg0[] =
1667c478bd9Sstevel@tonic-gate "		<propval name='%s' type='astring'\n"
1677c478bd9Sstevel@tonic-gate "		    value='%s' />\n";
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate static const char xml_exec_method_end[] =
1707c478bd9Sstevel@tonic-gate "	</exec_method>\n\n";
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate static const char xml_exec_method_disable[] =
1737c478bd9Sstevel@tonic-gate "	<!--\n"
1747c478bd9Sstevel@tonic-gate "	    Use inetd's built-in kill support to disable services.\n"
1757c478bd9Sstevel@tonic-gate "	-->\n"
1767c478bd9Sstevel@tonic-gate "	<exec_method\n"
1777c478bd9Sstevel@tonic-gate "		type='method'\n"
1787c478bd9Sstevel@tonic-gate "		name='%s'\n"
1797c478bd9Sstevel@tonic-gate "		%s=':kill'\n"
1807c478bd9Sstevel@tonic-gate "		timeout_seconds='0'>\n";
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate static const char xml_exec_method_offline[] =
1837c478bd9Sstevel@tonic-gate "	<!--\n"
1847c478bd9Sstevel@tonic-gate "	    Use inetd's built-in process kill support to offline wait type\n"
1857c478bd9Sstevel@tonic-gate "	    services.\n"
1867c478bd9Sstevel@tonic-gate "	-->\n"
1877c478bd9Sstevel@tonic-gate "	<exec_method\n"
1887c478bd9Sstevel@tonic-gate "		type='method'\n"
1897c478bd9Sstevel@tonic-gate "		name='%s'\n"
1907c478bd9Sstevel@tonic-gate "		%s=':kill_process'\n"
1917c478bd9Sstevel@tonic-gate "		timeout_seconds='0'>\n";
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate static const char xml_inetconv_group_start[] =
1947c478bd9Sstevel@tonic-gate "	<!--\n"
1957c478bd9Sstevel@tonic-gate "	    This property group is used to record information about\n"
1967c478bd9Sstevel@tonic-gate "	    how this manifest was created.  It is an implementation\n"
1977c478bd9Sstevel@tonic-gate "	    detail which should not be modified or deleted.\n"
1987c478bd9Sstevel@tonic-gate "	-->\n"
1997c478bd9Sstevel@tonic-gate "	<property_group name='%s' type='framework'>\n"
2007c478bd9Sstevel@tonic-gate "		<propval name='%s' type='boolean' value='%s' />\n"
2017c478bd9Sstevel@tonic-gate "		<propval name='%s' type='integer' value='%d' />\n"
2027c478bd9Sstevel@tonic-gate "		<propval name='%s' type='astring' value=\n"
2037c478bd9Sstevel@tonic-gate "'%s %s %s %s %s %s%s%s'\n"
2047c478bd9Sstevel@tonic-gate "		/>\n";
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate static const char xml_property_group_start[] =
2077c478bd9Sstevel@tonic-gate "	<property_group name='%s' type='framework'>\n"
2087c478bd9Sstevel@tonic-gate "		<propval name='%s' type='astring' value='%s' />\n"
2097c478bd9Sstevel@tonic-gate "		<propval name='%s' type='astring' value='%s' />\n"
2107c478bd9Sstevel@tonic-gate "		<propval name='%s' type='astring' value='%s' />\n"
2117c478bd9Sstevel@tonic-gate "		<propval name='%s' type='boolean' value='%s' />\n"
2127c478bd9Sstevel@tonic-gate "		<propval name='%s' type='boolean' value='%s' />\n";
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate static const char xml_property_group_rpc[] =
2157c478bd9Sstevel@tonic-gate "		<propval name='%s' type='integer' value='%d' />\n"
2167c478bd9Sstevel@tonic-gate "		<propval name='%s' type='integer' value='%d' />"
2177c478bd9Sstevel@tonic-gate "\n";
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate static const char xml_property_group_end[] =
2207c478bd9Sstevel@tonic-gate "	</property_group>\n\n";
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate static const char xml_stability[] =
2237c478bd9Sstevel@tonic-gate "	<stability value='External' />\n\n";
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate static const char xml_template[] =
2267c478bd9Sstevel@tonic-gate "	<template>\n"
2277c478bd9Sstevel@tonic-gate "		<common_name>\n"
2287c478bd9Sstevel@tonic-gate "			<loctext xml:lang='C'>\n"
2297c478bd9Sstevel@tonic-gate "%s\n"
2307c478bd9Sstevel@tonic-gate "			</loctext>\n"
2317c478bd9Sstevel@tonic-gate "		</common_name>\n"
2327c478bd9Sstevel@tonic-gate "	</template>\n";
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate static const char xml_footer[] =
2357c478bd9Sstevel@tonic-gate "</service>\n"
2367c478bd9Sstevel@tonic-gate "\n"
2377c478bd9Sstevel@tonic-gate "</service_bundle>\n";
2387c478bd9Sstevel@tonic-gate /* end of manifest XML template strings */
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate static void *
2417c478bd9Sstevel@tonic-gate safe_malloc(size_t size)
2427c478bd9Sstevel@tonic-gate {
2437c478bd9Sstevel@tonic-gate 	void *cp;
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	if ((cp = malloc(size)) == NULL) {
2467c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: malloc failed: %s\n"),
2477c478bd9Sstevel@tonic-gate 		    progname, strerror(errno));
2487c478bd9Sstevel@tonic-gate 		exit(EXIT_ERROR_SYS);
2497c478bd9Sstevel@tonic-gate 	}
2507c478bd9Sstevel@tonic-gate 	return (cp);
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate static char *
2547c478bd9Sstevel@tonic-gate safe_strdup(char *s)
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate 	char *cp;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	if ((cp = strdup(s)) == NULL) {
2597c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: strdup failed: %s\n"),
2607c478bd9Sstevel@tonic-gate 		    progname, strerror(errno));
2617c478bd9Sstevel@tonic-gate 		exit(EXIT_ERROR_SYS);
2627c478bd9Sstevel@tonic-gate 	}
2637c478bd9Sstevel@tonic-gate 	return (cp);
2647c478bd9Sstevel@tonic-gate }
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate static char *
2677c478bd9Sstevel@tonic-gate propertyname(char *name, char *prefix)
2687c478bd9Sstevel@tonic-gate {
2697c478bd9Sstevel@tonic-gate 	static char *buf;
2707c478bd9Sstevel@tonic-gate 	size_t len;
2717c478bd9Sstevel@tonic-gate 	int c;
2727c478bd9Sstevel@tonic-gate 	char *cp;
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	/* free any memory allocated by a previous call */
2757c478bd9Sstevel@tonic-gate 	free(buf);
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	len = strlen(name) + strlen(prefix) + 1;
2787c478bd9Sstevel@tonic-gate 	buf = safe_malloc(len);
2797c478bd9Sstevel@tonic-gate 	buf[0] = '\0';
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	/*
2827c478bd9Sstevel@tonic-gate 	 * Property names must match the regular expression:
2837c478bd9Sstevel@tonic-gate 	 * ([A-Za-z][_A-Za-z0-9.-]*,)?[A-Za-z][_A-Za-z0-9-]*
2847c478bd9Sstevel@tonic-gate 	 */
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	/*
2877c478bd9Sstevel@tonic-gate 	 * Make sure the first character is alphabetic, if not insert prefix.
2884421e676Stn143363 	 * Can't use isalpha() here as it's locale dependent but the property
2897c478bd9Sstevel@tonic-gate 	 * name regular expression isn't.
2907c478bd9Sstevel@tonic-gate 	 */
2917c478bd9Sstevel@tonic-gate 	c = name[0];
2927c478bd9Sstevel@tonic-gate 	if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z')) {
2937c478bd9Sstevel@tonic-gate 		(void) strlcat(buf, prefix, len);
2947c478bd9Sstevel@tonic-gate 	}
2957c478bd9Sstevel@tonic-gate 	(void) strlcat(buf, name, len);
2967c478bd9Sstevel@tonic-gate 
2974421e676Stn143363 	/* convert any disallowed characters into '_' */
2987c478bd9Sstevel@tonic-gate 	for (cp = buf; *cp != '\0'; cp++) {
2997c478bd9Sstevel@tonic-gate 		if ((*cp < 'A' || *cp > 'Z') && (*cp < 'a' || *cp > 'z') &&
3007c478bd9Sstevel@tonic-gate 		    (*cp < '0' || *cp > '9') && (*cp != '.') && (*cp != '-'))
3017c478bd9Sstevel@tonic-gate 			*cp = '_';
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate 	return (buf);
3047c478bd9Sstevel@tonic-gate }
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate static char *
3077c478bd9Sstevel@tonic-gate servicename(struct inetconfent *iconf)
3087c478bd9Sstevel@tonic-gate {
3097c478bd9Sstevel@tonic-gate 	static char *buf;
3107c478bd9Sstevel@tonic-gate 	size_t len;
3114421e676Stn143363 	char *cp, *proto;
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	/* free any memory allocated by a previous call */
3147c478bd9Sstevel@tonic-gate 	free(buf);
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	len = strlen(iconf->service) + strlen(iconf->protocol) +
3177c478bd9Sstevel@tonic-gate 	    sizeof ("rpc-/visible");
3187c478bd9Sstevel@tonic-gate 	buf = safe_malloc(len);
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	/*
3217c478bd9Sstevel@tonic-gate 	 * Combine the service and protocol fields to produce a unique
3227c478bd9Sstevel@tonic-gate 	 * manifest service name. The syntax of a service name is:
3237c478bd9Sstevel@tonic-gate 	 * prop(/prop)*
3247c478bd9Sstevel@tonic-gate 	 */
3257c478bd9Sstevel@tonic-gate 	(void) strlcpy(buf, propertyname(iconf->service,
3267c478bd9Sstevel@tonic-gate 	    iconf->isrpc ? "rpc-": "s-"), len);
3277c478bd9Sstevel@tonic-gate 	(void) strlcat(buf, "/", len);
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	proto = iconf->protocol;
3307c478bd9Sstevel@tonic-gate 	if (iconf->isrpc && (strcmp(iconf->protocol, "rpc/*") == 0))
3317c478bd9Sstevel@tonic-gate 		proto = "rpc/visible";
3324421e676Stn143363 
3334421e676Stn143363 	/*
3344421e676Stn143363 	 * SMF service names may not contain '.', but IANA services do
3354421e676Stn143363 	 * allow its use, and property names can contain '.' as returned
3364421e676Stn143363 	 * by propertyname().  So if the resultant SMF service name
3374421e676Stn143363 	 * would contain a '.' we fix it here.
3384421e676Stn143363 	 */
3394421e676Stn143363 	for (cp = buf; *cp != '\0'; cp++) {
3404421e676Stn143363 		if (*cp == '.')
3414421e676Stn143363 			*cp = '_';
3424421e676Stn143363 	}
3437c478bd9Sstevel@tonic-gate 	(void) strlcat(buf, propertyname(proto, "p-"), len);
3447c478bd9Sstevel@tonic-gate 	return (buf);
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate static boolean_t
3487c478bd9Sstevel@tonic-gate is_v6only(char *protocol)
3497c478bd9Sstevel@tonic-gate {
3507c478bd9Sstevel@tonic-gate 	/* returns true if protocol is an IPv6 only protocol */
3517c478bd9Sstevel@tonic-gate 	if ((strcmp(protocol, SOCKET_PROTO_TCP6_ONLY) == 0) ||
3527c478bd9Sstevel@tonic-gate 	    (strcmp(protocol, SOCKET_PROTO_UDP6_ONLY) == 0))
3537c478bd9Sstevel@tonic-gate 		return (B_TRUE);
3547c478bd9Sstevel@tonic-gate 	return (B_FALSE);
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate static char *
3587c478bd9Sstevel@tonic-gate invalid_props(inetd_prop_t *p)
3597c478bd9Sstevel@tonic-gate {
3607c478bd9Sstevel@tonic-gate 	static char
3617c478bd9Sstevel@tonic-gate 	    buf[sizeof (" service-name endpoint-type protocol wait-status")];
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	buf[0] = '\0';
3647c478bd9Sstevel@tonic-gate 	if ((p[PT_SVC_NAME_INDEX].ip_error == IVE_INVALID) ||
3657c478bd9Sstevel@tonic-gate 	    (p[PT_SVC_NAME_INDEX].ip_error == IVE_UNSET) ||
3667c478bd9Sstevel@tonic-gate 	    (p[PT_RPC_LW_VER_INDEX].ip_error == IVE_INVALID) ||
3677c478bd9Sstevel@tonic-gate 	    (p[PT_RPC_HI_VER_INDEX].ip_error == IVE_INVALID))
3687c478bd9Sstevel@tonic-gate 		(void) strlcat(buf, " service-name", sizeof (buf));
3697c478bd9Sstevel@tonic-gate 	if ((p[PT_SOCK_TYPE_INDEX].ip_error == IVE_INVALID) ||
3707c478bd9Sstevel@tonic-gate 	    (p[PT_SOCK_TYPE_INDEX].ip_error == IVE_UNSET))
3717c478bd9Sstevel@tonic-gate 		(void) strlcat(buf, " endpoint-type", sizeof (buf));
3727c478bd9Sstevel@tonic-gate 	if ((p[PT_PROTO_INDEX].ip_error == IVE_INVALID) ||
3737c478bd9Sstevel@tonic-gate 	    (p[PT_PROTO_INDEX].ip_error == IVE_UNSET) ||
3747c478bd9Sstevel@tonic-gate 	    (p[PT_ISRPC_INDEX].ip_error == IVE_INVALID))
3757c478bd9Sstevel@tonic-gate 		(void) strlcat(buf, " protocol", sizeof (buf));
3767c478bd9Sstevel@tonic-gate 	if (p[PT_ISWAIT_INDEX].ip_error == IVE_INVALID)
3777c478bd9Sstevel@tonic-gate 		(void) strlcat(buf, " wait-status", sizeof (buf));
3787c478bd9Sstevel@tonic-gate 	return (buf);
3797c478bd9Sstevel@tonic-gate }
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate static boolean_t
3827c478bd9Sstevel@tonic-gate valid_basic_properties(struct inetconfent *iconf, struct fileinfo *finfo)
3837c478bd9Sstevel@tonic-gate {
3847c478bd9Sstevel@tonic-gate 	size_t prop_size;
3857c478bd9Sstevel@tonic-gate 	inetd_prop_t *prop, *inetd_properties;
3867c478bd9Sstevel@tonic-gate 	boolean_t valid = B_TRUE;
3877c478bd9Sstevel@tonic-gate 	char *proto = iconf->protocol;
3887c478bd9Sstevel@tonic-gate 	char *svc_name = iconf->service;
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	inetd_properties = get_prop_table(&prop_size);
3917c478bd9Sstevel@tonic-gate 	prop = safe_malloc(prop_size * sizeof (inetd_prop_t));
3927c478bd9Sstevel@tonic-gate 	(void) memcpy(prop, inetd_properties,
3937c478bd9Sstevel@tonic-gate 	    prop_size * sizeof (inetd_prop_t));
3947c478bd9Sstevel@tonic-gate 
395ba1637f8Smh138676 	put_prop_value_boolean(prop, PR_ISRPC_NAME, iconf->isrpc);
396ba1637f8Smh138676 	put_prop_value_boolean(prop, PR_ISWAIT_NAME, iconf->wait);
3977c478bd9Sstevel@tonic-gate 	if (iconf->isrpc) {
398ba1637f8Smh138676 		put_prop_value_int(prop, PR_RPC_LW_VER_NAME,
399ba1637f8Smh138676 		    iconf->rpc_low_version);
400ba1637f8Smh138676 		put_prop_value_int(prop, PR_RPC_HI_VER_NAME,
401ba1637f8Smh138676 		    iconf->rpc_high_version);
4027c478bd9Sstevel@tonic-gate 		svc_name = iconf->rpc_prog;
4037c478bd9Sstevel@tonic-gate 		proto += 4;	/* skip 'rpc/' */
4047c478bd9Sstevel@tonic-gate 	}
4057c478bd9Sstevel@tonic-gate 
406ba1637f8Smh138676 	if (!put_prop_value_string(prop, PR_SOCK_TYPE_NAME, iconf->endpoint) ||
407ba1637f8Smh138676 	    !put_prop_value_string(prop, PR_SVC_NAME_NAME, svc_name)) {
4087c478bd9Sstevel@tonic-gate 		valid = B_FALSE;
4097c478bd9Sstevel@tonic-gate 
410ba1637f8Smh138676 		if (errno == ENOMEM) {
411ba1637f8Smh138676 			(void) fprintf(stderr,
412ba1637f8Smh138676 			    gettext("%s: failed to allocate memory: %s\n"),
413ba1637f8Smh138676 			    progname, strerror(errno));
414ba1637f8Smh138676 			exit(EXIT_ERROR_SYS);
415ba1637f8Smh138676 		}
416ba1637f8Smh138676 	}
417ba1637f8Smh138676 
418ba1637f8Smh138676 	put_prop_value_string_list(prop, PR_PROTO_NAME, get_protos(proto));
419ba1637f8Smh138676 
4207c478bd9Sstevel@tonic-gate 	if (!valid_props(prop, NULL, NULL, NULL, NULL) || !valid) {
4217c478bd9Sstevel@tonic-gate 		valid = B_FALSE;
4227c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: Error %s line %d "
4237c478bd9Sstevel@tonic-gate 		    "invalid or inconsistent fields:%s\n"), progname,
4247c478bd9Sstevel@tonic-gate 		    finfo->filename, finfo->lineno,
4257c478bd9Sstevel@tonic-gate 		    invalid_props(prop));
4267c478bd9Sstevel@tonic-gate 	}
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	free_instance_props(prop);
4297c478bd9Sstevel@tonic-gate 	return (valid);
4307c478bd9Sstevel@tonic-gate }
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate static boolean_t
4337c478bd9Sstevel@tonic-gate valid_inetconfent(struct inetconfent *iconf, struct fileinfo *finfo)
4347c478bd9Sstevel@tonic-gate {
4357c478bd9Sstevel@tonic-gate 	boolean_t valid = B_TRUE;
4367c478bd9Sstevel@tonic-gate 	size_t len;
4377c478bd9Sstevel@tonic-gate 	char *cp, *endp;
4387c478bd9Sstevel@tonic-gate 	struct passwd *pwd;
4397c478bd9Sstevel@tonic-gate 	struct group *grp;
4407c478bd9Sstevel@tonic-gate 	struct stat statb;
4417c478bd9Sstevel@tonic-gate 	char *proto = iconf->protocol;
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	iconf->isrpc = B_FALSE;
4447c478bd9Sstevel@tonic-gate 	if (strncmp(iconf->protocol, "rpc/", 4) == 0) {
4457c478bd9Sstevel@tonic-gate 		iconf->isrpc = B_TRUE;
4467c478bd9Sstevel@tonic-gate 		iconf->rpc_prog = safe_strdup(iconf->service);
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 		/* set RPC version numbers */
4497c478bd9Sstevel@tonic-gate 		iconf->rpc_low_version = 1;
4507c478bd9Sstevel@tonic-gate 		iconf->rpc_high_version = 1;
4517c478bd9Sstevel@tonic-gate 		if ((cp = strrchr(iconf->rpc_prog, '/')) != NULL) {
4527c478bd9Sstevel@tonic-gate 			*cp = '\0';
4537c478bd9Sstevel@tonic-gate 			if (*++cp != '\0') {
4547c478bd9Sstevel@tonic-gate 				errno = 0;
4557c478bd9Sstevel@tonic-gate 				iconf->rpc_low_version = strtol(cp, &endp, 10);
4567c478bd9Sstevel@tonic-gate 				if (errno != 0)
4577c478bd9Sstevel@tonic-gate 					goto vererr;
4587c478bd9Sstevel@tonic-gate 				cp = endp;
4597c478bd9Sstevel@tonic-gate 				if (*cp == '-') {
4607c478bd9Sstevel@tonic-gate 					if (*++cp == '\0')
4617c478bd9Sstevel@tonic-gate 						goto vererr;
4627c478bd9Sstevel@tonic-gate 					errno = 0;
4637c478bd9Sstevel@tonic-gate 					iconf->rpc_high_version = strtol(cp,
4647c478bd9Sstevel@tonic-gate 					    &endp, 10);
4657c478bd9Sstevel@tonic-gate 					if ((errno != 0) || (*endp != '\0'))
4667c478bd9Sstevel@tonic-gate 						goto vererr;
4677c478bd9Sstevel@tonic-gate 				} else if (*cp == '\0') {
4687c478bd9Sstevel@tonic-gate 					iconf->rpc_high_version =
4697c478bd9Sstevel@tonic-gate 					    iconf->rpc_low_version;
4707c478bd9Sstevel@tonic-gate 				} else {
4717c478bd9Sstevel@tonic-gate vererr:
4727c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
4737c478bd9Sstevel@tonic-gate 					    "%s: Error %s line %d invalid RPC "
4747c478bd9Sstevel@tonic-gate 					    "version in service: %s\n"),
4757c478bd9Sstevel@tonic-gate 					    progname, finfo->filename,
4767c478bd9Sstevel@tonic-gate 					    finfo->lineno, iconf->service);
4777c478bd9Sstevel@tonic-gate 					valid = B_FALSE;
4787c478bd9Sstevel@tonic-gate 				}
4797c478bd9Sstevel@tonic-gate 			}
4807c478bd9Sstevel@tonic-gate 		}
4817c478bd9Sstevel@tonic-gate 		proto += 4;	/* skip 'rpc/' */
4827c478bd9Sstevel@tonic-gate 	}
4837c478bd9Sstevel@tonic-gate 	/* tcp6only and udp6only are not valid in inetd.conf */
4847c478bd9Sstevel@tonic-gate 	if (is_v6only(proto)) {
4857c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: Error %s line %d "
4867c478bd9Sstevel@tonic-gate 		    "invalid protocol: %s\n"), progname,
4877c478bd9Sstevel@tonic-gate 		    finfo->filename, finfo->lineno, proto);
4887c478bd9Sstevel@tonic-gate 		valid = B_FALSE;
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	if (strcmp(iconf->wait_status, "wait") == 0) {
4927c478bd9Sstevel@tonic-gate 		iconf->wait = B_TRUE;
4937c478bd9Sstevel@tonic-gate 	} else if (strcmp(iconf->wait_status, "nowait") == 0) {
4947c478bd9Sstevel@tonic-gate 		iconf->wait = B_FALSE;
4957c478bd9Sstevel@tonic-gate 	} else {
4967c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
4977c478bd9Sstevel@tonic-gate 		    gettext("%s: Error %s line %d invalid wait-status: %s\n"),
4987c478bd9Sstevel@tonic-gate 		    progname, finfo->filename, finfo->lineno,
4997c478bd9Sstevel@tonic-gate 		    iconf->wait_status);
5007c478bd9Sstevel@tonic-gate 		valid = B_FALSE;
5017c478bd9Sstevel@tonic-gate 	}
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	/* look up the username to set the groupname */
5047c478bd9Sstevel@tonic-gate 	if ((pwd = getpwnam(iconf->username)) == NULL) {
5057c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
5067c478bd9Sstevel@tonic-gate 		    gettext("%s: Error %s line %d unknown user: %s\n"),
5077c478bd9Sstevel@tonic-gate 		    progname, finfo->filename, finfo->lineno,
5087c478bd9Sstevel@tonic-gate 		    iconf->username);
5097c478bd9Sstevel@tonic-gate 		valid = B_FALSE;
5107c478bd9Sstevel@tonic-gate 	} else {
5117c478bd9Sstevel@tonic-gate 		if ((grp = getgrgid(pwd->pw_gid)) != NULL) {
5127c478bd9Sstevel@tonic-gate 			iconf->groupname = safe_strdup(grp->gr_name);
5137c478bd9Sstevel@tonic-gate 		} else {
5147c478bd9Sstevel@tonic-gate 			/* use the group ID if no groupname */
5157c478bd9Sstevel@tonic-gate 			char s[1];
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 			len = snprintf(s, 1, "%d", pwd->pw_gid) + 1;
5187c478bd9Sstevel@tonic-gate 			iconf->groupname = safe_malloc(len);
5197c478bd9Sstevel@tonic-gate 			(void) snprintf(iconf->groupname, len, "%d",
5207c478bd9Sstevel@tonic-gate 			    pwd->pw_gid);
5217c478bd9Sstevel@tonic-gate 		}
5227c478bd9Sstevel@tonic-gate 	}
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	/* check for internal services */
5257c478bd9Sstevel@tonic-gate 	if (strcmp(iconf->server_program, "internal") == 0) {
5267c478bd9Sstevel@tonic-gate 		valid = B_FALSE;
5277c478bd9Sstevel@tonic-gate 		if ((strcmp(iconf->service, "echo") == 0) ||
5287c478bd9Sstevel@tonic-gate 		    (strcmp(iconf->service, "discard") == 0) ||
5297c478bd9Sstevel@tonic-gate 		    (strcmp(iconf->service, "time") == 0) ||
5307c478bd9Sstevel@tonic-gate 		    (strcmp(iconf->service, "daytime") == 0) ||
5317c478bd9Sstevel@tonic-gate 		    (strcmp(iconf->service, "chargen") == 0)) {
5327c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
5337c478bd9Sstevel@tonic-gate 			    "%s: Error %s line %d the SUNWcnsr and SUNWcnsu"
5347c478bd9Sstevel@tonic-gate 			    " packages contain the internal services\n"),
5357c478bd9Sstevel@tonic-gate 			    progname, finfo->filename, finfo->lineno);
5367c478bd9Sstevel@tonic-gate 		} else {
5377c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s: Error %s line %d "
5387c478bd9Sstevel@tonic-gate 			    "unknown internal service: %s\n"), progname,
5397c478bd9Sstevel@tonic-gate 			    finfo->filename, finfo->lineno, iconf->service);
5407c478bd9Sstevel@tonic-gate 		}
5417c478bd9Sstevel@tonic-gate 	} else if ((stat(iconf->server_program, &statb) == -1) &&
5427c478bd9Sstevel@tonic-gate 	    (errno == ENOENT)) {
5437c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
5447c478bd9Sstevel@tonic-gate 		    "%s: Error %s line %d server-program not found: %s\n"),
5457c478bd9Sstevel@tonic-gate 		    progname, finfo->filename, finfo->lineno,
5467c478bd9Sstevel@tonic-gate 		    iconf->server_program);
5477c478bd9Sstevel@tonic-gate 		valid = B_FALSE;
5487c478bd9Sstevel@tonic-gate 	}
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	return (valid && valid_basic_properties(iconf, finfo));
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate static void
5547c478bd9Sstevel@tonic-gate free_inetconfent(struct inetconfent *iconf)
5557c478bd9Sstevel@tonic-gate {
5567c478bd9Sstevel@tonic-gate 	if (iconf == NULL)
5577c478bd9Sstevel@tonic-gate 		return;
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	free(iconf->service);
5607c478bd9Sstevel@tonic-gate 	free(iconf->endpoint);
5617c478bd9Sstevel@tonic-gate 	free(iconf->protocol);
5627c478bd9Sstevel@tonic-gate 	free(iconf->wait_status);
5637c478bd9Sstevel@tonic-gate 	free(iconf->username);
5647c478bd9Sstevel@tonic-gate 	free(iconf->server_program);
5657c478bd9Sstevel@tonic-gate 	free(iconf->server_args);
5667c478bd9Sstevel@tonic-gate 	free(iconf->rpc_prog);
5677c478bd9Sstevel@tonic-gate 	free(iconf->groupname);
5687c478bd9Sstevel@tonic-gate 	free(iconf->exec);
5697c478bd9Sstevel@tonic-gate 	free(iconf->arg0);
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	free(iconf);
5727c478bd9Sstevel@tonic-gate }
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate static struct inetconfent *
5757c478bd9Sstevel@tonic-gate line_to_inetconfent(char *line)
5767c478bd9Sstevel@tonic-gate {
5777c478bd9Sstevel@tonic-gate 	char *cp;
5787c478bd9Sstevel@tonic-gate 	struct inetconfent *iconf;
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	iconf = safe_malloc(sizeof (struct inetconfent));
5817c478bd9Sstevel@tonic-gate 	(void) memset(iconf, 0, sizeof (struct inetconfent));
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	if ((cp = strtok(line, " \t\n")) == NULL)
5847c478bd9Sstevel@tonic-gate 		goto fail;
5857c478bd9Sstevel@tonic-gate 	iconf->service = safe_strdup(cp);
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	if ((cp = strtok(NULL, " \t\n")) == NULL)
5887c478bd9Sstevel@tonic-gate 		goto fail;
5897c478bd9Sstevel@tonic-gate 	iconf->endpoint = safe_strdup(cp);
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	if ((cp = strtok(NULL, " \t\n")) == NULL)
5927c478bd9Sstevel@tonic-gate 		goto fail;
5937c478bd9Sstevel@tonic-gate 	iconf->protocol = safe_strdup(cp);
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	if ((cp = strtok(NULL, " \t\n")) == NULL)
5967c478bd9Sstevel@tonic-gate 		goto fail;
5977c478bd9Sstevel@tonic-gate 	iconf->wait_status = safe_strdup(cp);
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	if ((cp = strtok(NULL, " \t\n")) == NULL)
6007c478bd9Sstevel@tonic-gate 		goto fail;
6017c478bd9Sstevel@tonic-gate 	iconf->username = safe_strdup(cp);
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	if ((cp = strtok(NULL, " \t\n")) == NULL)
6047c478bd9Sstevel@tonic-gate 		goto fail;
6057c478bd9Sstevel@tonic-gate 	iconf->server_program = safe_strdup(cp);
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	/* last field is optional */
6087c478bd9Sstevel@tonic-gate 	if ((cp = strtok(NULL, "\n")) != NULL)
6097c478bd9Sstevel@tonic-gate 		iconf->server_args = safe_strdup(cp);
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	/* Combine args and server name to construct exec and args fields */
6127c478bd9Sstevel@tonic-gate 	if (iconf->server_args == NULL) {
6137c478bd9Sstevel@tonic-gate 		iconf->exec = safe_strdup(iconf->server_program);
6147c478bd9Sstevel@tonic-gate 	} else {
6157c478bd9Sstevel@tonic-gate 		int len;
6167c478bd9Sstevel@tonic-gate 		char *args, *endp;
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 		len = strlen(iconf->server_program) +
6197c478bd9Sstevel@tonic-gate 		    strlen(iconf->server_args) + 1;
6207c478bd9Sstevel@tonic-gate 		iconf->exec = safe_malloc(len);
6217c478bd9Sstevel@tonic-gate 		(void) strlcpy(iconf->exec, iconf->server_program, len);
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 		args = safe_strdup(iconf->server_args);
6247c478bd9Sstevel@tonic-gate 		if ((cp = strtok(args, " \t")) != NULL) {
6257c478bd9Sstevel@tonic-gate 			if ((endp = strrchr(iconf->exec, '/')) == NULL)
6267c478bd9Sstevel@tonic-gate 				endp = iconf->exec;
6277c478bd9Sstevel@tonic-gate 			else
6287c478bd9Sstevel@tonic-gate 				endp++;
6297c478bd9Sstevel@tonic-gate 			/* only set arg0 property value if needed */
6307c478bd9Sstevel@tonic-gate 			if (strcmp(endp, cp) != 0)
6317c478bd9Sstevel@tonic-gate 				iconf->arg0 = safe_strdup(cp);
6327c478bd9Sstevel@tonic-gate 			while ((cp = strtok(NULL, " \t")) != NULL) {
6337c478bd9Sstevel@tonic-gate 				(void) strlcat(iconf->exec, " ", len);
6347c478bd9Sstevel@tonic-gate 				(void) strlcat(iconf->exec, cp, len);
6357c478bd9Sstevel@tonic-gate 			}
6367c478bd9Sstevel@tonic-gate 		}
6377c478bd9Sstevel@tonic-gate 		free(args);
6387c478bd9Sstevel@tonic-gate 	}
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	return (iconf);
6417c478bd9Sstevel@tonic-gate fail:
6427c478bd9Sstevel@tonic-gate 	free_inetconfent(iconf);
6437c478bd9Sstevel@tonic-gate 	return (NULL);
6447c478bd9Sstevel@tonic-gate }
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate static void
6477c478bd9Sstevel@tonic-gate skipline(FILE *fp)
6487c478bd9Sstevel@tonic-gate {
6497c478bd9Sstevel@tonic-gate 	int c;
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	/* skip remainder of a line */
6527c478bd9Sstevel@tonic-gate 	while (((c = getc(fp)) != EOF) && (c != '\n'))
6537c478bd9Sstevel@tonic-gate 		;
6547c478bd9Sstevel@tonic-gate }
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate static struct inetconfent *
6577c478bd9Sstevel@tonic-gate fgetinetconfent(struct fileinfo *finfo, boolean_t validate)
6587c478bd9Sstevel@tonic-gate {
6597c478bd9Sstevel@tonic-gate 	char *cp;
6607c478bd9Sstevel@tonic-gate 	struct inetconfent *iconf;
6617c478bd9Sstevel@tonic-gate 	char line[MAX_SRC_LINELEN];
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	while (fgets(line, sizeof (line), finfo->fp) != NULL) {
6647c478bd9Sstevel@tonic-gate 		finfo->lineno++;
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 		/* skip empty or commented out lines */
6677c478bd9Sstevel@tonic-gate 		if (*line == '\n')
6687c478bd9Sstevel@tonic-gate 			continue;
6697c478bd9Sstevel@tonic-gate 		if (*line == '#') {
6707c478bd9Sstevel@tonic-gate 			if (line[strlen(line) - 1] != '\n')
6717c478bd9Sstevel@tonic-gate 				skipline(finfo->fp);
6727c478bd9Sstevel@tonic-gate 			continue;
6737c478bd9Sstevel@tonic-gate 		}
6747c478bd9Sstevel@tonic-gate 		/* check for lines which are too long */
6757c478bd9Sstevel@tonic-gate 		if (line[strlen(line) - 1] != '\n') {
6767c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
6777c478bd9Sstevel@tonic-gate 			    gettext("%s: Error %s line %d too long, skipped\n"),
6787c478bd9Sstevel@tonic-gate 			    progname, finfo->filename, finfo->lineno);
6797c478bd9Sstevel@tonic-gate 			skipline(finfo->fp);
6807c478bd9Sstevel@tonic-gate 			finfo->failcnt++;
6817c478bd9Sstevel@tonic-gate 			continue;
6827c478bd9Sstevel@tonic-gate 		}
6837c478bd9Sstevel@tonic-gate 		/* remove in line comments and newline character */
6847c478bd9Sstevel@tonic-gate 		if ((cp = strchr(line, '#')) == NULL)
6857c478bd9Sstevel@tonic-gate 			cp = strchr(line, '\n');
6867c478bd9Sstevel@tonic-gate 		if (cp)
6877c478bd9Sstevel@tonic-gate 			*cp = '\0';
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 		if ((iconf = line_to_inetconfent(line)) == NULL) {
6907c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
6917c478bd9Sstevel@tonic-gate 			    "%s: Error %s line %d too few fields, skipped\n"),
6927c478bd9Sstevel@tonic-gate 			    progname, finfo->filename, finfo->lineno);
6937c478bd9Sstevel@tonic-gate 			finfo->failcnt++;
6947c478bd9Sstevel@tonic-gate 			continue;
6957c478bd9Sstevel@tonic-gate 		}
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 		if (!validate || valid_inetconfent(iconf, finfo))
6987c478bd9Sstevel@tonic-gate 			return (iconf);
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 		finfo->failcnt++;
7017c478bd9Sstevel@tonic-gate 		free_inetconfent(iconf);
7027c478bd9Sstevel@tonic-gate 	}
7037c478bd9Sstevel@tonic-gate 	return (NULL);
7047c478bd9Sstevel@tonic-gate }
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate static char *
7077c478bd9Sstevel@tonic-gate boolstr(boolean_t val)
7087c478bd9Sstevel@tonic-gate {
7097c478bd9Sstevel@tonic-gate 	if (val)
7107c478bd9Sstevel@tonic-gate 		return ("true");
7117c478bd9Sstevel@tonic-gate 	return ("false");
7127c478bd9Sstevel@tonic-gate }
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate static int
7157c478bd9Sstevel@tonic-gate print_manifest(FILE *f, char *filename, struct inetconfent *iconf)
7167c478bd9Sstevel@tonic-gate {
7177c478bd9Sstevel@tonic-gate 	if (fprintf(f, xml_header) < 0)
7187c478bd9Sstevel@tonic-gate 		goto print_err;
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	if (fprintf(f, xml_comment,
7217c478bd9Sstevel@tonic-gate 	    iconf->isrpc ? iconf->rpc_prog : iconf->service) < 0)
7227c478bd9Sstevel@tonic-gate 		goto print_err;
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 	if (fprintf(f, xml_service_bundle, iconf->service) < 0)
7257c478bd9Sstevel@tonic-gate 		goto print_err;
7267c478bd9Sstevel@tonic-gate 	if (fprintf(f, xml_service_name, servicename(iconf)) < 0)
7277c478bd9Sstevel@tonic-gate 		goto print_err;
7287c478bd9Sstevel@tonic-gate 	if (fprintf(f, xml_instance) < 0)
7297c478bd9Sstevel@tonic-gate 		goto print_err;
7307c478bd9Sstevel@tonic-gate 	if (fprintf(f, xml_restarter, INETD_INSTANCE_FMRI) < 0)
7317c478bd9Sstevel@tonic-gate 		goto print_err;
732cdc89861Sdstaff 	if (iconf->isrpc) {
733cdc89861Sdstaff 		if (fprintf(f, xml_dependency, "rpcbind", RPCBIND_FMRI) < 0)
734cdc89861Sdstaff 			goto print_err;
735cdc89861Sdstaff 	}
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	if (fprintf(f, xml_exec_method_start, START_METHOD_NAME, PR_EXEC_NAME,
7387c478bd9Sstevel@tonic-gate 	    iconf->exec, PR_USER_NAME, iconf->username, iconf->groupname) < 0)
7397c478bd9Sstevel@tonic-gate 		goto print_err;
7407c478bd9Sstevel@tonic-gate 	if (iconf->arg0 != NULL) {
7417c478bd9Sstevel@tonic-gate 		if (fprintf(f, xml_arg0, PR_ARG0_NAME, iconf->arg0) < 0)
7427c478bd9Sstevel@tonic-gate 			goto print_err;
7437c478bd9Sstevel@tonic-gate 	}
7447c478bd9Sstevel@tonic-gate 	if (fprintf(f, xml_exec_method_end) < 0)
7457c478bd9Sstevel@tonic-gate 		goto print_err;
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	if (fprintf(f, xml_exec_method_disable, DISABLE_METHOD_NAME,
7487c478bd9Sstevel@tonic-gate 	    PR_EXEC_NAME) < 0)
7497c478bd9Sstevel@tonic-gate 		goto print_err;
7507c478bd9Sstevel@tonic-gate 	if (fprintf(f, xml_exec_method_end) < 0)
7517c478bd9Sstevel@tonic-gate 		goto print_err;
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 	if (iconf->wait) {
7547c478bd9Sstevel@tonic-gate 		if (fprintf(f, xml_exec_method_offline, OFFLINE_METHOD_NAME,
7557c478bd9Sstevel@tonic-gate 		    PR_EXEC_NAME) < 0)
7567c478bd9Sstevel@tonic-gate 			goto print_err;
7577c478bd9Sstevel@tonic-gate 		if (fprintf(f, xml_exec_method_end) < 0)
7587c478bd9Sstevel@tonic-gate 			goto print_err;
7597c478bd9Sstevel@tonic-gate 	}
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 	if (fprintf(f, xml_inetconv_group_start, PG_NAME_INETCONV,
7627c478bd9Sstevel@tonic-gate 	    PR_AUTO_CONVERTED_NAME, boolstr(B_TRUE),
7637c478bd9Sstevel@tonic-gate 	    PR_VERSION_NAME, INETCONV_VERSION,
7647c478bd9Sstevel@tonic-gate 	    PR_SOURCE_LINE_NAME, iconf->service,
7657c478bd9Sstevel@tonic-gate 	    iconf->endpoint, iconf->protocol, iconf->wait_status,
7667c478bd9Sstevel@tonic-gate 	    iconf->username, iconf->server_program,
7677c478bd9Sstevel@tonic-gate 	    iconf->server_args == NULL ? "" : " ",
7687c478bd9Sstevel@tonic-gate 	    iconf->server_args == NULL ? "" : iconf->server_args) < 0)
7697c478bd9Sstevel@tonic-gate 		goto print_err;
7707c478bd9Sstevel@tonic-gate 	if (fprintf(f, xml_property_group_end) < 0)
7717c478bd9Sstevel@tonic-gate 		goto print_err;
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	if (fprintf(f, xml_property_group_start, PG_NAME_SERVICE_CONFIG,
7747c478bd9Sstevel@tonic-gate 	    PR_SVC_NAME_NAME, iconf->isrpc ? iconf->rpc_prog : iconf->service,
7757c478bd9Sstevel@tonic-gate 	    PR_SOCK_TYPE_NAME, iconf->endpoint,
7767c478bd9Sstevel@tonic-gate 	    PR_PROTO_NAME, iconf->isrpc ? iconf->protocol + 4 :
7777c478bd9Sstevel@tonic-gate 	    iconf->protocol,
7787c478bd9Sstevel@tonic-gate 	    PR_ISWAIT_NAME, boolstr(iconf->wait),
7797c478bd9Sstevel@tonic-gate 	    PR_ISRPC_NAME, boolstr(iconf->isrpc)) < 0)
7807c478bd9Sstevel@tonic-gate 		goto print_err;
7817c478bd9Sstevel@tonic-gate 	if (iconf->isrpc) {
7827c478bd9Sstevel@tonic-gate 		if (fprintf(f, xml_property_group_rpc,
7837c478bd9Sstevel@tonic-gate 		    PR_RPC_LW_VER_NAME, iconf->rpc_low_version,
7847c478bd9Sstevel@tonic-gate 		    PR_RPC_HI_VER_NAME, iconf->rpc_high_version) < 0)
7857c478bd9Sstevel@tonic-gate 			goto print_err;
7867c478bd9Sstevel@tonic-gate 	}
7877c478bd9Sstevel@tonic-gate 	if (fprintf(f, xml_property_group_end) < 0)
7887c478bd9Sstevel@tonic-gate 		goto print_err;
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 	if (fprintf(f, xml_stability) < 0)
7917c478bd9Sstevel@tonic-gate 		goto print_err;
7927c478bd9Sstevel@tonic-gate 	if (fprintf(f, xml_template,
7937c478bd9Sstevel@tonic-gate 	    iconf->isrpc ? iconf->rpc_prog : iconf->service) < 0)
7947c478bd9Sstevel@tonic-gate 		goto print_err;
7957c478bd9Sstevel@tonic-gate 	if (fprintf(f, xml_footer) < 0)
7967c478bd9Sstevel@tonic-gate 		goto print_err;
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	(void) printf("%s -> %s\n", iconf->service, filename);
7997c478bd9Sstevel@tonic-gate 	return (0);
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate print_err:
8027c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("%s: Error writing manifest %s: %s\n"),
8037c478bd9Sstevel@tonic-gate 	    progname, filename, strerror(errno));
8047c478bd9Sstevel@tonic-gate 	return (-1);
8057c478bd9Sstevel@tonic-gate }
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate static struct fileinfo *
8087c478bd9Sstevel@tonic-gate open_srcfile(char *filename)
8097c478bd9Sstevel@tonic-gate {
8107c478bd9Sstevel@tonic-gate 	struct fileinfo *finfo = NULL;
8117c478bd9Sstevel@tonic-gate 	FILE *fp;
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	if (filename != NULL) {
8147c478bd9Sstevel@tonic-gate 		if ((fp = fopen(filename, "r")) == NULL) {
8157c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
8167c478bd9Sstevel@tonic-gate 			    gettext("%s: Error opening %s: %s\n"),
8177c478bd9Sstevel@tonic-gate 			    progname, filename, strerror(errno));
8187c478bd9Sstevel@tonic-gate 		}
8197c478bd9Sstevel@tonic-gate 	} else {
8207c478bd9Sstevel@tonic-gate 		/*
8217c478bd9Sstevel@tonic-gate 		 * If no source file specified, do the same as inetd and first
8227c478bd9Sstevel@tonic-gate 		 * try /etc/inet/inetd.conf, followed by /etc/inetd.conf.
8237c478bd9Sstevel@tonic-gate 		 */
8247c478bd9Sstevel@tonic-gate 		filename = MAIN_CONFIG;
8257c478bd9Sstevel@tonic-gate 		if ((fp = fopen(filename, "r")) == NULL) {
8267c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
8277c478bd9Sstevel@tonic-gate 			    gettext("%s: Error opening %s: %s\n"),
8287c478bd9Sstevel@tonic-gate 			    progname, filename, strerror(errno));
8297c478bd9Sstevel@tonic-gate 			filename = ALT_CONFIG;
8307c478bd9Sstevel@tonic-gate 			if ((fp = fopen(filename, "r")) == NULL) {
8317c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
8327c478bd9Sstevel@tonic-gate 				    "%s: Error opening %s: %s\n"), progname,
8337c478bd9Sstevel@tonic-gate 				    filename, strerror(errno));
8347c478bd9Sstevel@tonic-gate 			}
8357c478bd9Sstevel@tonic-gate 		}
8367c478bd9Sstevel@tonic-gate 	}
8377c478bd9Sstevel@tonic-gate 	if (fp != NULL) {
8387c478bd9Sstevel@tonic-gate 		finfo = safe_malloc(sizeof (struct fileinfo));
8397c478bd9Sstevel@tonic-gate 		finfo->fp = fp;
8407c478bd9Sstevel@tonic-gate 		finfo->filename = filename;
8417c478bd9Sstevel@tonic-gate 		finfo->lineno = 0;
8427c478bd9Sstevel@tonic-gate 		finfo->failcnt = 0;
8437c478bd9Sstevel@tonic-gate 		(void) fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
8447c478bd9Sstevel@tonic-gate 	}
8457c478bd9Sstevel@tonic-gate 	return (finfo);
8467c478bd9Sstevel@tonic-gate }
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate /*
8497c478bd9Sstevel@tonic-gate  * Opens manifest output file.  Returns 0 on success, -1 if the file
8507c478bd9Sstevel@tonic-gate  * exists, -2 on other errors.
8517c478bd9Sstevel@tonic-gate  */
8527c478bd9Sstevel@tonic-gate static int
8537c478bd9Sstevel@tonic-gate open_dstfile(
8547c478bd9Sstevel@tonic-gate     char *destdir,
8557c478bd9Sstevel@tonic-gate     boolean_t overwrite,
8567c478bd9Sstevel@tonic-gate     struct inetconfent *iconf,
8577c478bd9Sstevel@tonic-gate     struct fileinfo **finfo)
8587c478bd9Sstevel@tonic-gate {
8597c478bd9Sstevel@tonic-gate 	int fd;
8607c478bd9Sstevel@tonic-gate 	size_t len;
8617c478bd9Sstevel@tonic-gate 	char *dstfile, *cp, *proto;
8627c478bd9Sstevel@tonic-gate 	FILE *fp;
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	/* if no destdir specified, use appropriate default */
8657c478bd9Sstevel@tonic-gate 	if (destdir == NULL) {
8667c478bd9Sstevel@tonic-gate 		if (iconf->isrpc)
8677c478bd9Sstevel@tonic-gate 			destdir = MANIFEST_RPC_DIR;
8687c478bd9Sstevel@tonic-gate 		else
8697c478bd9Sstevel@tonic-gate 			destdir = MANIFEST_DIR;
8707c478bd9Sstevel@tonic-gate 	}
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 	len = strlen(destdir) + strlen(iconf->service) +
8737c478bd9Sstevel@tonic-gate 	    strlen(iconf->protocol) + sizeof ("/-visible.xml");
8747c478bd9Sstevel@tonic-gate 	dstfile = safe_malloc(len);
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 	(void) strlcpy(dstfile, destdir, len);
8777c478bd9Sstevel@tonic-gate 	if (dstfile[strlen(dstfile) - 1] != '/')
8787c478bd9Sstevel@tonic-gate 		(void) strlcat(dstfile, "/", len);
8797c478bd9Sstevel@tonic-gate 	cp = dstfile + strlen(dstfile);
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 	(void) strlcat(dstfile, iconf->service, len);
8827c478bd9Sstevel@tonic-gate 	(void) strlcat(dstfile, "-", len);
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	proto = iconf->protocol;
8857c478bd9Sstevel@tonic-gate 	if (iconf->isrpc && (strcmp(iconf->protocol, "rpc/*") == 0))
8867c478bd9Sstevel@tonic-gate 		proto = "rpc/visible";
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 	(void) strlcat(dstfile, proto, len);
8897c478bd9Sstevel@tonic-gate 	(void) strlcat(dstfile, ".xml", len);
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	/* convert any '/' chars in service or protocol to '_' chars */
8927c478bd9Sstevel@tonic-gate 	while ((cp = strchr(cp, '/')) != NULL)
8937c478bd9Sstevel@tonic-gate 		*cp = '_';
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	fd = open(dstfile, O_WRONLY|O_CREAT|(overwrite ? O_TRUNC : O_EXCL),
8967c478bd9Sstevel@tonic-gate 	    0644);
8977c478bd9Sstevel@tonic-gate 	if (fd == -1) {
8987c478bd9Sstevel@tonic-gate 		if (!overwrite && (errno == EEXIST)) {
8997c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
9007c478bd9Sstevel@tonic-gate 			    gettext("%s: Notice: Service manifest for "
9017c478bd9Sstevel@tonic-gate 			    "%s already generated as %s, skipped\n"),
9027c478bd9Sstevel@tonic-gate 			    progname, iconf->service, dstfile);
9037c478bd9Sstevel@tonic-gate 			free(dstfile);
9047c478bd9Sstevel@tonic-gate 			return (-1);
9057c478bd9Sstevel@tonic-gate 		} else {
9067c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
9077c478bd9Sstevel@tonic-gate 			    gettext("%s: Error opening %s: %s\n"),
9087c478bd9Sstevel@tonic-gate 			    progname, dstfile, strerror(errno));
9097c478bd9Sstevel@tonic-gate 			free(dstfile);
9107c478bd9Sstevel@tonic-gate 			return (-2);
9117c478bd9Sstevel@tonic-gate 		}
9127c478bd9Sstevel@tonic-gate 	}
9137c478bd9Sstevel@tonic-gate 	/* Clear errno to catch the "no stdio streams" case */
9147c478bd9Sstevel@tonic-gate 	errno = 0;
9157c478bd9Sstevel@tonic-gate 	if ((fp = fdopen(fd, "w")) == NULL) {
9167c478bd9Sstevel@tonic-gate 		char *s = strerror(errno);
9177c478bd9Sstevel@tonic-gate 		if (errno == 0)
9187c478bd9Sstevel@tonic-gate 			s = gettext("No stdio streams available");
9197c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: Error fdopen failed: %s\n"),
9207c478bd9Sstevel@tonic-gate 		    progname, s);
9217c478bd9Sstevel@tonic-gate 		(void) close(fd);
9227c478bd9Sstevel@tonic-gate 		free(dstfile);
9237c478bd9Sstevel@tonic-gate 		return (-2);
9247c478bd9Sstevel@tonic-gate 	}
9257c478bd9Sstevel@tonic-gate 	*finfo = safe_malloc(sizeof (struct fileinfo));
9267c478bd9Sstevel@tonic-gate 	(*finfo)->fp = fp;
9277c478bd9Sstevel@tonic-gate 	(*finfo)->filename = dstfile;
9287c478bd9Sstevel@tonic-gate 	(*finfo)->lineno = 0;
9297c478bd9Sstevel@tonic-gate 	(*finfo)->failcnt = 0;
9307c478bd9Sstevel@tonic-gate 	return (0);
9317c478bd9Sstevel@tonic-gate }
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate static int
9347c478bd9Sstevel@tonic-gate import_manifest(char *filename)
9357c478bd9Sstevel@tonic-gate {
9367c478bd9Sstevel@tonic-gate 	int status;
9377c478bd9Sstevel@tonic-gate 	pid_t pid, wpid;
9387c478bd9Sstevel@tonic-gate 	char *cp;
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 	if ((cp = strrchr(filename, '/')) == NULL)
9417c478bd9Sstevel@tonic-gate 		cp = filename;
9427c478bd9Sstevel@tonic-gate 	else
9437c478bd9Sstevel@tonic-gate 		cp++;
9447c478bd9Sstevel@tonic-gate 	(void) printf(gettext("Importing %s ..."), cp);
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 	if ((pid = fork()) == -1) {
9477c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
9487c478bd9Sstevel@tonic-gate 		    gettext("\n%s: fork failed, %s not imported: %s\n"),
9497c478bd9Sstevel@tonic-gate 		    progname, filename, strerror(errno));
9507c478bd9Sstevel@tonic-gate 		exit(EXIT_ERROR_SYS);
9517c478bd9Sstevel@tonic-gate 	}
9527c478bd9Sstevel@tonic-gate 	if (pid == 0) {
9537c478bd9Sstevel@tonic-gate 		/* child */
9547c478bd9Sstevel@tonic-gate 		(void) fclose(stdin);
9557c478bd9Sstevel@tonic-gate 		(void) setenv("SVCCFG_CHECKHASH", "1", 1);
9567c478bd9Sstevel@tonic-gate 		(void) execl(SVCCFG_PATH, "svccfg", "import", filename, NULL);
9577c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("\n%s: exec of %s failed: %s"),
9587c478bd9Sstevel@tonic-gate 		    progname, SVCCFG_PATH, strerror(errno));
9597c478bd9Sstevel@tonic-gate 		_exit(EXIT_ERROR_SYS);
9607c478bd9Sstevel@tonic-gate 	}
9617c478bd9Sstevel@tonic-gate 	/* parent */
9627c478bd9Sstevel@tonic-gate 	if ((wpid = waitpid(pid, &status, 0)) != pid) {
9637c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
9647c478bd9Sstevel@tonic-gate 		    "\n%s: unexpected wait (%d) from import of %s: %s\n"),
9657c478bd9Sstevel@tonic-gate 		    progname, wpid, filename, strerror(errno));
9667c478bd9Sstevel@tonic-gate 		return (-1);
9677c478bd9Sstevel@tonic-gate 	}
9687c478bd9Sstevel@tonic-gate 	if (WIFEXITED(status) && (WEXITSTATUS(status) != 0)) {
9697c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
9707c478bd9Sstevel@tonic-gate 		    gettext("\n%s: import failure (%d) for %s\n"),
9717c478bd9Sstevel@tonic-gate 		    progname, WEXITSTATUS(status), filename);
9727c478bd9Sstevel@tonic-gate 		return (-1);
9737c478bd9Sstevel@tonic-gate 	}
9747c478bd9Sstevel@tonic-gate 	(void) printf(gettext("Done\n"));
9757c478bd9Sstevel@tonic-gate 	return (0);
9767c478bd9Sstevel@tonic-gate }
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate static int
9797c478bd9Sstevel@tonic-gate inetd_config_path(char **path)
9807c478bd9Sstevel@tonic-gate {
9817c478bd9Sstevel@tonic-gate 	int fd;
9827c478bd9Sstevel@tonic-gate 	char *arg1, *configfile, *configstr;
9837c478bd9Sstevel@tonic-gate 	scf_simple_prop_t *sp;
9847c478bd9Sstevel@tonic-gate 	char cpath[PATH_MAX];
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 	if ((sp = scf_simple_prop_get(NULL, INETD_INSTANCE_FMRI, "start",
9877c478bd9Sstevel@tonic-gate 	    SCF_PROPERTY_EXEC)) == NULL)
9887c478bd9Sstevel@tonic-gate 		return (-1);
9897c478bd9Sstevel@tonic-gate 	if ((configstr = scf_simple_prop_next_astring(sp)) == NULL) {
9907c478bd9Sstevel@tonic-gate 		scf_simple_prop_free(sp);
9917c478bd9Sstevel@tonic-gate 		return (-1);
9927c478bd9Sstevel@tonic-gate 	}
9937c478bd9Sstevel@tonic-gate 	configstr = safe_strdup(configstr);
9947c478bd9Sstevel@tonic-gate 	scf_simple_prop_free(sp);
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 	/*
9977c478bd9Sstevel@tonic-gate 	 * Look for the optional configuration file, the syntax is:
9987c478bd9Sstevel@tonic-gate 	 * /usr/lib/inet/inetd [config-file] start|stop|refresh|disable|%m
9997c478bd9Sstevel@tonic-gate 	 */
10007c478bd9Sstevel@tonic-gate 	if (strtok(configstr, " \t") == NULL) {
10017c478bd9Sstevel@tonic-gate 		free(configstr);
10027c478bd9Sstevel@tonic-gate 		return (-1);
10037c478bd9Sstevel@tonic-gate 	}
10047c478bd9Sstevel@tonic-gate 	if ((arg1 = strtok(NULL, " \t")) == NULL) {
10057c478bd9Sstevel@tonic-gate 		free(configstr);
10067c478bd9Sstevel@tonic-gate 		return (-1);
10077c478bd9Sstevel@tonic-gate 	}
10087c478bd9Sstevel@tonic-gate 	if (strtok(NULL, " \t") == NULL) {
10097c478bd9Sstevel@tonic-gate 		/*
10107c478bd9Sstevel@tonic-gate 		 * No configuration file specified, do the same as inetd and
10117c478bd9Sstevel@tonic-gate 		 * first try /etc/inet/inetd.conf, followed by /etc/inetd.conf.
10127c478bd9Sstevel@tonic-gate 		 */
10137c478bd9Sstevel@tonic-gate 		configfile = MAIN_CONFIG;
10147c478bd9Sstevel@tonic-gate 		if ((fd = open(configfile, O_RDONLY)) >= 0)
10157c478bd9Sstevel@tonic-gate 			(void) close(fd);
10167c478bd9Sstevel@tonic-gate 		else
10177c478bd9Sstevel@tonic-gate 			configfile = ALT_CONFIG;
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 	} else {
10207c478bd9Sstevel@tonic-gate 		/* make sure there are no more arguments */
10217c478bd9Sstevel@tonic-gate 		if (strtok(NULL, " \t") != NULL) {
10227c478bd9Sstevel@tonic-gate 			free(configstr);
10237c478bd9Sstevel@tonic-gate 			return (-1);
10247c478bd9Sstevel@tonic-gate 		}
10257c478bd9Sstevel@tonic-gate 		configfile = arg1;
10267c478bd9Sstevel@tonic-gate 	}
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 	/* configuration file must be an absolute pathname */
10297c478bd9Sstevel@tonic-gate 	if (*configfile != '/') {
10307c478bd9Sstevel@tonic-gate 		free(configstr);
10317c478bd9Sstevel@tonic-gate 		return (-1);
10327c478bd9Sstevel@tonic-gate 	}
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 	if (realpath(configfile, cpath) == NULL)
10357c478bd9Sstevel@tonic-gate 		(void) strlcpy(cpath, configfile, sizeof (cpath));
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	free(configstr);
10387c478bd9Sstevel@tonic-gate 	*path = safe_strdup(cpath);
10397c478bd9Sstevel@tonic-gate 	return (0);
10407c478bd9Sstevel@tonic-gate }
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate static int
10437c478bd9Sstevel@tonic-gate update_hash(char *srcfile)
10447c478bd9Sstevel@tonic-gate {
10457c478bd9Sstevel@tonic-gate 	scf_error_t rval;
10467c478bd9Sstevel@tonic-gate 	char *inetd_cpath, *hashstr;
10477c478bd9Sstevel@tonic-gate 	char cpath[PATH_MAX];
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	/* determine the config file inetd is using */
10507c478bd9Sstevel@tonic-gate 	if (inetd_config_path(&inetd_cpath) == -1) {
10517c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
10527c478bd9Sstevel@tonic-gate 		    gettext("%s: Error reading from repository\n"), progname);
10537c478bd9Sstevel@tonic-gate 		return (-1);
10547c478bd9Sstevel@tonic-gate 	}
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 	/* resolve inetconv input filename */
10577c478bd9Sstevel@tonic-gate 	if (realpath(srcfile, cpath) == NULL)
10587c478bd9Sstevel@tonic-gate 		(void) strlcpy(cpath, srcfile, sizeof (cpath));
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 	/* if inetconv and inetd are using the same config file, update hash */
10617c478bd9Sstevel@tonic-gate 	if (strcmp(cpath, inetd_cpath) != 0) {
10627c478bd9Sstevel@tonic-gate 		free(inetd_cpath);
10637c478bd9Sstevel@tonic-gate 		return (0);
10647c478bd9Sstevel@tonic-gate 	}
10657c478bd9Sstevel@tonic-gate 	free(inetd_cpath);
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate 	/* generic error message as use of hash is not exposed to the user */
10687c478bd9Sstevel@tonic-gate 	if (calculate_hash(cpath, &hashstr) != 0) {
10697c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
10707c478bd9Sstevel@tonic-gate 		    gettext("%s: Error unable to update repository\n"),
10717c478bd9Sstevel@tonic-gate 		    progname);
10727c478bd9Sstevel@tonic-gate 		return (-1);
10737c478bd9Sstevel@tonic-gate 	}
10747c478bd9Sstevel@tonic-gate 	/* generic error message as use of hash is not exposed to the user */
10757c478bd9Sstevel@tonic-gate 	if ((rval = store_inetd_hash(hashstr)) != SCF_ERROR_NONE) {
10767c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
10777c478bd9Sstevel@tonic-gate 		    gettext("%s: Error updating repository: %s\n"),
10787c478bd9Sstevel@tonic-gate 		    progname, scf_strerror(rval));
10797c478bd9Sstevel@tonic-gate 		free(hashstr);
10807c478bd9Sstevel@tonic-gate 		return (-1);
10817c478bd9Sstevel@tonic-gate 	}
10827c478bd9Sstevel@tonic-gate 	free(hashstr);
10837c478bd9Sstevel@tonic-gate 	return (0);
10847c478bd9Sstevel@tonic-gate }
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate static void
10877c478bd9Sstevel@tonic-gate property_error(const char *fmri, const char *prop)
10887c478bd9Sstevel@tonic-gate {
10897c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
10907c478bd9Sstevel@tonic-gate 	    gettext("Error: Instance %1$s is missing property '%2$s'.\n"),
10917c478bd9Sstevel@tonic-gate 	    fmri, prop);
10927c478bd9Sstevel@tonic-gate }
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate /*
10957c478bd9Sstevel@tonic-gate  * modify_sprop takes a handle, an instance, a property group, a property,
10967c478bd9Sstevel@tonic-gate  * and an astring value, and modifies the instance (or service's) specified
10977c478bd9Sstevel@tonic-gate  * property in the repository to the submitted value.
10987c478bd9Sstevel@tonic-gate  *
10997c478bd9Sstevel@tonic-gate  * returns -1 on error, 1 on successful transaction completion.
11007c478bd9Sstevel@tonic-gate  */
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate static int
11037c478bd9Sstevel@tonic-gate modify_sprop(scf_handle_t *h, const scf_instance_t *inst,
11047c478bd9Sstevel@tonic-gate     const char *pg, const char *prop, const char *value)
11057c478bd9Sstevel@tonic-gate {
11067c478bd9Sstevel@tonic-gate 	scf_transaction_t		*tx = NULL;
11077c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t		*ent = NULL;
11087c478bd9Sstevel@tonic-gate 	scf_propertygroup_t		*gpg = NULL;
11097c478bd9Sstevel@tonic-gate 	scf_property_t			*eprop = NULL;
11107c478bd9Sstevel@tonic-gate 	scf_value_t			*v = NULL;
11117c478bd9Sstevel@tonic-gate 	scf_service_t			*svc = NULL;
11127c478bd9Sstevel@tonic-gate 	int				ret = 0, create = 0;
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 	if ((gpg = scf_pg_create(h)) == NULL)
11157c478bd9Sstevel@tonic-gate 		return (-1);
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 	/* Get the property group */
11187c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, pg, gpg) == -1) {
11197c478bd9Sstevel@tonic-gate 		/* Not a property of the instance, try the service instead */
11207c478bd9Sstevel@tonic-gate 		if ((svc = scf_service_create(h)) == NULL) {
11217c478bd9Sstevel@tonic-gate 			ret = -1;
11227c478bd9Sstevel@tonic-gate 			goto out;
11237c478bd9Sstevel@tonic-gate 		}
11247c478bd9Sstevel@tonic-gate 		if ((scf_instance_get_parent(inst, svc) == -1) ||
11257c478bd9Sstevel@tonic-gate 		    (scf_service_get_pg(svc, pg, gpg) == -1)) {
11267c478bd9Sstevel@tonic-gate 			ret = -1;
11277c478bd9Sstevel@tonic-gate 			goto out;
11287c478bd9Sstevel@tonic-gate 		}
11297c478bd9Sstevel@tonic-gate 	}
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 	if ((eprop = scf_property_create(h)) == NULL) {
11327c478bd9Sstevel@tonic-gate 		ret = -1;
11337c478bd9Sstevel@tonic-gate 		goto out;
11347c478bd9Sstevel@tonic-gate 	}
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(gpg, prop, eprop) == -1) {
11377c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND) {
11387c478bd9Sstevel@tonic-gate 			ret = -1;
11397c478bd9Sstevel@tonic-gate 			goto out;
11407c478bd9Sstevel@tonic-gate 		}
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 		create = 1;
11437c478bd9Sstevel@tonic-gate 	}
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate 	if ((tx = scf_transaction_create(h)) == NULL ||
11467c478bd9Sstevel@tonic-gate 	    (ent = scf_entry_create(h)) == NULL) {
11477c478bd9Sstevel@tonic-gate 		ret = -1;
11487c478bd9Sstevel@tonic-gate 		goto out;
11497c478bd9Sstevel@tonic-gate 	}
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate 	do {
11527c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(tx, gpg) == -1) {
11537c478bd9Sstevel@tonic-gate 			ret = -1;
11547c478bd9Sstevel@tonic-gate 			goto out;
11557c478bd9Sstevel@tonic-gate 		}
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 		/* Modify the property */
11587c478bd9Sstevel@tonic-gate 		if (create)
11597c478bd9Sstevel@tonic-gate 			ret = scf_transaction_property_new(tx, ent, prop,
11607c478bd9Sstevel@tonic-gate 			    SCF_TYPE_ASTRING);
11617c478bd9Sstevel@tonic-gate 		else
11627c478bd9Sstevel@tonic-gate 			ret = scf_transaction_property_change_type(tx, ent,
11637c478bd9Sstevel@tonic-gate 			    prop, SCF_TYPE_ASTRING);
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 		if (ret == -1)
11667c478bd9Sstevel@tonic-gate 			goto out;
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate 		if ((v = scf_value_create(h)) == NULL) {
11697c478bd9Sstevel@tonic-gate 			ret = -1;
11707c478bd9Sstevel@tonic-gate 			goto out;
11717c478bd9Sstevel@tonic-gate 		}
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 		if (scf_value_set_astring(v, value) == -1) {
11747c478bd9Sstevel@tonic-gate 			ret = -1;
11757c478bd9Sstevel@tonic-gate 			goto out;
11767c478bd9Sstevel@tonic-gate 		}
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate 		if (scf_entry_add_value(ent, v) == -1) {
11797c478bd9Sstevel@tonic-gate 			ret = -1;
11807c478bd9Sstevel@tonic-gate 			goto out;
11817c478bd9Sstevel@tonic-gate 		}
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 		ret = scf_transaction_commit(tx);
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 		if (ret == 0) {
11867c478bd9Sstevel@tonic-gate 			/* Property group was stale, retry */
11877c478bd9Sstevel@tonic-gate 			if (scf_pg_update(gpg) == -1) {
11887c478bd9Sstevel@tonic-gate 				ret = -1;
11897c478bd9Sstevel@tonic-gate 				goto out;
11907c478bd9Sstevel@tonic-gate 			}
11917c478bd9Sstevel@tonic-gate 			scf_transaction_reset(tx);
11927c478bd9Sstevel@tonic-gate 		}
11937c478bd9Sstevel@tonic-gate 
11947c478bd9Sstevel@tonic-gate 	} while (ret == 0);
11957c478bd9Sstevel@tonic-gate out:
11967c478bd9Sstevel@tonic-gate 	scf_value_destroy(v);
11977c478bd9Sstevel@tonic-gate 	scf_entry_destroy(ent);
11987c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(tx);
11997c478bd9Sstevel@tonic-gate 	scf_property_destroy(eprop);
12007c478bd9Sstevel@tonic-gate 	scf_service_destroy(svc);
12017c478bd9Sstevel@tonic-gate 	scf_pg_destroy(gpg);
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 	return (ret);
12047c478bd9Sstevel@tonic-gate }
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate /*
12077c478bd9Sstevel@tonic-gate  * list_callback is the callback function to be handed to simple_walk_instances
12087c478bd9Sstevel@tonic-gate  * in main.  It is called once on every instance on a machine.  If that
12097c478bd9Sstevel@tonic-gate  * instance is controlled by inetd, we test whether it's the same
12107c478bd9Sstevel@tonic-gate  * service that we're looking at from the inetd.conf file, and enable it if
12117c478bd9Sstevel@tonic-gate  * they are the same.
12127c478bd9Sstevel@tonic-gate  */
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12157c478bd9Sstevel@tonic-gate static int
12167c478bd9Sstevel@tonic-gate list_callback(scf_handle_t *h, scf_instance_t *inst, void *buf)
12177c478bd9Sstevel@tonic-gate {
12187c478bd9Sstevel@tonic-gate 	ssize_t			max_name_length;
12197c478bd9Sstevel@tonic-gate 	char			*svc_name;
12207c478bd9Sstevel@tonic-gate 	scf_simple_prop_t	*prop = NULL;
12217c478bd9Sstevel@tonic-gate 	scf_simple_prop_t	*sockprop = NULL;
12227c478bd9Sstevel@tonic-gate 	scf_simple_prop_t	*rpcprop = NULL;
12237c478bd9Sstevel@tonic-gate 	scf_simple_prop_t	*progprop = NULL;
12247c478bd9Sstevel@tonic-gate 	const char		*name, *endpoint, *restart_str, *prog;
12257c478bd9Sstevel@tonic-gate 	struct inetconfent	*iconf = (struct inetconfent *)buf;
12267c478bd9Sstevel@tonic-gate 	uint8_t			*isrpc;
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate 	max_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
12297c478bd9Sstevel@tonic-gate 	if ((svc_name = malloc(max_name_length + 1)) == NULL) {
12307c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Error: Out of memory.\n"));
12317c478bd9Sstevel@tonic-gate 		return (SCF_FAILED);
12327c478bd9Sstevel@tonic-gate 	}
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate 	/*
12357c478bd9Sstevel@tonic-gate 	 * Get the FMRI of the instance, and check if its delegated restarter
12367c478bd9Sstevel@tonic-gate 	 * is inetd.  A missing or empty restarter property implies that
12377c478bd9Sstevel@tonic-gate 	 * svc.startd is the restarter.
12387c478bd9Sstevel@tonic-gate 	 */
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 	if (scf_instance_to_fmri(inst, svc_name, max_name_length) < 0) {
12417c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
12427c478bd9Sstevel@tonic-gate 		    gettext("Error: Unable to obtain FMRI for service %1$s."),
12437c478bd9Sstevel@tonic-gate 		    svc_name);
12447c478bd9Sstevel@tonic-gate 		free(svc_name);
12457c478bd9Sstevel@tonic-gate 		return (SCF_FAILED);
12467c478bd9Sstevel@tonic-gate 	}
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate 	if ((prop = scf_simple_prop_get(h, svc_name, SCF_PG_GENERAL,
12497c478bd9Sstevel@tonic-gate 	    SCF_PROPERTY_RESTARTER)) == NULL)
12507c478bd9Sstevel@tonic-gate 		goto out;
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	if ((restart_str = scf_simple_prop_next_ustring(prop)) == NULL)
12537c478bd9Sstevel@tonic-gate 		goto out;
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate 	if (strcmp(restart_str, INETD_INSTANCE_FMRI) != 0)
12567c478bd9Sstevel@tonic-gate 		goto out;
12577c478bd9Sstevel@tonic-gate 
12587c478bd9Sstevel@tonic-gate 	/* Free restarter prop so it can be reused below */
12597c478bd9Sstevel@tonic-gate 	scf_simple_prop_free(prop);
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 	/*
12627c478bd9Sstevel@tonic-gate 	 * We know that this instance is managed by inetd.
12637c478bd9Sstevel@tonic-gate 	 * Now get the properties needed to decide if it matches this
12647c478bd9Sstevel@tonic-gate 	 * line in the old config file.
12657c478bd9Sstevel@tonic-gate 	 */
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 	if (((prop = scf_simple_prop_get(h, svc_name, PG_NAME_SERVICE_CONFIG,
12687c478bd9Sstevel@tonic-gate 	    PR_SVC_NAME_NAME)) == NULL) ||
12697c478bd9Sstevel@tonic-gate 	    ((name = scf_simple_prop_next_astring(prop)) == NULL)) {
12707c478bd9Sstevel@tonic-gate 		property_error(svc_name, PR_SVC_NAME_NAME);
12717c478bd9Sstevel@tonic-gate 		goto out;
12727c478bd9Sstevel@tonic-gate 	}
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 	if (((sockprop = scf_simple_prop_get(h, svc_name,
12757c478bd9Sstevel@tonic-gate 	    PG_NAME_SERVICE_CONFIG, PR_SOCK_TYPE_NAME)) == NULL) ||
12767c478bd9Sstevel@tonic-gate 	    ((endpoint = scf_simple_prop_next_astring(sockprop)) == NULL)) {
12777c478bd9Sstevel@tonic-gate 		property_error(svc_name, PR_SOCK_TYPE_NAME);
12787c478bd9Sstevel@tonic-gate 		goto out;
12797c478bd9Sstevel@tonic-gate 	}
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate 	if (((rpcprop = scf_simple_prop_get(h, svc_name,
12827c478bd9Sstevel@tonic-gate 	    PG_NAME_SERVICE_CONFIG, PR_ISRPC_NAME)) == NULL) ||
12837c478bd9Sstevel@tonic-gate 	    ((isrpc = scf_simple_prop_next_boolean(rpcprop)) == NULL)) {
12847c478bd9Sstevel@tonic-gate 		property_error(svc_name, PR_ISRPC_NAME);
12857c478bd9Sstevel@tonic-gate 		goto out;
12867c478bd9Sstevel@tonic-gate 	}
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 	if (((progprop = scf_simple_prop_get(h, svc_name, START_METHOD_NAME,
12897c478bd9Sstevel@tonic-gate 	    PR_EXEC_NAME)) == NULL) ||
12907c478bd9Sstevel@tonic-gate 	    ((prog = scf_simple_prop_next_astring(progprop)) == NULL)) {
12917c478bd9Sstevel@tonic-gate 		property_error(svc_name, PR_EXEC_NAME);
12927c478bd9Sstevel@tonic-gate 	}
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate 	/* If it's RPC, we truncate off the version portion for comparison */
12967c478bd9Sstevel@tonic-gate 	if (*isrpc) {
12977c478bd9Sstevel@tonic-gate 		char *cp;
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 		cp = strchr(iconf->service, '/');
13007c478bd9Sstevel@tonic-gate 		if (cp != NULL)
13017c478bd9Sstevel@tonic-gate 			*cp = '\0';
13027c478bd9Sstevel@tonic-gate 	}
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 	/*
13057c478bd9Sstevel@tonic-gate 	 * If name of this service and endpoint are equal to values from
13067c478bd9Sstevel@tonic-gate 	 * iconf fields, and they're either both RPC or both non-RPC,
13077c478bd9Sstevel@tonic-gate 	 * then we have a match; update the exec and arg0 properties if
13087c478bd9Sstevel@tonic-gate 	 * necessary, then enable it.
13097c478bd9Sstevel@tonic-gate 	 * We don't return an error if either operation fails so that we
13107c478bd9Sstevel@tonic-gate 	 * continue to try all the other services.
13117c478bd9Sstevel@tonic-gate 	 */
13127c478bd9Sstevel@tonic-gate 	if (strcmp(name, iconf->service) == 0 &&
13137c478bd9Sstevel@tonic-gate 	    strcmp(endpoint, iconf->endpoint) == 0 &&
13147c478bd9Sstevel@tonic-gate 	    *isrpc == (strncmp(iconf->protocol, "rpc/", 4) == 0)) {
13157c478bd9Sstevel@tonic-gate 		/* Can't update exec on internal services */
13167c478bd9Sstevel@tonic-gate 		if ((strcmp(iconf->server_program, "internal") != 0) &&
13177c478bd9Sstevel@tonic-gate 		    (strcmp(iconf->exec, prog) != 0)) {
13187c478bd9Sstevel@tonic-gate 			/* User had edited the command */
13197c478bd9Sstevel@tonic-gate 			if (!import) {
13207c478bd9Sstevel@tonic-gate 				/* Dry run only */
13217c478bd9Sstevel@tonic-gate 				(void) printf(
13227c478bd9Sstevel@tonic-gate 				    gettext("Would update %s to %s %s"),
13237c478bd9Sstevel@tonic-gate 				    svc_name, PR_EXEC_NAME, iconf->exec);
13247c478bd9Sstevel@tonic-gate 				if (iconf->arg0 != NULL) {
13257c478bd9Sstevel@tonic-gate 					(void) printf(
13267c478bd9Sstevel@tonic-gate 					    gettext(" with %s of %s\n"),
13277c478bd9Sstevel@tonic-gate 					    PR_ARG0_NAME, iconf->arg0);
13287c478bd9Sstevel@tonic-gate 				} else {
13297c478bd9Sstevel@tonic-gate 					(void) printf("\n");
13307c478bd9Sstevel@tonic-gate 				}
13317c478bd9Sstevel@tonic-gate 			} else {
13327c478bd9Sstevel@tonic-gate 				/* Update instance's exec property */
13337c478bd9Sstevel@tonic-gate 				if (modify_sprop(h, inst, START_METHOD_NAME,
13347c478bd9Sstevel@tonic-gate 				    PR_EXEC_NAME, iconf->exec) != 1)
13357c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
13367c478bd9Sstevel@tonic-gate 					    gettext("Error: Unable to update "
13377c478bd9Sstevel@tonic-gate 					    "%s property of %s, %s\n"),
13387c478bd9Sstevel@tonic-gate 					    PR_EXEC_NAME, svc_name,
13397c478bd9Sstevel@tonic-gate 					    scf_strerror(scf_error()));
13407c478bd9Sstevel@tonic-gate 				else
13417c478bd9Sstevel@tonic-gate 					(void) printf("%s will %s %s\n",
13427c478bd9Sstevel@tonic-gate 					    svc_name, PR_EXEC_NAME,
13437c478bd9Sstevel@tonic-gate 					    iconf->exec);
13447c478bd9Sstevel@tonic-gate 
13457c478bd9Sstevel@tonic-gate 				/* Update arg0 prop, if needed */
13467c478bd9Sstevel@tonic-gate 				if (iconf->arg0 != NULL) {
13477c478bd9Sstevel@tonic-gate 					if (modify_sprop(h, inst,
13487c478bd9Sstevel@tonic-gate 					    START_METHOD_NAME, PR_ARG0_NAME,
13497c478bd9Sstevel@tonic-gate 					    iconf->arg0) != 1) {
13507c478bd9Sstevel@tonic-gate 						(void) fprintf(stderr,
13517c478bd9Sstevel@tonic-gate 						    gettext("Error: Unable to "
13527c478bd9Sstevel@tonic-gate 						    "update %s property of "
13537c478bd9Sstevel@tonic-gate 						    "%s, %s\n"), PR_ARG0_NAME,
13547c478bd9Sstevel@tonic-gate 						    svc_name,
13557c478bd9Sstevel@tonic-gate 						    scf_strerror(scf_error()));
13567c478bd9Sstevel@tonic-gate 					} else {
13577c478bd9Sstevel@tonic-gate 						(void) printf("%s will have an "
13587c478bd9Sstevel@tonic-gate 						    "%s of %s\n", svc_name,
13597c478bd9Sstevel@tonic-gate 						    PR_ARG0_NAME, iconf->arg0);
13607c478bd9Sstevel@tonic-gate 					}
13617c478bd9Sstevel@tonic-gate 				}
13627c478bd9Sstevel@tonic-gate 			}
13637c478bd9Sstevel@tonic-gate 		}
13647c478bd9Sstevel@tonic-gate 
13657c478bd9Sstevel@tonic-gate 		if (!import) {
13667c478bd9Sstevel@tonic-gate 			/* Dry-run only */
13677c478bd9Sstevel@tonic-gate 			(void) printf("Would enable %s\n", svc_name);
13687c478bd9Sstevel@tonic-gate 		} else {
13697c478bd9Sstevel@tonic-gate 			if (smf_enable_instance(svc_name, 0) != 0)
13707c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
13717c478bd9Sstevel@tonic-gate 				    gettext("Error: Failed to enable %s\n"),
13727c478bd9Sstevel@tonic-gate 				    svc_name);
13737c478bd9Sstevel@tonic-gate 			else
13747c478bd9Sstevel@tonic-gate 				(void) printf("%s enabled\n", svc_name);
13757c478bd9Sstevel@tonic-gate 		}
13767c478bd9Sstevel@tonic-gate 	}
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate out:
13797c478bd9Sstevel@tonic-gate 	free(svc_name);
13807c478bd9Sstevel@tonic-gate 	scf_simple_prop_free(prop);
13817c478bd9Sstevel@tonic-gate 	scf_simple_prop_free(sockprop);
13827c478bd9Sstevel@tonic-gate 	scf_simple_prop_free(rpcprop);
13837c478bd9Sstevel@tonic-gate 	scf_simple_prop_free(progprop);
13847c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
13857c478bd9Sstevel@tonic-gate }
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate static void
13887c478bd9Sstevel@tonic-gate usage(void)
13897c478bd9Sstevel@tonic-gate {
13907c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
13917c478bd9Sstevel@tonic-gate 	    "Usage: %s [-fn] [-i srcfile] [-o destdir]\n"
13927c478bd9Sstevel@tonic-gate 	    "       %1$s -e [-n] [-i srcfile]\n"
13937c478bd9Sstevel@tonic-gate 	    "-?          Display this usage message\n"
13947c478bd9Sstevel@tonic-gate 	    "-e          Enable smf services which are enabled in the input\n"
13957c478bd9Sstevel@tonic-gate 	    "            file\n"
13967c478bd9Sstevel@tonic-gate 	    "-f          Force overwrite of existing manifests\n"
13977c478bd9Sstevel@tonic-gate 	    "-n          Do not import converted manifests,\n"
13987c478bd9Sstevel@tonic-gate 	    "            or only display services which would be enabled\n"
13997c478bd9Sstevel@tonic-gate 	    "-i srcfile  Alternate input file\n"
14007c478bd9Sstevel@tonic-gate 	    "-o destdir  Alternate output directory for manifests\n"),
14017c478bd9Sstevel@tonic-gate 	    progname);
14027c478bd9Sstevel@tonic-gate 	exit(EXIT_USAGE);
14037c478bd9Sstevel@tonic-gate }
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate int
14067c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
14077c478bd9Sstevel@tonic-gate {
14087c478bd9Sstevel@tonic-gate 	int c, rval, convert_err, import_err = 0, enable_err = 0;
14097c478bd9Sstevel@tonic-gate 	boolean_t overwrite = B_FALSE;
14107c478bd9Sstevel@tonic-gate 	boolean_t enable = B_FALSE;
14117c478bd9Sstevel@tonic-gate 	char *srcfile = NULL;
14127c478bd9Sstevel@tonic-gate 	char *destdir = NULL;
14137c478bd9Sstevel@tonic-gate 	struct fileinfo *srcfinfo, *dstfinfo;
14147c478bd9Sstevel@tonic-gate 	struct inetconfent *iconf;
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 	setbuf(stdout, NULL);
14177c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
14187c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 	if ((progname = strrchr(argv[0], '/')) == NULL)
14217c478bd9Sstevel@tonic-gate 		progname = argv[0];
14227c478bd9Sstevel@tonic-gate 	else
14237c478bd9Sstevel@tonic-gate 		progname++;
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "?efni:o:")) != -1) {
14267c478bd9Sstevel@tonic-gate 		switch (c) {
14277c478bd9Sstevel@tonic-gate 		case 'e':
14287c478bd9Sstevel@tonic-gate 			/* enable services based on existing file config */
14297c478bd9Sstevel@tonic-gate 			enable = B_TRUE;
14307c478bd9Sstevel@tonic-gate 			break;
14317c478bd9Sstevel@tonic-gate 
14327c478bd9Sstevel@tonic-gate 		case 'f':
14337c478bd9Sstevel@tonic-gate 			/* overwrite existing manifests */
14347c478bd9Sstevel@tonic-gate 			overwrite = B_TRUE;
14357c478bd9Sstevel@tonic-gate 			break;
14367c478bd9Sstevel@tonic-gate 		case 'n':
14377c478bd9Sstevel@tonic-gate 			/* don't import manifests, or dry-run enable */
14387c478bd9Sstevel@tonic-gate 			import = B_FALSE;
14397c478bd9Sstevel@tonic-gate 			break;
14407c478bd9Sstevel@tonic-gate 		case 'i':
14417c478bd9Sstevel@tonic-gate 			/* alternate input file */
14427c478bd9Sstevel@tonic-gate 			if (srcfile != NULL) {
14437c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
14447c478bd9Sstevel@tonic-gate 				    gettext("%s: Error only one -%c allowed\n"),
14457c478bd9Sstevel@tonic-gate 				    progname, optopt);
14467c478bd9Sstevel@tonic-gate 				usage();
14477c478bd9Sstevel@tonic-gate 			}
14487c478bd9Sstevel@tonic-gate 			srcfile = optarg;
14497c478bd9Sstevel@tonic-gate 			break;
14507c478bd9Sstevel@tonic-gate 		case 'o':
14517c478bd9Sstevel@tonic-gate 			/* alternate output directory */
14527c478bd9Sstevel@tonic-gate 			if (destdir != NULL) {
14537c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
14547c478bd9Sstevel@tonic-gate 				    gettext("%s: Error only one -%c allowed\n"),
14557c478bd9Sstevel@tonic-gate 				    progname, optopt);
14567c478bd9Sstevel@tonic-gate 				usage();
14577c478bd9Sstevel@tonic-gate 			}
14587c478bd9Sstevel@tonic-gate 			destdir = optarg;
14597c478bd9Sstevel@tonic-gate 			break;
14607c478bd9Sstevel@tonic-gate 		case '?': /*FALLTHROUGH*/
14617c478bd9Sstevel@tonic-gate 		default:
14627c478bd9Sstevel@tonic-gate 			usage();
14637c478bd9Sstevel@tonic-gate 			break;
14647c478bd9Sstevel@tonic-gate 		}
14657c478bd9Sstevel@tonic-gate 	}
14667c478bd9Sstevel@tonic-gate 
14677c478bd9Sstevel@tonic-gate 	/*
14687c478bd9Sstevel@tonic-gate 	 * Display usage if extraneous args supplied or enable specified in
14697c478bd9Sstevel@tonic-gate 	 * combination with overwrite or destdir
14707c478bd9Sstevel@tonic-gate 	 */
14717c478bd9Sstevel@tonic-gate 	if ((optind != argc) || (enable && (overwrite || destdir != NULL)))
14727c478bd9Sstevel@tonic-gate 		usage();
14737c478bd9Sstevel@tonic-gate 
14747c478bd9Sstevel@tonic-gate 	if ((srcfinfo = open_srcfile(srcfile)) == NULL)
14757c478bd9Sstevel@tonic-gate 		return (EXIT_ERROR_CONV);
14767c478bd9Sstevel@tonic-gate 
14777c478bd9Sstevel@tonic-gate 	while ((iconf = fgetinetconfent(srcfinfo, !enable)) != NULL) {
14787c478bd9Sstevel@tonic-gate 		/*
14797c478bd9Sstevel@tonic-gate 		 * If we're enabling, then just walk all the services for each
14807c478bd9Sstevel@tonic-gate 		 * line and enable those which match.
14817c478bd9Sstevel@tonic-gate 		 */
14827c478bd9Sstevel@tonic-gate 		if (enable) {
14837c478bd9Sstevel@tonic-gate 			rval = scf_simple_walk_instances(SCF_STATE_ALL, iconf,
14847c478bd9Sstevel@tonic-gate 			    list_callback);
14857c478bd9Sstevel@tonic-gate 			free_inetconfent(iconf);
14867c478bd9Sstevel@tonic-gate 			if (rval == SCF_FAILED) {
14877c478bd9Sstevel@tonic-gate 				/* Only print msg if framework error */
14887c478bd9Sstevel@tonic-gate 				if (scf_error() != SCF_ERROR_CALLBACK_FAILED)
14897c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
14907c478bd9Sstevel@tonic-gate 					    "Error walking instances: %s.\n"),
14917c478bd9Sstevel@tonic-gate 					    scf_strerror(scf_error()));
14927c478bd9Sstevel@tonic-gate 				enable_err++;
14937c478bd9Sstevel@tonic-gate 				break;
14947c478bd9Sstevel@tonic-gate 			}
14957c478bd9Sstevel@tonic-gate 			continue;
14967c478bd9Sstevel@tonic-gate 		}
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 		/* Remainder of loop used for conversion & import */
14997c478bd9Sstevel@tonic-gate 		if ((rval = open_dstfile(destdir, overwrite, iconf, &dstfinfo))
15007c478bd9Sstevel@tonic-gate 		    < 0) {
15017c478bd9Sstevel@tonic-gate 			/*
15027c478bd9Sstevel@tonic-gate 			 * Only increment error counter if the failure was
15037c478bd9Sstevel@tonic-gate 			 * other than the file already existing.
15047c478bd9Sstevel@tonic-gate 			 */
15057c478bd9Sstevel@tonic-gate 			if (rval == -2)
15067c478bd9Sstevel@tonic-gate 				srcfinfo->failcnt++;
15077c478bd9Sstevel@tonic-gate 			free_inetconfent(iconf);
15087c478bd9Sstevel@tonic-gate 			continue;
15097c478bd9Sstevel@tonic-gate 		}
15107c478bd9Sstevel@tonic-gate 		rval = print_manifest(dstfinfo->fp, dstfinfo->filename, iconf);
15117c478bd9Sstevel@tonic-gate 		(void) fclose(dstfinfo->fp);
15127c478bd9Sstevel@tonic-gate 		if (rval == 0) {
15137c478bd9Sstevel@tonic-gate 			if (import &&
15147c478bd9Sstevel@tonic-gate 			    (import_manifest(dstfinfo->filename) != 0))
15157c478bd9Sstevel@tonic-gate 				import_err++;
15167c478bd9Sstevel@tonic-gate 		} else {
15177c478bd9Sstevel@tonic-gate 			(void) unlink(dstfinfo->filename);
15187c478bd9Sstevel@tonic-gate 			srcfinfo->failcnt++;
15197c478bd9Sstevel@tonic-gate 		}
15207c478bd9Sstevel@tonic-gate 		free(dstfinfo->filename);
15217c478bd9Sstevel@tonic-gate 		free(dstfinfo);
15227c478bd9Sstevel@tonic-gate 		free_inetconfent(iconf);
15237c478bd9Sstevel@tonic-gate 	}
15247c478bd9Sstevel@tonic-gate 	(void) fclose(srcfinfo->fp);
15257c478bd9Sstevel@tonic-gate 	convert_err = srcfinfo->failcnt;
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate 	/* Update hash only if not in enable mode, and only if importing */
15287c478bd9Sstevel@tonic-gate 	if (!enable && import && (update_hash(srcfinfo->filename) != 0))
15297c478bd9Sstevel@tonic-gate 		import_err++;
15307c478bd9Sstevel@tonic-gate 
15317c478bd9Sstevel@tonic-gate 	free(srcfinfo);
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 	if (enable_err != 0)
15347c478bd9Sstevel@tonic-gate 		return (EXIT_ERROR_ENBL);
15357c478bd9Sstevel@tonic-gate 	if (import_err != 0)
15367c478bd9Sstevel@tonic-gate 		return (EXIT_ERROR_IMP);
15377c478bd9Sstevel@tonic-gate 	if (convert_err != 0)
15387c478bd9Sstevel@tonic-gate 		return (EXIT_ERROR_CONV);
15397c478bd9Sstevel@tonic-gate 	return (EXIT_SUCCESS);
15407c478bd9Sstevel@tonic-gate }
1541