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
55404Stn143363 * Common Development and Distribution License (the "License").
65404Stn143363 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*11996SThomas.Whitten@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate * inetconv - convert inetd.conf entries into smf(5) service manifests,
280Sstevel@tonic-gate * import them into smf(5) repository
290Sstevel@tonic-gate */
300Sstevel@tonic-gate
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/param.h>
330Sstevel@tonic-gate #include <sys/stat.h>
340Sstevel@tonic-gate #include <sys/wait.h>
350Sstevel@tonic-gate #include <stdio.h>
360Sstevel@tonic-gate #include <stdlib.h>
370Sstevel@tonic-gate #include <string.h>
380Sstevel@tonic-gate #include <unistd.h>
390Sstevel@tonic-gate #include <fcntl.h>
400Sstevel@tonic-gate #include <pwd.h>
410Sstevel@tonic-gate #include <grp.h>
420Sstevel@tonic-gate #include <errno.h>
430Sstevel@tonic-gate #include <limits.h>
440Sstevel@tonic-gate #include <locale.h>
450Sstevel@tonic-gate #include <libintl.h>
460Sstevel@tonic-gate #include <libscf.h>
470Sstevel@tonic-gate #include <inetsvc.h>
480Sstevel@tonic-gate #include <rpc/nettype.h>
490Sstevel@tonic-gate
500Sstevel@tonic-gate /* exit codes */
510Sstevel@tonic-gate #define EXIT_SUCCESS 0 /* succeeded */
520Sstevel@tonic-gate #define EXIT_USAGE 1 /* bad options */
530Sstevel@tonic-gate #define EXIT_ERROR_CONV 2 /* error(s) coverting inetd.conf entries */
540Sstevel@tonic-gate #define EXIT_ERROR_IMP 3 /* error(s) importing manifests */
550Sstevel@tonic-gate #define EXIT_ERROR_SYS 4 /* system error */
560Sstevel@tonic-gate #define EXIT_ERROR_ENBL 5 /* error(s) enabling services */
570Sstevel@tonic-gate
580Sstevel@tonic-gate #ifndef TEXT_DOMAIN
590Sstevel@tonic-gate #define TEXT_DOMAIN "SUNW_OST_OSCMD"
600Sstevel@tonic-gate #endif
610Sstevel@tonic-gate
620Sstevel@tonic-gate #define MAIN_CONFIG "/etc/inet/inetd.conf"
630Sstevel@tonic-gate #define ALT_CONFIG "/etc/inetd.conf"
640Sstevel@tonic-gate
65*11996SThomas.Whitten@Sun.COM #define MANIFEST_DIR "/lib/svc/manifest/network"
66290Sdstaff #define MANIFEST_RPC_DIR MANIFEST_DIR "/rpc"
670Sstevel@tonic-gate #define SVCCFG_PATH "/usr/sbin/svccfg"
680Sstevel@tonic-gate
69290Sdstaff #define RPCBIND_FMRI "svc:/network/rpc/bind"
70290Sdstaff
710Sstevel@tonic-gate /* maximum allowed length of an inetd.conf format line */
720Sstevel@tonic-gate #define MAX_SRC_LINELEN 32768
730Sstevel@tonic-gate
740Sstevel@tonic-gate /* Version of inetconv, used as a marker in services we generate */
750Sstevel@tonic-gate #define INETCONV_VERSION 1
760Sstevel@tonic-gate
770Sstevel@tonic-gate struct inetconfent {
780Sstevel@tonic-gate /* fields as read from inetd.conf format line */
790Sstevel@tonic-gate char *service;
800Sstevel@tonic-gate char *endpoint;
810Sstevel@tonic-gate char *protocol;
820Sstevel@tonic-gate char *wait_status;
830Sstevel@tonic-gate char *username;
840Sstevel@tonic-gate char *server_program;
850Sstevel@tonic-gate char *server_args;
860Sstevel@tonic-gate /* information derived from above fields */
870Sstevel@tonic-gate boolean_t wait;
880Sstevel@tonic-gate boolean_t isrpc;
890Sstevel@tonic-gate int rpc_low_version;
900Sstevel@tonic-gate int rpc_high_version;
910Sstevel@tonic-gate char *rpc_prog;
920Sstevel@tonic-gate char *groupname;
930Sstevel@tonic-gate char *exec;
940Sstevel@tonic-gate char *arg0;
950Sstevel@tonic-gate };
960Sstevel@tonic-gate
970Sstevel@tonic-gate struct fileinfo {
980Sstevel@tonic-gate FILE *fp;
990Sstevel@tonic-gate char *filename;
1000Sstevel@tonic-gate int lineno;
1010Sstevel@tonic-gate int failcnt;
1020Sstevel@tonic-gate };
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate static char *progname;
1050Sstevel@tonic-gate
1060Sstevel@tonic-gate static boolean_t import = B_TRUE;
1070Sstevel@tonic-gate
1080Sstevel@tonic-gate /* start of manifest XML template strings */
1090Sstevel@tonic-gate static const char xml_header[] =
1100Sstevel@tonic-gate "<?xml version='1.0'?>\n"
1110Sstevel@tonic-gate "<!DOCTYPE service_bundle SYSTEM "
1120Sstevel@tonic-gate "'/usr/share/lib/xml/dtd/service_bundle.dtd.1'>\n";
1130Sstevel@tonic-gate
1140Sstevel@tonic-gate static const char xml_comment[] =
1150Sstevel@tonic-gate "<!--\n"
1160Sstevel@tonic-gate " Service manifest for the %s service.\n"
1170Sstevel@tonic-gate "\n"
1180Sstevel@tonic-gate " Generated by inetconv(1M) from inetd.conf(4).\n"
1190Sstevel@tonic-gate "-->\n\n";
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate static const char xml_service_bundle[] =
1220Sstevel@tonic-gate "<service_bundle type='manifest' name='inetconv:%s'>\n\n";
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate static const char xml_service_name[] =
1250Sstevel@tonic-gate "<service\n"
1260Sstevel@tonic-gate " name='network/%s'\n"
1270Sstevel@tonic-gate " type='service'\n"
1280Sstevel@tonic-gate " version='1'>\n\n";
1290Sstevel@tonic-gate
130290Sdstaff static const char xml_dependency[] =
131290Sdstaff " <dependency\n"
132290Sdstaff " name='%s'\n"
133290Sdstaff " grouping='require_all'\n"
134290Sdstaff " restart_on='restart'\n"
135290Sdstaff " type='service'>\n"
136290Sdstaff " <service_fmri value='%s' />\n"
137290Sdstaff " </dependency>\n\n";
138290Sdstaff
1390Sstevel@tonic-gate static const char xml_instance[] =
1400Sstevel@tonic-gate " <create_default_instance enabled='true'/>\n\n";
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate static const char xml_restarter[] =
1430Sstevel@tonic-gate " <restarter>\n"
1440Sstevel@tonic-gate " <service_fmri value='%s' />\n"
1450Sstevel@tonic-gate " </restarter>\n\n";
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate static const char xml_exec_method_start[] =
1480Sstevel@tonic-gate " <!--\n"
1490Sstevel@tonic-gate " Set a timeout of 0 to signify to inetd that we don't want to\n"
1500Sstevel@tonic-gate " timeout this service, since the forked process is the one that\n"
1510Sstevel@tonic-gate " does the service's work. This is the case for most/all legacy\n"
1520Sstevel@tonic-gate " inetd services; for services written to take advantage of SMF\n"
1530Sstevel@tonic-gate " capabilities, the start method should fork off a process to\n"
1540Sstevel@tonic-gate " handle the request and return a success code.\n"
1550Sstevel@tonic-gate " -->\n"
1560Sstevel@tonic-gate " <exec_method\n"
1570Sstevel@tonic-gate " type='method'\n"
1580Sstevel@tonic-gate " name='%s'\n"
1590Sstevel@tonic-gate " %s='%s'\n"
1600Sstevel@tonic-gate " timeout_seconds='0'>\n"
1610Sstevel@tonic-gate " <method_context>\n"
1620Sstevel@tonic-gate " <method_credential %s='%s' group='%s' />\n"
1630Sstevel@tonic-gate " </method_context>\n";
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate static const char xml_arg0[] =
1660Sstevel@tonic-gate " <propval name='%s' type='astring'\n"
1670Sstevel@tonic-gate " value='%s' />\n";
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate static const char xml_exec_method_end[] =
1700Sstevel@tonic-gate " </exec_method>\n\n";
1710Sstevel@tonic-gate
1720Sstevel@tonic-gate static const char xml_exec_method_disable[] =
1730Sstevel@tonic-gate " <!--\n"
1740Sstevel@tonic-gate " Use inetd's built-in kill support to disable services.\n"
1750Sstevel@tonic-gate " -->\n"
1760Sstevel@tonic-gate " <exec_method\n"
1770Sstevel@tonic-gate " type='method'\n"
1780Sstevel@tonic-gate " name='%s'\n"
1790Sstevel@tonic-gate " %s=':kill'\n"
1800Sstevel@tonic-gate " timeout_seconds='0'>\n";
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate static const char xml_exec_method_offline[] =
1830Sstevel@tonic-gate " <!--\n"
1840Sstevel@tonic-gate " Use inetd's built-in process kill support to offline wait type\n"
1850Sstevel@tonic-gate " services.\n"
1860Sstevel@tonic-gate " -->\n"
1870Sstevel@tonic-gate " <exec_method\n"
1880Sstevel@tonic-gate " type='method'\n"
1890Sstevel@tonic-gate " name='%s'\n"
1900Sstevel@tonic-gate " %s=':kill_process'\n"
1910Sstevel@tonic-gate " timeout_seconds='0'>\n";
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate static const char xml_inetconv_group_start[] =
1940Sstevel@tonic-gate " <!--\n"
1950Sstevel@tonic-gate " This property group is used to record information about\n"
1960Sstevel@tonic-gate " how this manifest was created. It is an implementation\n"
1970Sstevel@tonic-gate " detail which should not be modified or deleted.\n"
1980Sstevel@tonic-gate " -->\n"
1990Sstevel@tonic-gate " <property_group name='%s' type='framework'>\n"
2000Sstevel@tonic-gate " <propval name='%s' type='boolean' value='%s' />\n"
2010Sstevel@tonic-gate " <propval name='%s' type='integer' value='%d' />\n"
2020Sstevel@tonic-gate " <propval name='%s' type='astring' value=\n"
2030Sstevel@tonic-gate "'%s %s %s %s %s %s%s%s'\n"
2040Sstevel@tonic-gate " />\n";
2050Sstevel@tonic-gate
2060Sstevel@tonic-gate static const char xml_property_group_start[] =
2070Sstevel@tonic-gate " <property_group name='%s' type='framework'>\n"
2080Sstevel@tonic-gate " <propval name='%s' type='astring' value='%s' />\n"
2090Sstevel@tonic-gate " <propval name='%s' type='astring' value='%s' />\n"
2100Sstevel@tonic-gate " <propval name='%s' type='astring' value='%s' />\n"
2110Sstevel@tonic-gate " <propval name='%s' type='boolean' value='%s' />\n"
2120Sstevel@tonic-gate " <propval name='%s' type='boolean' value='%s' />\n";
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate static const char xml_property_group_rpc[] =
2150Sstevel@tonic-gate " <propval name='%s' type='integer' value='%d' />\n"
2160Sstevel@tonic-gate " <propval name='%s' type='integer' value='%d' />"
2170Sstevel@tonic-gate "\n";
2180Sstevel@tonic-gate
2190Sstevel@tonic-gate static const char xml_property_group_end[] =
2200Sstevel@tonic-gate " </property_group>\n\n";
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate static const char xml_stability[] =
2230Sstevel@tonic-gate " <stability value='External' />\n\n";
2240Sstevel@tonic-gate
2250Sstevel@tonic-gate static const char xml_template[] =
2260Sstevel@tonic-gate " <template>\n"
2270Sstevel@tonic-gate " <common_name>\n"
2280Sstevel@tonic-gate " <loctext xml:lang='C'>\n"
2290Sstevel@tonic-gate "%s\n"
2300Sstevel@tonic-gate " </loctext>\n"
2310Sstevel@tonic-gate " </common_name>\n"
2320Sstevel@tonic-gate " </template>\n";
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate static const char xml_footer[] =
2350Sstevel@tonic-gate "</service>\n"
2360Sstevel@tonic-gate "\n"
2370Sstevel@tonic-gate "</service_bundle>\n";
2380Sstevel@tonic-gate /* end of manifest XML template strings */
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate static void *
safe_malloc(size_t size)2410Sstevel@tonic-gate safe_malloc(size_t size)
2420Sstevel@tonic-gate {
2430Sstevel@tonic-gate void *cp;
2440Sstevel@tonic-gate
2450Sstevel@tonic-gate if ((cp = malloc(size)) == NULL) {
2460Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: malloc failed: %s\n"),
2470Sstevel@tonic-gate progname, strerror(errno));
2480Sstevel@tonic-gate exit(EXIT_ERROR_SYS);
2490Sstevel@tonic-gate }
2500Sstevel@tonic-gate return (cp);
2510Sstevel@tonic-gate }
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate static char *
safe_strdup(char * s)2540Sstevel@tonic-gate safe_strdup(char *s)
2550Sstevel@tonic-gate {
2560Sstevel@tonic-gate char *cp;
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate if ((cp = strdup(s)) == NULL) {
2590Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: strdup failed: %s\n"),
2600Sstevel@tonic-gate progname, strerror(errno));
2610Sstevel@tonic-gate exit(EXIT_ERROR_SYS);
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate return (cp);
2640Sstevel@tonic-gate }
2650Sstevel@tonic-gate
2660Sstevel@tonic-gate static char *
propertyname(char * name,char * prefix)2670Sstevel@tonic-gate propertyname(char *name, char *prefix)
2680Sstevel@tonic-gate {
2690Sstevel@tonic-gate static char *buf;
2700Sstevel@tonic-gate size_t len;
2710Sstevel@tonic-gate int c;
2720Sstevel@tonic-gate char *cp;
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate /* free any memory allocated by a previous call */
2750Sstevel@tonic-gate free(buf);
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate len = strlen(name) + strlen(prefix) + 1;
2780Sstevel@tonic-gate buf = safe_malloc(len);
2790Sstevel@tonic-gate buf[0] = '\0';
2800Sstevel@tonic-gate
2810Sstevel@tonic-gate /*
2820Sstevel@tonic-gate * Property names must match the regular expression:
2830Sstevel@tonic-gate * ([A-Za-z][_A-Za-z0-9.-]*,)?[A-Za-z][_A-Za-z0-9-]*
2840Sstevel@tonic-gate */
2850Sstevel@tonic-gate
2860Sstevel@tonic-gate /*
2870Sstevel@tonic-gate * Make sure the first character is alphabetic, if not insert prefix.
2885404Stn143363 * Can't use isalpha() here as it's locale dependent but the property
2890Sstevel@tonic-gate * name regular expression isn't.
2900Sstevel@tonic-gate */
2910Sstevel@tonic-gate c = name[0];
2920Sstevel@tonic-gate if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z')) {
2930Sstevel@tonic-gate (void) strlcat(buf, prefix, len);
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate (void) strlcat(buf, name, len);
2960Sstevel@tonic-gate
2975404Stn143363 /* convert any disallowed characters into '_' */
2980Sstevel@tonic-gate for (cp = buf; *cp != '\0'; cp++) {
2990Sstevel@tonic-gate if ((*cp < 'A' || *cp > 'Z') && (*cp < 'a' || *cp > 'z') &&
3000Sstevel@tonic-gate (*cp < '0' || *cp > '9') && (*cp != '.') && (*cp != '-'))
3010Sstevel@tonic-gate *cp = '_';
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate return (buf);
3040Sstevel@tonic-gate }
3050Sstevel@tonic-gate
3060Sstevel@tonic-gate static char *
servicename(struct inetconfent * iconf)3070Sstevel@tonic-gate servicename(struct inetconfent *iconf)
3080Sstevel@tonic-gate {
3090Sstevel@tonic-gate static char *buf;
3100Sstevel@tonic-gate size_t len;
3115404Stn143363 char *cp, *proto;
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate /* free any memory allocated by a previous call */
3140Sstevel@tonic-gate free(buf);
3150Sstevel@tonic-gate
3160Sstevel@tonic-gate len = strlen(iconf->service) + strlen(iconf->protocol) +
3170Sstevel@tonic-gate sizeof ("rpc-/visible");
3180Sstevel@tonic-gate buf = safe_malloc(len);
3190Sstevel@tonic-gate
3200Sstevel@tonic-gate /*
3210Sstevel@tonic-gate * Combine the service and protocol fields to produce a unique
3220Sstevel@tonic-gate * manifest service name. The syntax of a service name is:
3230Sstevel@tonic-gate * prop(/prop)*
3240Sstevel@tonic-gate */
3250Sstevel@tonic-gate (void) strlcpy(buf, propertyname(iconf->service,
3260Sstevel@tonic-gate iconf->isrpc ? "rpc-": "s-"), len);
3270Sstevel@tonic-gate (void) strlcat(buf, "/", len);
3280Sstevel@tonic-gate
3290Sstevel@tonic-gate proto = iconf->protocol;
3300Sstevel@tonic-gate if (iconf->isrpc && (strcmp(iconf->protocol, "rpc/*") == 0))
3310Sstevel@tonic-gate proto = "rpc/visible";
3325404Stn143363
3335404Stn143363 /*
3345404Stn143363 * SMF service names may not contain '.', but IANA services do
3355404Stn143363 * allow its use, and property names can contain '.' as returned
3365404Stn143363 * by propertyname(). So if the resultant SMF service name
3375404Stn143363 * would contain a '.' we fix it here.
3385404Stn143363 */
3395404Stn143363 for (cp = buf; *cp != '\0'; cp++) {
3405404Stn143363 if (*cp == '.')
3415404Stn143363 *cp = '_';
3425404Stn143363 }
3430Sstevel@tonic-gate (void) strlcat(buf, propertyname(proto, "p-"), len);
3440Sstevel@tonic-gate return (buf);
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate static boolean_t
is_v6only(char * protocol)3480Sstevel@tonic-gate is_v6only(char *protocol)
3490Sstevel@tonic-gate {
3500Sstevel@tonic-gate /* returns true if protocol is an IPv6 only protocol */
3510Sstevel@tonic-gate if ((strcmp(protocol, SOCKET_PROTO_TCP6_ONLY) == 0) ||
3520Sstevel@tonic-gate (strcmp(protocol, SOCKET_PROTO_UDP6_ONLY) == 0))
3530Sstevel@tonic-gate return (B_TRUE);
3540Sstevel@tonic-gate return (B_FALSE);
3550Sstevel@tonic-gate }
3560Sstevel@tonic-gate
3570Sstevel@tonic-gate static char *
invalid_props(inetd_prop_t * p)3580Sstevel@tonic-gate invalid_props(inetd_prop_t *p)
3590Sstevel@tonic-gate {
3600Sstevel@tonic-gate static char
3610Sstevel@tonic-gate buf[sizeof (" service-name endpoint-type protocol wait-status")];
3620Sstevel@tonic-gate
3630Sstevel@tonic-gate buf[0] = '\0';
3640Sstevel@tonic-gate if ((p[PT_SVC_NAME_INDEX].ip_error == IVE_INVALID) ||
3650Sstevel@tonic-gate (p[PT_SVC_NAME_INDEX].ip_error == IVE_UNSET) ||
3660Sstevel@tonic-gate (p[PT_RPC_LW_VER_INDEX].ip_error == IVE_INVALID) ||
3670Sstevel@tonic-gate (p[PT_RPC_HI_VER_INDEX].ip_error == IVE_INVALID))
3680Sstevel@tonic-gate (void) strlcat(buf, " service-name", sizeof (buf));
3690Sstevel@tonic-gate if ((p[PT_SOCK_TYPE_INDEX].ip_error == IVE_INVALID) ||
3700Sstevel@tonic-gate (p[PT_SOCK_TYPE_INDEX].ip_error == IVE_UNSET))
3710Sstevel@tonic-gate (void) strlcat(buf, " endpoint-type", sizeof (buf));
3720Sstevel@tonic-gate if ((p[PT_PROTO_INDEX].ip_error == IVE_INVALID) ||
3730Sstevel@tonic-gate (p[PT_PROTO_INDEX].ip_error == IVE_UNSET) ||
3740Sstevel@tonic-gate (p[PT_ISRPC_INDEX].ip_error == IVE_INVALID))
3750Sstevel@tonic-gate (void) strlcat(buf, " protocol", sizeof (buf));
3760Sstevel@tonic-gate if (p[PT_ISWAIT_INDEX].ip_error == IVE_INVALID)
3770Sstevel@tonic-gate (void) strlcat(buf, " wait-status", sizeof (buf));
3780Sstevel@tonic-gate return (buf);
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate
3810Sstevel@tonic-gate static boolean_t
valid_basic_properties(struct inetconfent * iconf,struct fileinfo * finfo)3820Sstevel@tonic-gate valid_basic_properties(struct inetconfent *iconf, struct fileinfo *finfo)
3830Sstevel@tonic-gate {
3840Sstevel@tonic-gate size_t prop_size;
3850Sstevel@tonic-gate inetd_prop_t *prop, *inetd_properties;
3860Sstevel@tonic-gate boolean_t valid = B_TRUE;
3870Sstevel@tonic-gate char *proto = iconf->protocol;
3880Sstevel@tonic-gate char *svc_name = iconf->service;
3890Sstevel@tonic-gate
3900Sstevel@tonic-gate inetd_properties = get_prop_table(&prop_size);
3910Sstevel@tonic-gate prop = safe_malloc(prop_size * sizeof (inetd_prop_t));
3920Sstevel@tonic-gate (void) memcpy(prop, inetd_properties,
3930Sstevel@tonic-gate prop_size * sizeof (inetd_prop_t));
3940Sstevel@tonic-gate
3951293Smh138676 put_prop_value_boolean(prop, PR_ISRPC_NAME, iconf->isrpc);
3961293Smh138676 put_prop_value_boolean(prop, PR_ISWAIT_NAME, iconf->wait);
3970Sstevel@tonic-gate if (iconf->isrpc) {
3981293Smh138676 put_prop_value_int(prop, PR_RPC_LW_VER_NAME,
3991293Smh138676 iconf->rpc_low_version);
4001293Smh138676 put_prop_value_int(prop, PR_RPC_HI_VER_NAME,
4011293Smh138676 iconf->rpc_high_version);
4020Sstevel@tonic-gate svc_name = iconf->rpc_prog;
4030Sstevel@tonic-gate proto += 4; /* skip 'rpc/' */
4040Sstevel@tonic-gate }
4050Sstevel@tonic-gate
4061293Smh138676 if (!put_prop_value_string(prop, PR_SOCK_TYPE_NAME, iconf->endpoint) ||
4071293Smh138676 !put_prop_value_string(prop, PR_SVC_NAME_NAME, svc_name)) {
4080Sstevel@tonic-gate valid = B_FALSE;
4090Sstevel@tonic-gate
4101293Smh138676 if (errno == ENOMEM) {
4111293Smh138676 (void) fprintf(stderr,
4121293Smh138676 gettext("%s: failed to allocate memory: %s\n"),
4131293Smh138676 progname, strerror(errno));
4141293Smh138676 exit(EXIT_ERROR_SYS);
4151293Smh138676 }
4161293Smh138676 }
4171293Smh138676
4181293Smh138676 put_prop_value_string_list(prop, PR_PROTO_NAME, get_protos(proto));
4191293Smh138676
4200Sstevel@tonic-gate if (!valid_props(prop, NULL, NULL, NULL, NULL) || !valid) {
4210Sstevel@tonic-gate valid = B_FALSE;
4220Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error %s line %d "
4230Sstevel@tonic-gate "invalid or inconsistent fields:%s\n"), progname,
4240Sstevel@tonic-gate finfo->filename, finfo->lineno,
4250Sstevel@tonic-gate invalid_props(prop));
4260Sstevel@tonic-gate }
4270Sstevel@tonic-gate
4280Sstevel@tonic-gate free_instance_props(prop);
4290Sstevel@tonic-gate return (valid);
4300Sstevel@tonic-gate }
4310Sstevel@tonic-gate
4320Sstevel@tonic-gate static boolean_t
valid_inetconfent(struct inetconfent * iconf,struct fileinfo * finfo)4330Sstevel@tonic-gate valid_inetconfent(struct inetconfent *iconf, struct fileinfo *finfo)
4340Sstevel@tonic-gate {
4350Sstevel@tonic-gate boolean_t valid = B_TRUE;
4360Sstevel@tonic-gate size_t len;
4370Sstevel@tonic-gate char *cp, *endp;
4380Sstevel@tonic-gate struct passwd *pwd;
4390Sstevel@tonic-gate struct group *grp;
4400Sstevel@tonic-gate struct stat statb;
4410Sstevel@tonic-gate char *proto = iconf->protocol;
4420Sstevel@tonic-gate
4430Sstevel@tonic-gate iconf->isrpc = B_FALSE;
4440Sstevel@tonic-gate if (strncmp(iconf->protocol, "rpc/", 4) == 0) {
4450Sstevel@tonic-gate iconf->isrpc = B_TRUE;
4460Sstevel@tonic-gate iconf->rpc_prog = safe_strdup(iconf->service);
4470Sstevel@tonic-gate
4480Sstevel@tonic-gate /* set RPC version numbers */
4490Sstevel@tonic-gate iconf->rpc_low_version = 1;
4500Sstevel@tonic-gate iconf->rpc_high_version = 1;
4510Sstevel@tonic-gate if ((cp = strrchr(iconf->rpc_prog, '/')) != NULL) {
4520Sstevel@tonic-gate *cp = '\0';
4530Sstevel@tonic-gate if (*++cp != '\0') {
4540Sstevel@tonic-gate errno = 0;
4550Sstevel@tonic-gate iconf->rpc_low_version = strtol(cp, &endp, 10);
4560Sstevel@tonic-gate if (errno != 0)
4570Sstevel@tonic-gate goto vererr;
4580Sstevel@tonic-gate cp = endp;
4590Sstevel@tonic-gate if (*cp == '-') {
4600Sstevel@tonic-gate if (*++cp == '\0')
4610Sstevel@tonic-gate goto vererr;
4620Sstevel@tonic-gate errno = 0;
4630Sstevel@tonic-gate iconf->rpc_high_version = strtol(cp,
4640Sstevel@tonic-gate &endp, 10);
4650Sstevel@tonic-gate if ((errno != 0) || (*endp != '\0'))
4660Sstevel@tonic-gate goto vererr;
4670Sstevel@tonic-gate } else if (*cp == '\0') {
4680Sstevel@tonic-gate iconf->rpc_high_version =
4690Sstevel@tonic-gate iconf->rpc_low_version;
4700Sstevel@tonic-gate } else {
4710Sstevel@tonic-gate vererr:
4720Sstevel@tonic-gate (void) fprintf(stderr, gettext(
4730Sstevel@tonic-gate "%s: Error %s line %d invalid RPC "
4740Sstevel@tonic-gate "version in service: %s\n"),
4750Sstevel@tonic-gate progname, finfo->filename,
4760Sstevel@tonic-gate finfo->lineno, iconf->service);
4770Sstevel@tonic-gate valid = B_FALSE;
4780Sstevel@tonic-gate }
4790Sstevel@tonic-gate }
4800Sstevel@tonic-gate }
4810Sstevel@tonic-gate proto += 4; /* skip 'rpc/' */
4820Sstevel@tonic-gate }
4830Sstevel@tonic-gate /* tcp6only and udp6only are not valid in inetd.conf */
4840Sstevel@tonic-gate if (is_v6only(proto)) {
4850Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error %s line %d "
4860Sstevel@tonic-gate "invalid protocol: %s\n"), progname,
4870Sstevel@tonic-gate finfo->filename, finfo->lineno, proto);
4880Sstevel@tonic-gate valid = B_FALSE;
4890Sstevel@tonic-gate }
4900Sstevel@tonic-gate
4910Sstevel@tonic-gate if (strcmp(iconf->wait_status, "wait") == 0) {
4920Sstevel@tonic-gate iconf->wait = B_TRUE;
4930Sstevel@tonic-gate } else if (strcmp(iconf->wait_status, "nowait") == 0) {
4940Sstevel@tonic-gate iconf->wait = B_FALSE;
4950Sstevel@tonic-gate } else {
4960Sstevel@tonic-gate (void) fprintf(stderr,
4970Sstevel@tonic-gate gettext("%s: Error %s line %d invalid wait-status: %s\n"),
4980Sstevel@tonic-gate progname, finfo->filename, finfo->lineno,
4990Sstevel@tonic-gate iconf->wait_status);
5000Sstevel@tonic-gate valid = B_FALSE;
5010Sstevel@tonic-gate }
5020Sstevel@tonic-gate
5030Sstevel@tonic-gate /* look up the username to set the groupname */
5040Sstevel@tonic-gate if ((pwd = getpwnam(iconf->username)) == NULL) {
5050Sstevel@tonic-gate (void) fprintf(stderr,
5060Sstevel@tonic-gate gettext("%s: Error %s line %d unknown user: %s\n"),
5070Sstevel@tonic-gate progname, finfo->filename, finfo->lineno,
5080Sstevel@tonic-gate iconf->username);
5090Sstevel@tonic-gate valid = B_FALSE;
5100Sstevel@tonic-gate } else {
5110Sstevel@tonic-gate if ((grp = getgrgid(pwd->pw_gid)) != NULL) {
5120Sstevel@tonic-gate iconf->groupname = safe_strdup(grp->gr_name);
5130Sstevel@tonic-gate } else {
5140Sstevel@tonic-gate /* use the group ID if no groupname */
5150Sstevel@tonic-gate char s[1];
5160Sstevel@tonic-gate
5170Sstevel@tonic-gate len = snprintf(s, 1, "%d", pwd->pw_gid) + 1;
5180Sstevel@tonic-gate iconf->groupname = safe_malloc(len);
5190Sstevel@tonic-gate (void) snprintf(iconf->groupname, len, "%d",
5200Sstevel@tonic-gate pwd->pw_gid);
5210Sstevel@tonic-gate }
5220Sstevel@tonic-gate }
5230Sstevel@tonic-gate
5240Sstevel@tonic-gate /* check for internal services */
5250Sstevel@tonic-gate if (strcmp(iconf->server_program, "internal") == 0) {
5260Sstevel@tonic-gate valid = B_FALSE;
5270Sstevel@tonic-gate if ((strcmp(iconf->service, "echo") == 0) ||
5280Sstevel@tonic-gate (strcmp(iconf->service, "discard") == 0) ||
5290Sstevel@tonic-gate (strcmp(iconf->service, "time") == 0) ||
5300Sstevel@tonic-gate (strcmp(iconf->service, "daytime") == 0) ||
5310Sstevel@tonic-gate (strcmp(iconf->service, "chargen") == 0)) {
5320Sstevel@tonic-gate (void) fprintf(stderr, gettext(
5330Sstevel@tonic-gate "%s: Error %s line %d the SUNWcnsr and SUNWcnsu"
5340Sstevel@tonic-gate " packages contain the internal services\n"),
5350Sstevel@tonic-gate progname, finfo->filename, finfo->lineno);
5360Sstevel@tonic-gate } else {
5370Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error %s line %d "
5380Sstevel@tonic-gate "unknown internal service: %s\n"), progname,
5390Sstevel@tonic-gate finfo->filename, finfo->lineno, iconf->service);
5400Sstevel@tonic-gate }
5410Sstevel@tonic-gate } else if ((stat(iconf->server_program, &statb) == -1) &&
5420Sstevel@tonic-gate (errno == ENOENT)) {
5430Sstevel@tonic-gate (void) fprintf(stderr, gettext(
5440Sstevel@tonic-gate "%s: Error %s line %d server-program not found: %s\n"),
5450Sstevel@tonic-gate progname, finfo->filename, finfo->lineno,
5460Sstevel@tonic-gate iconf->server_program);
5470Sstevel@tonic-gate valid = B_FALSE;
5480Sstevel@tonic-gate }
5490Sstevel@tonic-gate
5500Sstevel@tonic-gate return (valid && valid_basic_properties(iconf, finfo));
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate
5530Sstevel@tonic-gate static void
free_inetconfent(struct inetconfent * iconf)5540Sstevel@tonic-gate free_inetconfent(struct inetconfent *iconf)
5550Sstevel@tonic-gate {
5560Sstevel@tonic-gate if (iconf == NULL)
5570Sstevel@tonic-gate return;
5580Sstevel@tonic-gate
5590Sstevel@tonic-gate free(iconf->service);
5600Sstevel@tonic-gate free(iconf->endpoint);
5610Sstevel@tonic-gate free(iconf->protocol);
5620Sstevel@tonic-gate free(iconf->wait_status);
5630Sstevel@tonic-gate free(iconf->username);
5640Sstevel@tonic-gate free(iconf->server_program);
5650Sstevel@tonic-gate free(iconf->server_args);
5660Sstevel@tonic-gate free(iconf->rpc_prog);
5670Sstevel@tonic-gate free(iconf->groupname);
5680Sstevel@tonic-gate free(iconf->exec);
5690Sstevel@tonic-gate free(iconf->arg0);
5700Sstevel@tonic-gate
5710Sstevel@tonic-gate free(iconf);
5720Sstevel@tonic-gate }
5730Sstevel@tonic-gate
5740Sstevel@tonic-gate static struct inetconfent *
line_to_inetconfent(char * line)5750Sstevel@tonic-gate line_to_inetconfent(char *line)
5760Sstevel@tonic-gate {
5770Sstevel@tonic-gate char *cp;
5780Sstevel@tonic-gate struct inetconfent *iconf;
5790Sstevel@tonic-gate
5800Sstevel@tonic-gate iconf = safe_malloc(sizeof (struct inetconfent));
5810Sstevel@tonic-gate (void) memset(iconf, 0, sizeof (struct inetconfent));
5820Sstevel@tonic-gate
5830Sstevel@tonic-gate if ((cp = strtok(line, " \t\n")) == NULL)
5840Sstevel@tonic-gate goto fail;
5850Sstevel@tonic-gate iconf->service = safe_strdup(cp);
5860Sstevel@tonic-gate
5870Sstevel@tonic-gate if ((cp = strtok(NULL, " \t\n")) == NULL)
5880Sstevel@tonic-gate goto fail;
5890Sstevel@tonic-gate iconf->endpoint = safe_strdup(cp);
5900Sstevel@tonic-gate
5910Sstevel@tonic-gate if ((cp = strtok(NULL, " \t\n")) == NULL)
5920Sstevel@tonic-gate goto fail;
5930Sstevel@tonic-gate iconf->protocol = safe_strdup(cp);
5940Sstevel@tonic-gate
5950Sstevel@tonic-gate if ((cp = strtok(NULL, " \t\n")) == NULL)
5960Sstevel@tonic-gate goto fail;
5970Sstevel@tonic-gate iconf->wait_status = safe_strdup(cp);
5980Sstevel@tonic-gate
5990Sstevel@tonic-gate if ((cp = strtok(NULL, " \t\n")) == NULL)
6000Sstevel@tonic-gate goto fail;
6010Sstevel@tonic-gate iconf->username = safe_strdup(cp);
6020Sstevel@tonic-gate
6030Sstevel@tonic-gate if ((cp = strtok(NULL, " \t\n")) == NULL)
6040Sstevel@tonic-gate goto fail;
6050Sstevel@tonic-gate iconf->server_program = safe_strdup(cp);
6060Sstevel@tonic-gate
6070Sstevel@tonic-gate /* last field is optional */
6080Sstevel@tonic-gate if ((cp = strtok(NULL, "\n")) != NULL)
6090Sstevel@tonic-gate iconf->server_args = safe_strdup(cp);
6100Sstevel@tonic-gate
6110Sstevel@tonic-gate /* Combine args and server name to construct exec and args fields */
6120Sstevel@tonic-gate if (iconf->server_args == NULL) {
6130Sstevel@tonic-gate iconf->exec = safe_strdup(iconf->server_program);
6140Sstevel@tonic-gate } else {
6150Sstevel@tonic-gate int len;
6160Sstevel@tonic-gate char *args, *endp;
6170Sstevel@tonic-gate
6180Sstevel@tonic-gate len = strlen(iconf->server_program) +
6190Sstevel@tonic-gate strlen(iconf->server_args) + 1;
6200Sstevel@tonic-gate iconf->exec = safe_malloc(len);
6210Sstevel@tonic-gate (void) strlcpy(iconf->exec, iconf->server_program, len);
6220Sstevel@tonic-gate
6230Sstevel@tonic-gate args = safe_strdup(iconf->server_args);
6240Sstevel@tonic-gate if ((cp = strtok(args, " \t")) != NULL) {
6250Sstevel@tonic-gate if ((endp = strrchr(iconf->exec, '/')) == NULL)
6260Sstevel@tonic-gate endp = iconf->exec;
6270Sstevel@tonic-gate else
6280Sstevel@tonic-gate endp++;
6290Sstevel@tonic-gate /* only set arg0 property value if needed */
6300Sstevel@tonic-gate if (strcmp(endp, cp) != 0)
6310Sstevel@tonic-gate iconf->arg0 = safe_strdup(cp);
6320Sstevel@tonic-gate while ((cp = strtok(NULL, " \t")) != NULL) {
6330Sstevel@tonic-gate (void) strlcat(iconf->exec, " ", len);
6340Sstevel@tonic-gate (void) strlcat(iconf->exec, cp, len);
6350Sstevel@tonic-gate }
6360Sstevel@tonic-gate }
6370Sstevel@tonic-gate free(args);
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate
6400Sstevel@tonic-gate return (iconf);
6410Sstevel@tonic-gate fail:
6420Sstevel@tonic-gate free_inetconfent(iconf);
6430Sstevel@tonic-gate return (NULL);
6440Sstevel@tonic-gate }
6450Sstevel@tonic-gate
6460Sstevel@tonic-gate static void
skipline(FILE * fp)6470Sstevel@tonic-gate skipline(FILE *fp)
6480Sstevel@tonic-gate {
6490Sstevel@tonic-gate int c;
6500Sstevel@tonic-gate
6510Sstevel@tonic-gate /* skip remainder of a line */
6520Sstevel@tonic-gate while (((c = getc(fp)) != EOF) && (c != '\n'))
6530Sstevel@tonic-gate ;
6540Sstevel@tonic-gate }
6550Sstevel@tonic-gate
6560Sstevel@tonic-gate static struct inetconfent *
fgetinetconfent(struct fileinfo * finfo,boolean_t validate)6570Sstevel@tonic-gate fgetinetconfent(struct fileinfo *finfo, boolean_t validate)
6580Sstevel@tonic-gate {
6590Sstevel@tonic-gate char *cp;
6600Sstevel@tonic-gate struct inetconfent *iconf;
6610Sstevel@tonic-gate char line[MAX_SRC_LINELEN];
6620Sstevel@tonic-gate
6630Sstevel@tonic-gate while (fgets(line, sizeof (line), finfo->fp) != NULL) {
6640Sstevel@tonic-gate finfo->lineno++;
6650Sstevel@tonic-gate
6660Sstevel@tonic-gate /* skip empty or commented out lines */
6670Sstevel@tonic-gate if (*line == '\n')
6680Sstevel@tonic-gate continue;
6690Sstevel@tonic-gate if (*line == '#') {
6700Sstevel@tonic-gate if (line[strlen(line) - 1] != '\n')
6710Sstevel@tonic-gate skipline(finfo->fp);
6720Sstevel@tonic-gate continue;
6730Sstevel@tonic-gate }
6740Sstevel@tonic-gate /* check for lines which are too long */
6750Sstevel@tonic-gate if (line[strlen(line) - 1] != '\n') {
6760Sstevel@tonic-gate (void) fprintf(stderr,
6770Sstevel@tonic-gate gettext("%s: Error %s line %d too long, skipped\n"),
6780Sstevel@tonic-gate progname, finfo->filename, finfo->lineno);
6790Sstevel@tonic-gate skipline(finfo->fp);
6800Sstevel@tonic-gate finfo->failcnt++;
6810Sstevel@tonic-gate continue;
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate /* remove in line comments and newline character */
6840Sstevel@tonic-gate if ((cp = strchr(line, '#')) == NULL)
6850Sstevel@tonic-gate cp = strchr(line, '\n');
6860Sstevel@tonic-gate if (cp)
6870Sstevel@tonic-gate *cp = '\0';
6880Sstevel@tonic-gate
6890Sstevel@tonic-gate if ((iconf = line_to_inetconfent(line)) == NULL) {
6900Sstevel@tonic-gate (void) fprintf(stderr, gettext(
6910Sstevel@tonic-gate "%s: Error %s line %d too few fields, skipped\n"),
6920Sstevel@tonic-gate progname, finfo->filename, finfo->lineno);
6930Sstevel@tonic-gate finfo->failcnt++;
6940Sstevel@tonic-gate continue;
6950Sstevel@tonic-gate }
6960Sstevel@tonic-gate
6970Sstevel@tonic-gate if (!validate || valid_inetconfent(iconf, finfo))
6980Sstevel@tonic-gate return (iconf);
6990Sstevel@tonic-gate
7000Sstevel@tonic-gate finfo->failcnt++;
7010Sstevel@tonic-gate free_inetconfent(iconf);
7020Sstevel@tonic-gate }
7030Sstevel@tonic-gate return (NULL);
7040Sstevel@tonic-gate }
7050Sstevel@tonic-gate
7060Sstevel@tonic-gate static char *
boolstr(boolean_t val)7070Sstevel@tonic-gate boolstr(boolean_t val)
7080Sstevel@tonic-gate {
7090Sstevel@tonic-gate if (val)
7100Sstevel@tonic-gate return ("true");
7110Sstevel@tonic-gate return ("false");
7120Sstevel@tonic-gate }
7130Sstevel@tonic-gate
7140Sstevel@tonic-gate static int
print_manifest(FILE * f,char * filename,struct inetconfent * iconf)7150Sstevel@tonic-gate print_manifest(FILE *f, char *filename, struct inetconfent *iconf)
7160Sstevel@tonic-gate {
7170Sstevel@tonic-gate if (fprintf(f, xml_header) < 0)
7180Sstevel@tonic-gate goto print_err;
7190Sstevel@tonic-gate
7200Sstevel@tonic-gate if (fprintf(f, xml_comment,
7210Sstevel@tonic-gate iconf->isrpc ? iconf->rpc_prog : iconf->service) < 0)
7220Sstevel@tonic-gate goto print_err;
7230Sstevel@tonic-gate
7240Sstevel@tonic-gate if (fprintf(f, xml_service_bundle, iconf->service) < 0)
7250Sstevel@tonic-gate goto print_err;
7260Sstevel@tonic-gate if (fprintf(f, xml_service_name, servicename(iconf)) < 0)
7270Sstevel@tonic-gate goto print_err;
7280Sstevel@tonic-gate if (fprintf(f, xml_instance) < 0)
7290Sstevel@tonic-gate goto print_err;
7300Sstevel@tonic-gate if (fprintf(f, xml_restarter, INETD_INSTANCE_FMRI) < 0)
7310Sstevel@tonic-gate goto print_err;
732290Sdstaff if (iconf->isrpc) {
733290Sdstaff if (fprintf(f, xml_dependency, "rpcbind", RPCBIND_FMRI) < 0)
734290Sdstaff goto print_err;
735290Sdstaff }
7360Sstevel@tonic-gate
7370Sstevel@tonic-gate if (fprintf(f, xml_exec_method_start, START_METHOD_NAME, PR_EXEC_NAME,
7380Sstevel@tonic-gate iconf->exec, PR_USER_NAME, iconf->username, iconf->groupname) < 0)
7390Sstevel@tonic-gate goto print_err;
7400Sstevel@tonic-gate if (iconf->arg0 != NULL) {
7410Sstevel@tonic-gate if (fprintf(f, xml_arg0, PR_ARG0_NAME, iconf->arg0) < 0)
7420Sstevel@tonic-gate goto print_err;
7430Sstevel@tonic-gate }
7440Sstevel@tonic-gate if (fprintf(f, xml_exec_method_end) < 0)
7450Sstevel@tonic-gate goto print_err;
7460Sstevel@tonic-gate
7470Sstevel@tonic-gate if (fprintf(f, xml_exec_method_disable, DISABLE_METHOD_NAME,
7480Sstevel@tonic-gate PR_EXEC_NAME) < 0)
7490Sstevel@tonic-gate goto print_err;
7500Sstevel@tonic-gate if (fprintf(f, xml_exec_method_end) < 0)
7510Sstevel@tonic-gate goto print_err;
7520Sstevel@tonic-gate
7530Sstevel@tonic-gate if (iconf->wait) {
7540Sstevel@tonic-gate if (fprintf(f, xml_exec_method_offline, OFFLINE_METHOD_NAME,
7550Sstevel@tonic-gate PR_EXEC_NAME) < 0)
7560Sstevel@tonic-gate goto print_err;
7570Sstevel@tonic-gate if (fprintf(f, xml_exec_method_end) < 0)
7580Sstevel@tonic-gate goto print_err;
7590Sstevel@tonic-gate }
7600Sstevel@tonic-gate
7610Sstevel@tonic-gate if (fprintf(f, xml_inetconv_group_start, PG_NAME_INETCONV,
7620Sstevel@tonic-gate PR_AUTO_CONVERTED_NAME, boolstr(B_TRUE),
7630Sstevel@tonic-gate PR_VERSION_NAME, INETCONV_VERSION,
7640Sstevel@tonic-gate PR_SOURCE_LINE_NAME, iconf->service,
7650Sstevel@tonic-gate iconf->endpoint, iconf->protocol, iconf->wait_status,
7660Sstevel@tonic-gate iconf->username, iconf->server_program,
7670Sstevel@tonic-gate iconf->server_args == NULL ? "" : " ",
7680Sstevel@tonic-gate iconf->server_args == NULL ? "" : iconf->server_args) < 0)
7690Sstevel@tonic-gate goto print_err;
7700Sstevel@tonic-gate if (fprintf(f, xml_property_group_end) < 0)
7710Sstevel@tonic-gate goto print_err;
7720Sstevel@tonic-gate
7730Sstevel@tonic-gate if (fprintf(f, xml_property_group_start, PG_NAME_SERVICE_CONFIG,
7740Sstevel@tonic-gate PR_SVC_NAME_NAME, iconf->isrpc ? iconf->rpc_prog : iconf->service,
7750Sstevel@tonic-gate PR_SOCK_TYPE_NAME, iconf->endpoint,
7760Sstevel@tonic-gate PR_PROTO_NAME, iconf->isrpc ? iconf->protocol + 4 :
7770Sstevel@tonic-gate iconf->protocol,
7780Sstevel@tonic-gate PR_ISWAIT_NAME, boolstr(iconf->wait),
7790Sstevel@tonic-gate PR_ISRPC_NAME, boolstr(iconf->isrpc)) < 0)
7800Sstevel@tonic-gate goto print_err;
7810Sstevel@tonic-gate if (iconf->isrpc) {
7820Sstevel@tonic-gate if (fprintf(f, xml_property_group_rpc,
7830Sstevel@tonic-gate PR_RPC_LW_VER_NAME, iconf->rpc_low_version,
7840Sstevel@tonic-gate PR_RPC_HI_VER_NAME, iconf->rpc_high_version) < 0)
7850Sstevel@tonic-gate goto print_err;
7860Sstevel@tonic-gate }
7870Sstevel@tonic-gate if (fprintf(f, xml_property_group_end) < 0)
7880Sstevel@tonic-gate goto print_err;
7890Sstevel@tonic-gate
7900Sstevel@tonic-gate if (fprintf(f, xml_stability) < 0)
7910Sstevel@tonic-gate goto print_err;
7920Sstevel@tonic-gate if (fprintf(f, xml_template,
7930Sstevel@tonic-gate iconf->isrpc ? iconf->rpc_prog : iconf->service) < 0)
7940Sstevel@tonic-gate goto print_err;
7950Sstevel@tonic-gate if (fprintf(f, xml_footer) < 0)
7960Sstevel@tonic-gate goto print_err;
7970Sstevel@tonic-gate
7980Sstevel@tonic-gate (void) printf("%s -> %s\n", iconf->service, filename);
7990Sstevel@tonic-gate return (0);
8000Sstevel@tonic-gate
8010Sstevel@tonic-gate print_err:
8020Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error writing manifest %s: %s\n"),
8030Sstevel@tonic-gate progname, filename, strerror(errno));
8040Sstevel@tonic-gate return (-1);
8050Sstevel@tonic-gate }
8060Sstevel@tonic-gate
8070Sstevel@tonic-gate static struct fileinfo *
open_srcfile(char * filename)8080Sstevel@tonic-gate open_srcfile(char *filename)
8090Sstevel@tonic-gate {
8100Sstevel@tonic-gate struct fileinfo *finfo = NULL;
8110Sstevel@tonic-gate FILE *fp;
8120Sstevel@tonic-gate
8130Sstevel@tonic-gate if (filename != NULL) {
8140Sstevel@tonic-gate if ((fp = fopen(filename, "r")) == NULL) {
8150Sstevel@tonic-gate (void) fprintf(stderr,
8160Sstevel@tonic-gate gettext("%s: Error opening %s: %s\n"),
8170Sstevel@tonic-gate progname, filename, strerror(errno));
8180Sstevel@tonic-gate }
8190Sstevel@tonic-gate } else {
8200Sstevel@tonic-gate /*
8210Sstevel@tonic-gate * If no source file specified, do the same as inetd and first
8220Sstevel@tonic-gate * try /etc/inet/inetd.conf, followed by /etc/inetd.conf.
8230Sstevel@tonic-gate */
8240Sstevel@tonic-gate filename = MAIN_CONFIG;
8250Sstevel@tonic-gate if ((fp = fopen(filename, "r")) == NULL) {
8260Sstevel@tonic-gate (void) fprintf(stderr,
8270Sstevel@tonic-gate gettext("%s: Error opening %s: %s\n"),
8280Sstevel@tonic-gate progname, filename, strerror(errno));
8290Sstevel@tonic-gate filename = ALT_CONFIG;
8300Sstevel@tonic-gate if ((fp = fopen(filename, "r")) == NULL) {
8310Sstevel@tonic-gate (void) fprintf(stderr, gettext(
8320Sstevel@tonic-gate "%s: Error opening %s: %s\n"), progname,
8330Sstevel@tonic-gate filename, strerror(errno));
8340Sstevel@tonic-gate }
8350Sstevel@tonic-gate }
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate if (fp != NULL) {
8380Sstevel@tonic-gate finfo = safe_malloc(sizeof (struct fileinfo));
8390Sstevel@tonic-gate finfo->fp = fp;
8400Sstevel@tonic-gate finfo->filename = filename;
8410Sstevel@tonic-gate finfo->lineno = 0;
8420Sstevel@tonic-gate finfo->failcnt = 0;
8430Sstevel@tonic-gate (void) fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
8440Sstevel@tonic-gate }
8450Sstevel@tonic-gate return (finfo);
8460Sstevel@tonic-gate }
8470Sstevel@tonic-gate
8480Sstevel@tonic-gate /*
8490Sstevel@tonic-gate * Opens manifest output file. Returns 0 on success, -1 if the file
8500Sstevel@tonic-gate * exists, -2 on other errors.
8510Sstevel@tonic-gate */
8520Sstevel@tonic-gate static int
open_dstfile(char * destdir,boolean_t overwrite,struct inetconfent * iconf,struct fileinfo ** finfo)8530Sstevel@tonic-gate open_dstfile(
8540Sstevel@tonic-gate char *destdir,
8550Sstevel@tonic-gate boolean_t overwrite,
8560Sstevel@tonic-gate struct inetconfent *iconf,
8570Sstevel@tonic-gate struct fileinfo **finfo)
8580Sstevel@tonic-gate {
8590Sstevel@tonic-gate int fd;
8600Sstevel@tonic-gate size_t len;
8610Sstevel@tonic-gate char *dstfile, *cp, *proto;
8620Sstevel@tonic-gate FILE *fp;
8630Sstevel@tonic-gate
8640Sstevel@tonic-gate /* if no destdir specified, use appropriate default */
8650Sstevel@tonic-gate if (destdir == NULL) {
8660Sstevel@tonic-gate if (iconf->isrpc)
8670Sstevel@tonic-gate destdir = MANIFEST_RPC_DIR;
8680Sstevel@tonic-gate else
8690Sstevel@tonic-gate destdir = MANIFEST_DIR;
8700Sstevel@tonic-gate }
8710Sstevel@tonic-gate
8720Sstevel@tonic-gate len = strlen(destdir) + strlen(iconf->service) +
8730Sstevel@tonic-gate strlen(iconf->protocol) + sizeof ("/-visible.xml");
8740Sstevel@tonic-gate dstfile = safe_malloc(len);
8750Sstevel@tonic-gate
8760Sstevel@tonic-gate (void) strlcpy(dstfile, destdir, len);
8770Sstevel@tonic-gate if (dstfile[strlen(dstfile) - 1] != '/')
8780Sstevel@tonic-gate (void) strlcat(dstfile, "/", len);
8790Sstevel@tonic-gate cp = dstfile + strlen(dstfile);
8800Sstevel@tonic-gate
8810Sstevel@tonic-gate (void) strlcat(dstfile, iconf->service, len);
8820Sstevel@tonic-gate (void) strlcat(dstfile, "-", len);
8830Sstevel@tonic-gate
8840Sstevel@tonic-gate proto = iconf->protocol;
8850Sstevel@tonic-gate if (iconf->isrpc && (strcmp(iconf->protocol, "rpc/*") == 0))
8860Sstevel@tonic-gate proto = "rpc/visible";
8870Sstevel@tonic-gate
8880Sstevel@tonic-gate (void) strlcat(dstfile, proto, len);
8890Sstevel@tonic-gate (void) strlcat(dstfile, ".xml", len);
8900Sstevel@tonic-gate
8910Sstevel@tonic-gate /* convert any '/' chars in service or protocol to '_' chars */
8920Sstevel@tonic-gate while ((cp = strchr(cp, '/')) != NULL)
8930Sstevel@tonic-gate *cp = '_';
8940Sstevel@tonic-gate
8950Sstevel@tonic-gate fd = open(dstfile, O_WRONLY|O_CREAT|(overwrite ? O_TRUNC : O_EXCL),
8960Sstevel@tonic-gate 0644);
8970Sstevel@tonic-gate if (fd == -1) {
8980Sstevel@tonic-gate if (!overwrite && (errno == EEXIST)) {
8990Sstevel@tonic-gate (void) fprintf(stderr,
9000Sstevel@tonic-gate gettext("%s: Notice: Service manifest for "
9010Sstevel@tonic-gate "%s already generated as %s, skipped\n"),
9020Sstevel@tonic-gate progname, iconf->service, dstfile);
9030Sstevel@tonic-gate free(dstfile);
9040Sstevel@tonic-gate return (-1);
9050Sstevel@tonic-gate } else {
9060Sstevel@tonic-gate (void) fprintf(stderr,
9070Sstevel@tonic-gate gettext("%s: Error opening %s: %s\n"),
9080Sstevel@tonic-gate progname, dstfile, strerror(errno));
9090Sstevel@tonic-gate free(dstfile);
9100Sstevel@tonic-gate return (-2);
9110Sstevel@tonic-gate }
9120Sstevel@tonic-gate }
9130Sstevel@tonic-gate /* Clear errno to catch the "no stdio streams" case */
9140Sstevel@tonic-gate errno = 0;
9150Sstevel@tonic-gate if ((fp = fdopen(fd, "w")) == NULL) {
9160Sstevel@tonic-gate char *s = strerror(errno);
9170Sstevel@tonic-gate if (errno == 0)
9180Sstevel@tonic-gate s = gettext("No stdio streams available");
9190Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error fdopen failed: %s\n"),
9200Sstevel@tonic-gate progname, s);
9210Sstevel@tonic-gate (void) close(fd);
9220Sstevel@tonic-gate free(dstfile);
9230Sstevel@tonic-gate return (-2);
9240Sstevel@tonic-gate }
9250Sstevel@tonic-gate *finfo = safe_malloc(sizeof (struct fileinfo));
9260Sstevel@tonic-gate (*finfo)->fp = fp;
9270Sstevel@tonic-gate (*finfo)->filename = dstfile;
9280Sstevel@tonic-gate (*finfo)->lineno = 0;
9290Sstevel@tonic-gate (*finfo)->failcnt = 0;
9300Sstevel@tonic-gate return (0);
9310Sstevel@tonic-gate }
9320Sstevel@tonic-gate
9330Sstevel@tonic-gate static int
import_manifest(char * filename)9340Sstevel@tonic-gate import_manifest(char *filename)
9350Sstevel@tonic-gate {
9360Sstevel@tonic-gate int status;
9370Sstevel@tonic-gate pid_t pid, wpid;
9380Sstevel@tonic-gate char *cp;
9390Sstevel@tonic-gate
9400Sstevel@tonic-gate if ((cp = strrchr(filename, '/')) == NULL)
9410Sstevel@tonic-gate cp = filename;
9420Sstevel@tonic-gate else
9430Sstevel@tonic-gate cp++;
9440Sstevel@tonic-gate (void) printf(gettext("Importing %s ..."), cp);
9450Sstevel@tonic-gate
9460Sstevel@tonic-gate if ((pid = fork()) == -1) {
9470Sstevel@tonic-gate (void) fprintf(stderr,
9480Sstevel@tonic-gate gettext("\n%s: fork failed, %s not imported: %s\n"),
9490Sstevel@tonic-gate progname, filename, strerror(errno));
9500Sstevel@tonic-gate exit(EXIT_ERROR_SYS);
9510Sstevel@tonic-gate }
9520Sstevel@tonic-gate if (pid == 0) {
9530Sstevel@tonic-gate /* child */
9540Sstevel@tonic-gate (void) fclose(stdin);
9550Sstevel@tonic-gate (void) setenv("SVCCFG_CHECKHASH", "1", 1);
9560Sstevel@tonic-gate (void) execl(SVCCFG_PATH, "svccfg", "import", filename, NULL);
9570Sstevel@tonic-gate (void) fprintf(stderr, gettext("\n%s: exec of %s failed: %s"),
9580Sstevel@tonic-gate progname, SVCCFG_PATH, strerror(errno));
9590Sstevel@tonic-gate _exit(EXIT_ERROR_SYS);
9600Sstevel@tonic-gate }
9610Sstevel@tonic-gate /* parent */
9620Sstevel@tonic-gate if ((wpid = waitpid(pid, &status, 0)) != pid) {
9630Sstevel@tonic-gate (void) fprintf(stderr, gettext(
9640Sstevel@tonic-gate "\n%s: unexpected wait (%d) from import of %s: %s\n"),
9650Sstevel@tonic-gate progname, wpid, filename, strerror(errno));
9660Sstevel@tonic-gate return (-1);
9670Sstevel@tonic-gate }
9680Sstevel@tonic-gate if (WIFEXITED(status) && (WEXITSTATUS(status) != 0)) {
9690Sstevel@tonic-gate (void) fprintf(stderr,
9700Sstevel@tonic-gate gettext("\n%s: import failure (%d) for %s\n"),
9710Sstevel@tonic-gate progname, WEXITSTATUS(status), filename);
9720Sstevel@tonic-gate return (-1);
9730Sstevel@tonic-gate }
9740Sstevel@tonic-gate (void) printf(gettext("Done\n"));
9750Sstevel@tonic-gate return (0);
9760Sstevel@tonic-gate }
9770Sstevel@tonic-gate
9780Sstevel@tonic-gate static int
inetd_config_path(char ** path)9790Sstevel@tonic-gate inetd_config_path(char **path)
9800Sstevel@tonic-gate {
9810Sstevel@tonic-gate int fd;
9820Sstevel@tonic-gate char *arg1, *configfile, *configstr;
9830Sstevel@tonic-gate scf_simple_prop_t *sp;
9840Sstevel@tonic-gate char cpath[PATH_MAX];
9850Sstevel@tonic-gate
9860Sstevel@tonic-gate if ((sp = scf_simple_prop_get(NULL, INETD_INSTANCE_FMRI, "start",
9870Sstevel@tonic-gate SCF_PROPERTY_EXEC)) == NULL)
9880Sstevel@tonic-gate return (-1);
9890Sstevel@tonic-gate if ((configstr = scf_simple_prop_next_astring(sp)) == NULL) {
9900Sstevel@tonic-gate scf_simple_prop_free(sp);
9910Sstevel@tonic-gate return (-1);
9920Sstevel@tonic-gate }
9930Sstevel@tonic-gate configstr = safe_strdup(configstr);
9940Sstevel@tonic-gate scf_simple_prop_free(sp);
9950Sstevel@tonic-gate
9960Sstevel@tonic-gate /*
9970Sstevel@tonic-gate * Look for the optional configuration file, the syntax is:
9980Sstevel@tonic-gate * /usr/lib/inet/inetd [config-file] start|stop|refresh|disable|%m
9990Sstevel@tonic-gate */
10000Sstevel@tonic-gate if (strtok(configstr, " \t") == NULL) {
10010Sstevel@tonic-gate free(configstr);
10020Sstevel@tonic-gate return (-1);
10030Sstevel@tonic-gate }
10040Sstevel@tonic-gate if ((arg1 = strtok(NULL, " \t")) == NULL) {
10050Sstevel@tonic-gate free(configstr);
10060Sstevel@tonic-gate return (-1);
10070Sstevel@tonic-gate }
10080Sstevel@tonic-gate if (strtok(NULL, " \t") == NULL) {
10090Sstevel@tonic-gate /*
10100Sstevel@tonic-gate * No configuration file specified, do the same as inetd and
10110Sstevel@tonic-gate * first try /etc/inet/inetd.conf, followed by /etc/inetd.conf.
10120Sstevel@tonic-gate */
10130Sstevel@tonic-gate configfile = MAIN_CONFIG;
10140Sstevel@tonic-gate if ((fd = open(configfile, O_RDONLY)) >= 0)
10150Sstevel@tonic-gate (void) close(fd);
10160Sstevel@tonic-gate else
10170Sstevel@tonic-gate configfile = ALT_CONFIG;
10180Sstevel@tonic-gate
10190Sstevel@tonic-gate } else {
10200Sstevel@tonic-gate /* make sure there are no more arguments */
10210Sstevel@tonic-gate if (strtok(NULL, " \t") != NULL) {
10220Sstevel@tonic-gate free(configstr);
10230Sstevel@tonic-gate return (-1);
10240Sstevel@tonic-gate }
10250Sstevel@tonic-gate configfile = arg1;
10260Sstevel@tonic-gate }
10270Sstevel@tonic-gate
10280Sstevel@tonic-gate /* configuration file must be an absolute pathname */
10290Sstevel@tonic-gate if (*configfile != '/') {
10300Sstevel@tonic-gate free(configstr);
10310Sstevel@tonic-gate return (-1);
10320Sstevel@tonic-gate }
10330Sstevel@tonic-gate
10340Sstevel@tonic-gate if (realpath(configfile, cpath) == NULL)
10350Sstevel@tonic-gate (void) strlcpy(cpath, configfile, sizeof (cpath));
10360Sstevel@tonic-gate
10370Sstevel@tonic-gate free(configstr);
10380Sstevel@tonic-gate *path = safe_strdup(cpath);
10390Sstevel@tonic-gate return (0);
10400Sstevel@tonic-gate }
10410Sstevel@tonic-gate
10420Sstevel@tonic-gate static int
update_hash(char * srcfile)10430Sstevel@tonic-gate update_hash(char *srcfile)
10440Sstevel@tonic-gate {
10450Sstevel@tonic-gate scf_error_t rval;
10460Sstevel@tonic-gate char *inetd_cpath, *hashstr;
10470Sstevel@tonic-gate char cpath[PATH_MAX];
10480Sstevel@tonic-gate
10490Sstevel@tonic-gate /* determine the config file inetd is using */
10500Sstevel@tonic-gate if (inetd_config_path(&inetd_cpath) == -1) {
10510Sstevel@tonic-gate (void) fprintf(stderr,
10520Sstevel@tonic-gate gettext("%s: Error reading from repository\n"), progname);
10530Sstevel@tonic-gate return (-1);
10540Sstevel@tonic-gate }
10550Sstevel@tonic-gate
10560Sstevel@tonic-gate /* resolve inetconv input filename */
10570Sstevel@tonic-gate if (realpath(srcfile, cpath) == NULL)
10580Sstevel@tonic-gate (void) strlcpy(cpath, srcfile, sizeof (cpath));
10590Sstevel@tonic-gate
10600Sstevel@tonic-gate /* if inetconv and inetd are using the same config file, update hash */
10610Sstevel@tonic-gate if (strcmp(cpath, inetd_cpath) != 0) {
10620Sstevel@tonic-gate free(inetd_cpath);
10630Sstevel@tonic-gate return (0);
10640Sstevel@tonic-gate }
10650Sstevel@tonic-gate free(inetd_cpath);
10660Sstevel@tonic-gate
10670Sstevel@tonic-gate /* generic error message as use of hash is not exposed to the user */
10680Sstevel@tonic-gate if (calculate_hash(cpath, &hashstr) != 0) {
10690Sstevel@tonic-gate (void) fprintf(stderr,
10700Sstevel@tonic-gate gettext("%s: Error unable to update repository\n"),
10710Sstevel@tonic-gate progname);
10720Sstevel@tonic-gate return (-1);
10730Sstevel@tonic-gate }
10740Sstevel@tonic-gate /* generic error message as use of hash is not exposed to the user */
10750Sstevel@tonic-gate if ((rval = store_inetd_hash(hashstr)) != SCF_ERROR_NONE) {
10760Sstevel@tonic-gate (void) fprintf(stderr,
10770Sstevel@tonic-gate gettext("%s: Error updating repository: %s\n"),
10780Sstevel@tonic-gate progname, scf_strerror(rval));
10790Sstevel@tonic-gate free(hashstr);
10800Sstevel@tonic-gate return (-1);
10810Sstevel@tonic-gate }
10820Sstevel@tonic-gate free(hashstr);
10830Sstevel@tonic-gate return (0);
10840Sstevel@tonic-gate }
10850Sstevel@tonic-gate
10860Sstevel@tonic-gate static void
property_error(const char * fmri,const char * prop)10870Sstevel@tonic-gate property_error(const char *fmri, const char *prop)
10880Sstevel@tonic-gate {
10890Sstevel@tonic-gate (void) fprintf(stderr,
10900Sstevel@tonic-gate gettext("Error: Instance %1$s is missing property '%2$s'.\n"),
10910Sstevel@tonic-gate fmri, prop);
10920Sstevel@tonic-gate }
10930Sstevel@tonic-gate
10940Sstevel@tonic-gate /*
10950Sstevel@tonic-gate * modify_sprop takes a handle, an instance, a property group, a property,
10960Sstevel@tonic-gate * and an astring value, and modifies the instance (or service's) specified
10970Sstevel@tonic-gate * property in the repository to the submitted value.
10980Sstevel@tonic-gate *
10990Sstevel@tonic-gate * returns -1 on error, 1 on successful transaction completion.
11000Sstevel@tonic-gate */
11010Sstevel@tonic-gate
11020Sstevel@tonic-gate static int
modify_sprop(scf_handle_t * h,const scf_instance_t * inst,const char * pg,const char * prop,const char * value)11030Sstevel@tonic-gate modify_sprop(scf_handle_t *h, const scf_instance_t *inst,
11040Sstevel@tonic-gate const char *pg, const char *prop, const char *value)
11050Sstevel@tonic-gate {
11060Sstevel@tonic-gate scf_transaction_t *tx = NULL;
11070Sstevel@tonic-gate scf_transaction_entry_t *ent = NULL;
11080Sstevel@tonic-gate scf_propertygroup_t *gpg = NULL;
11090Sstevel@tonic-gate scf_property_t *eprop = NULL;
11100Sstevel@tonic-gate scf_value_t *v = NULL;
11110Sstevel@tonic-gate scf_service_t *svc = NULL;
11120Sstevel@tonic-gate int ret = 0, create = 0;
11130Sstevel@tonic-gate
11140Sstevel@tonic-gate if ((gpg = scf_pg_create(h)) == NULL)
11150Sstevel@tonic-gate return (-1);
11160Sstevel@tonic-gate
11170Sstevel@tonic-gate /* Get the property group */
11180Sstevel@tonic-gate if (scf_instance_get_pg(inst, pg, gpg) == -1) {
11190Sstevel@tonic-gate /* Not a property of the instance, try the service instead */
11200Sstevel@tonic-gate if ((svc = scf_service_create(h)) == NULL) {
11210Sstevel@tonic-gate ret = -1;
11220Sstevel@tonic-gate goto out;
11230Sstevel@tonic-gate }
11240Sstevel@tonic-gate if ((scf_instance_get_parent(inst, svc) == -1) ||
11250Sstevel@tonic-gate (scf_service_get_pg(svc, pg, gpg) == -1)) {
11260Sstevel@tonic-gate ret = -1;
11270Sstevel@tonic-gate goto out;
11280Sstevel@tonic-gate }
11290Sstevel@tonic-gate }
11300Sstevel@tonic-gate
11310Sstevel@tonic-gate if ((eprop = scf_property_create(h)) == NULL) {
11320Sstevel@tonic-gate ret = -1;
11330Sstevel@tonic-gate goto out;
11340Sstevel@tonic-gate }
11350Sstevel@tonic-gate
11360Sstevel@tonic-gate if (scf_pg_get_property(gpg, prop, eprop) == -1) {
11370Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND) {
11380Sstevel@tonic-gate ret = -1;
11390Sstevel@tonic-gate goto out;
11400Sstevel@tonic-gate }
11410Sstevel@tonic-gate
11420Sstevel@tonic-gate create = 1;
11430Sstevel@tonic-gate }
11440Sstevel@tonic-gate
11450Sstevel@tonic-gate if ((tx = scf_transaction_create(h)) == NULL ||
11460Sstevel@tonic-gate (ent = scf_entry_create(h)) == NULL) {
11470Sstevel@tonic-gate ret = -1;
11480Sstevel@tonic-gate goto out;
11490Sstevel@tonic-gate }
11500Sstevel@tonic-gate
11510Sstevel@tonic-gate do {
11520Sstevel@tonic-gate if (scf_transaction_start(tx, gpg) == -1) {
11530Sstevel@tonic-gate ret = -1;
11540Sstevel@tonic-gate goto out;
11550Sstevel@tonic-gate }
11560Sstevel@tonic-gate
11570Sstevel@tonic-gate /* Modify the property */
11580Sstevel@tonic-gate if (create)
11590Sstevel@tonic-gate ret = scf_transaction_property_new(tx, ent, prop,
11600Sstevel@tonic-gate SCF_TYPE_ASTRING);
11610Sstevel@tonic-gate else
11620Sstevel@tonic-gate ret = scf_transaction_property_change_type(tx, ent,
11630Sstevel@tonic-gate prop, SCF_TYPE_ASTRING);
11640Sstevel@tonic-gate
11650Sstevel@tonic-gate if (ret == -1)
11660Sstevel@tonic-gate goto out;
11670Sstevel@tonic-gate
11680Sstevel@tonic-gate if ((v = scf_value_create(h)) == NULL) {
11690Sstevel@tonic-gate ret = -1;
11700Sstevel@tonic-gate goto out;
11710Sstevel@tonic-gate }
11720Sstevel@tonic-gate
11730Sstevel@tonic-gate if (scf_value_set_astring(v, value) == -1) {
11740Sstevel@tonic-gate ret = -1;
11750Sstevel@tonic-gate goto out;
11760Sstevel@tonic-gate }
11770Sstevel@tonic-gate
11780Sstevel@tonic-gate if (scf_entry_add_value(ent, v) == -1) {
11790Sstevel@tonic-gate ret = -1;
11800Sstevel@tonic-gate goto out;
11810Sstevel@tonic-gate }
11820Sstevel@tonic-gate
11830Sstevel@tonic-gate ret = scf_transaction_commit(tx);
11840Sstevel@tonic-gate
11850Sstevel@tonic-gate if (ret == 0) {
11860Sstevel@tonic-gate /* Property group was stale, retry */
11870Sstevel@tonic-gate if (scf_pg_update(gpg) == -1) {
11880Sstevel@tonic-gate ret = -1;
11890Sstevel@tonic-gate goto out;
11900Sstevel@tonic-gate }
11910Sstevel@tonic-gate scf_transaction_reset(tx);
11920Sstevel@tonic-gate }
11930Sstevel@tonic-gate
11940Sstevel@tonic-gate } while (ret == 0);
11950Sstevel@tonic-gate out:
11960Sstevel@tonic-gate scf_value_destroy(v);
11970Sstevel@tonic-gate scf_entry_destroy(ent);
11980Sstevel@tonic-gate scf_transaction_destroy(tx);
11990Sstevel@tonic-gate scf_property_destroy(eprop);
12000Sstevel@tonic-gate scf_service_destroy(svc);
12010Sstevel@tonic-gate scf_pg_destroy(gpg);
12020Sstevel@tonic-gate
12030Sstevel@tonic-gate return (ret);
12040Sstevel@tonic-gate }
12050Sstevel@tonic-gate
12060Sstevel@tonic-gate /*
12070Sstevel@tonic-gate * list_callback is the callback function to be handed to simple_walk_instances
12080Sstevel@tonic-gate * in main. It is called once on every instance on a machine. If that
12090Sstevel@tonic-gate * instance is controlled by inetd, we test whether it's the same
12100Sstevel@tonic-gate * service that we're looking at from the inetd.conf file, and enable it if
12110Sstevel@tonic-gate * they are the same.
12120Sstevel@tonic-gate */
12130Sstevel@tonic-gate
12140Sstevel@tonic-gate /*ARGSUSED*/
12150Sstevel@tonic-gate static int
list_callback(scf_handle_t * h,scf_instance_t * inst,void * buf)12160Sstevel@tonic-gate list_callback(scf_handle_t *h, scf_instance_t *inst, void *buf)
12170Sstevel@tonic-gate {
12180Sstevel@tonic-gate ssize_t max_name_length;
12190Sstevel@tonic-gate char *svc_name;
12200Sstevel@tonic-gate scf_simple_prop_t *prop = NULL;
12210Sstevel@tonic-gate scf_simple_prop_t *sockprop = NULL;
12220Sstevel@tonic-gate scf_simple_prop_t *rpcprop = NULL;
12230Sstevel@tonic-gate scf_simple_prop_t *progprop = NULL;
12240Sstevel@tonic-gate const char *name, *endpoint, *restart_str, *prog;
12250Sstevel@tonic-gate struct inetconfent *iconf = (struct inetconfent *)buf;
12260Sstevel@tonic-gate uint8_t *isrpc;
12270Sstevel@tonic-gate
12280Sstevel@tonic-gate max_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
12290Sstevel@tonic-gate if ((svc_name = malloc(max_name_length + 1)) == NULL) {
12300Sstevel@tonic-gate (void) fprintf(stderr, gettext("Error: Out of memory.\n"));
12310Sstevel@tonic-gate return (SCF_FAILED);
12320Sstevel@tonic-gate }
12330Sstevel@tonic-gate
12340Sstevel@tonic-gate /*
12350Sstevel@tonic-gate * Get the FMRI of the instance, and check if its delegated restarter
12360Sstevel@tonic-gate * is inetd. A missing or empty restarter property implies that
12370Sstevel@tonic-gate * svc.startd is the restarter.
12380Sstevel@tonic-gate */
12390Sstevel@tonic-gate
12400Sstevel@tonic-gate if (scf_instance_to_fmri(inst, svc_name, max_name_length) < 0) {
12410Sstevel@tonic-gate (void) fprintf(stderr,
12420Sstevel@tonic-gate gettext("Error: Unable to obtain FMRI for service %1$s."),
12430Sstevel@tonic-gate svc_name);
12440Sstevel@tonic-gate free(svc_name);
12450Sstevel@tonic-gate return (SCF_FAILED);
12460Sstevel@tonic-gate }
12470Sstevel@tonic-gate
12480Sstevel@tonic-gate if ((prop = scf_simple_prop_get(h, svc_name, SCF_PG_GENERAL,
12490Sstevel@tonic-gate SCF_PROPERTY_RESTARTER)) == NULL)
12500Sstevel@tonic-gate goto out;
12510Sstevel@tonic-gate
12520Sstevel@tonic-gate if ((restart_str = scf_simple_prop_next_ustring(prop)) == NULL)
12530Sstevel@tonic-gate goto out;
12540Sstevel@tonic-gate
12550Sstevel@tonic-gate if (strcmp(restart_str, INETD_INSTANCE_FMRI) != 0)
12560Sstevel@tonic-gate goto out;
12570Sstevel@tonic-gate
12580Sstevel@tonic-gate /* Free restarter prop so it can be reused below */
12590Sstevel@tonic-gate scf_simple_prop_free(prop);
12600Sstevel@tonic-gate
12610Sstevel@tonic-gate /*
12620Sstevel@tonic-gate * We know that this instance is managed by inetd.
12630Sstevel@tonic-gate * Now get the properties needed to decide if it matches this
12640Sstevel@tonic-gate * line in the old config file.
12650Sstevel@tonic-gate */
12660Sstevel@tonic-gate
12670Sstevel@tonic-gate if (((prop = scf_simple_prop_get(h, svc_name, PG_NAME_SERVICE_CONFIG,
12680Sstevel@tonic-gate PR_SVC_NAME_NAME)) == NULL) ||
12690Sstevel@tonic-gate ((name = scf_simple_prop_next_astring(prop)) == NULL)) {
12700Sstevel@tonic-gate property_error(svc_name, PR_SVC_NAME_NAME);
12710Sstevel@tonic-gate goto out;
12720Sstevel@tonic-gate }
12730Sstevel@tonic-gate
12740Sstevel@tonic-gate if (((sockprop = scf_simple_prop_get(h, svc_name,
12750Sstevel@tonic-gate PG_NAME_SERVICE_CONFIG, PR_SOCK_TYPE_NAME)) == NULL) ||
12760Sstevel@tonic-gate ((endpoint = scf_simple_prop_next_astring(sockprop)) == NULL)) {
12770Sstevel@tonic-gate property_error(svc_name, PR_SOCK_TYPE_NAME);
12780Sstevel@tonic-gate goto out;
12790Sstevel@tonic-gate }
12800Sstevel@tonic-gate
12810Sstevel@tonic-gate if (((rpcprop = scf_simple_prop_get(h, svc_name,
12820Sstevel@tonic-gate PG_NAME_SERVICE_CONFIG, PR_ISRPC_NAME)) == NULL) ||
12830Sstevel@tonic-gate ((isrpc = scf_simple_prop_next_boolean(rpcprop)) == NULL)) {
12840Sstevel@tonic-gate property_error(svc_name, PR_ISRPC_NAME);
12850Sstevel@tonic-gate goto out;
12860Sstevel@tonic-gate }
12870Sstevel@tonic-gate
12880Sstevel@tonic-gate if (((progprop = scf_simple_prop_get(h, svc_name, START_METHOD_NAME,
12890Sstevel@tonic-gate PR_EXEC_NAME)) == NULL) ||
12900Sstevel@tonic-gate ((prog = scf_simple_prop_next_astring(progprop)) == NULL)) {
12910Sstevel@tonic-gate property_error(svc_name, PR_EXEC_NAME);
12920Sstevel@tonic-gate }
12930Sstevel@tonic-gate
12940Sstevel@tonic-gate
12950Sstevel@tonic-gate /* If it's RPC, we truncate off the version portion for comparison */
12960Sstevel@tonic-gate if (*isrpc) {
12970Sstevel@tonic-gate char *cp;
12980Sstevel@tonic-gate
12990Sstevel@tonic-gate cp = strchr(iconf->service, '/');
13000Sstevel@tonic-gate if (cp != NULL)
13010Sstevel@tonic-gate *cp = '\0';
13020Sstevel@tonic-gate }
13030Sstevel@tonic-gate
13040Sstevel@tonic-gate /*
13050Sstevel@tonic-gate * If name of this service and endpoint are equal to values from
13060Sstevel@tonic-gate * iconf fields, and they're either both RPC or both non-RPC,
13070Sstevel@tonic-gate * then we have a match; update the exec and arg0 properties if
13080Sstevel@tonic-gate * necessary, then enable it.
13090Sstevel@tonic-gate * We don't return an error if either operation fails so that we
13100Sstevel@tonic-gate * continue to try all the other services.
13110Sstevel@tonic-gate */
13120Sstevel@tonic-gate if (strcmp(name, iconf->service) == 0 &&
13130Sstevel@tonic-gate strcmp(endpoint, iconf->endpoint) == 0 &&
13140Sstevel@tonic-gate *isrpc == (strncmp(iconf->protocol, "rpc/", 4) == 0)) {
13150Sstevel@tonic-gate /* Can't update exec on internal services */
13160Sstevel@tonic-gate if ((strcmp(iconf->server_program, "internal") != 0) &&
13170Sstevel@tonic-gate (strcmp(iconf->exec, prog) != 0)) {
13180Sstevel@tonic-gate /* User had edited the command */
13190Sstevel@tonic-gate if (!import) {
13200Sstevel@tonic-gate /* Dry run only */
13210Sstevel@tonic-gate (void) printf(
13220Sstevel@tonic-gate gettext("Would update %s to %s %s"),
13230Sstevel@tonic-gate svc_name, PR_EXEC_NAME, iconf->exec);
13240Sstevel@tonic-gate if (iconf->arg0 != NULL) {
13250Sstevel@tonic-gate (void) printf(
13260Sstevel@tonic-gate gettext(" with %s of %s\n"),
13270Sstevel@tonic-gate PR_ARG0_NAME, iconf->arg0);
13280Sstevel@tonic-gate } else {
13290Sstevel@tonic-gate (void) printf("\n");
13300Sstevel@tonic-gate }
13310Sstevel@tonic-gate } else {
13320Sstevel@tonic-gate /* Update instance's exec property */
13330Sstevel@tonic-gate if (modify_sprop(h, inst, START_METHOD_NAME,
13340Sstevel@tonic-gate PR_EXEC_NAME, iconf->exec) != 1)
13350Sstevel@tonic-gate (void) fprintf(stderr,
13360Sstevel@tonic-gate gettext("Error: Unable to update "
13370Sstevel@tonic-gate "%s property of %s, %s\n"),
13380Sstevel@tonic-gate PR_EXEC_NAME, svc_name,
13390Sstevel@tonic-gate scf_strerror(scf_error()));
13400Sstevel@tonic-gate else
13410Sstevel@tonic-gate (void) printf("%s will %s %s\n",
13420Sstevel@tonic-gate svc_name, PR_EXEC_NAME,
13430Sstevel@tonic-gate iconf->exec);
13440Sstevel@tonic-gate
13450Sstevel@tonic-gate /* Update arg0 prop, if needed */
13460Sstevel@tonic-gate if (iconf->arg0 != NULL) {
13470Sstevel@tonic-gate if (modify_sprop(h, inst,
13480Sstevel@tonic-gate START_METHOD_NAME, PR_ARG0_NAME,
13490Sstevel@tonic-gate iconf->arg0) != 1) {
13500Sstevel@tonic-gate (void) fprintf(stderr,
13510Sstevel@tonic-gate gettext("Error: Unable to "
13520Sstevel@tonic-gate "update %s property of "
13530Sstevel@tonic-gate "%s, %s\n"), PR_ARG0_NAME,
13540Sstevel@tonic-gate svc_name,
13550Sstevel@tonic-gate scf_strerror(scf_error()));
13560Sstevel@tonic-gate } else {
13570Sstevel@tonic-gate (void) printf("%s will have an "
13580Sstevel@tonic-gate "%s of %s\n", svc_name,
13590Sstevel@tonic-gate PR_ARG0_NAME, iconf->arg0);
13600Sstevel@tonic-gate }
13610Sstevel@tonic-gate }
13620Sstevel@tonic-gate }
13630Sstevel@tonic-gate }
13640Sstevel@tonic-gate
13650Sstevel@tonic-gate if (!import) {
13660Sstevel@tonic-gate /* Dry-run only */
13670Sstevel@tonic-gate (void) printf("Would enable %s\n", svc_name);
13680Sstevel@tonic-gate } else {
13690Sstevel@tonic-gate if (smf_enable_instance(svc_name, 0) != 0)
13700Sstevel@tonic-gate (void) fprintf(stderr,
13710Sstevel@tonic-gate gettext("Error: Failed to enable %s\n"),
13720Sstevel@tonic-gate svc_name);
13730Sstevel@tonic-gate else
13740Sstevel@tonic-gate (void) printf("%s enabled\n", svc_name);
13750Sstevel@tonic-gate }
13760Sstevel@tonic-gate }
13770Sstevel@tonic-gate
13780Sstevel@tonic-gate out:
13790Sstevel@tonic-gate free(svc_name);
13800Sstevel@tonic-gate scf_simple_prop_free(prop);
13810Sstevel@tonic-gate scf_simple_prop_free(sockprop);
13820Sstevel@tonic-gate scf_simple_prop_free(rpcprop);
13830Sstevel@tonic-gate scf_simple_prop_free(progprop);
13840Sstevel@tonic-gate return (SCF_SUCCESS);
13850Sstevel@tonic-gate }
13860Sstevel@tonic-gate
13870Sstevel@tonic-gate static void
usage(void)13880Sstevel@tonic-gate usage(void)
13890Sstevel@tonic-gate {
13900Sstevel@tonic-gate (void) fprintf(stderr, gettext(
13910Sstevel@tonic-gate "Usage: %s [-fn] [-i srcfile] [-o destdir]\n"
13920Sstevel@tonic-gate " %1$s -e [-n] [-i srcfile]\n"
13930Sstevel@tonic-gate "-? Display this usage message\n"
13940Sstevel@tonic-gate "-e Enable smf services which are enabled in the input\n"
13950Sstevel@tonic-gate " file\n"
13960Sstevel@tonic-gate "-f Force overwrite of existing manifests\n"
13970Sstevel@tonic-gate "-n Do not import converted manifests,\n"
13980Sstevel@tonic-gate " or only display services which would be enabled\n"
13990Sstevel@tonic-gate "-i srcfile Alternate input file\n"
14000Sstevel@tonic-gate "-o destdir Alternate output directory for manifests\n"),
14010Sstevel@tonic-gate progname);
14020Sstevel@tonic-gate exit(EXIT_USAGE);
14030Sstevel@tonic-gate }
14040Sstevel@tonic-gate
14050Sstevel@tonic-gate int
main(int argc,char * argv[])14060Sstevel@tonic-gate main(int argc, char *argv[])
14070Sstevel@tonic-gate {
14080Sstevel@tonic-gate int c, rval, convert_err, import_err = 0, enable_err = 0;
14090Sstevel@tonic-gate boolean_t overwrite = B_FALSE;
14100Sstevel@tonic-gate boolean_t enable = B_FALSE;
14110Sstevel@tonic-gate char *srcfile = NULL;
14120Sstevel@tonic-gate char *destdir = NULL;
14130Sstevel@tonic-gate struct fileinfo *srcfinfo, *dstfinfo;
14140Sstevel@tonic-gate struct inetconfent *iconf;
14150Sstevel@tonic-gate
14160Sstevel@tonic-gate setbuf(stdout, NULL);
14170Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
14180Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
14190Sstevel@tonic-gate
14200Sstevel@tonic-gate if ((progname = strrchr(argv[0], '/')) == NULL)
14210Sstevel@tonic-gate progname = argv[0];
14220Sstevel@tonic-gate else
14230Sstevel@tonic-gate progname++;
14240Sstevel@tonic-gate
14250Sstevel@tonic-gate while ((c = getopt(argc, argv, "?efni:o:")) != -1) {
14260Sstevel@tonic-gate switch (c) {
14270Sstevel@tonic-gate case 'e':
14280Sstevel@tonic-gate /* enable services based on existing file config */
14290Sstevel@tonic-gate enable = B_TRUE;
14300Sstevel@tonic-gate break;
14310Sstevel@tonic-gate
14320Sstevel@tonic-gate case 'f':
14330Sstevel@tonic-gate /* overwrite existing manifests */
14340Sstevel@tonic-gate overwrite = B_TRUE;
14350Sstevel@tonic-gate break;
14360Sstevel@tonic-gate case 'n':
14370Sstevel@tonic-gate /* don't import manifests, or dry-run enable */
14380Sstevel@tonic-gate import = B_FALSE;
14390Sstevel@tonic-gate break;
14400Sstevel@tonic-gate case 'i':
14410Sstevel@tonic-gate /* alternate input file */
14420Sstevel@tonic-gate if (srcfile != NULL) {
14430Sstevel@tonic-gate (void) fprintf(stderr,
14440Sstevel@tonic-gate gettext("%s: Error only one -%c allowed\n"),
14450Sstevel@tonic-gate progname, optopt);
14460Sstevel@tonic-gate usage();
14470Sstevel@tonic-gate }
14480Sstevel@tonic-gate srcfile = optarg;
14490Sstevel@tonic-gate break;
14500Sstevel@tonic-gate case 'o':
14510Sstevel@tonic-gate /* alternate output directory */
14520Sstevel@tonic-gate if (destdir != NULL) {
14530Sstevel@tonic-gate (void) fprintf(stderr,
14540Sstevel@tonic-gate gettext("%s: Error only one -%c allowed\n"),
14550Sstevel@tonic-gate progname, optopt);
14560Sstevel@tonic-gate usage();
14570Sstevel@tonic-gate }
14580Sstevel@tonic-gate destdir = optarg;
14590Sstevel@tonic-gate break;
14600Sstevel@tonic-gate case '?': /*FALLTHROUGH*/
14610Sstevel@tonic-gate default:
14620Sstevel@tonic-gate usage();
14630Sstevel@tonic-gate break;
14640Sstevel@tonic-gate }
14650Sstevel@tonic-gate }
14660Sstevel@tonic-gate
14670Sstevel@tonic-gate /*
14680Sstevel@tonic-gate * Display usage if extraneous args supplied or enable specified in
14690Sstevel@tonic-gate * combination with overwrite or destdir
14700Sstevel@tonic-gate */
14710Sstevel@tonic-gate if ((optind != argc) || (enable && (overwrite || destdir != NULL)))
14720Sstevel@tonic-gate usage();
14730Sstevel@tonic-gate
14740Sstevel@tonic-gate if ((srcfinfo = open_srcfile(srcfile)) == NULL)
14750Sstevel@tonic-gate return (EXIT_ERROR_CONV);
14760Sstevel@tonic-gate
14770Sstevel@tonic-gate while ((iconf = fgetinetconfent(srcfinfo, !enable)) != NULL) {
14780Sstevel@tonic-gate /*
14790Sstevel@tonic-gate * If we're enabling, then just walk all the services for each
14800Sstevel@tonic-gate * line and enable those which match.
14810Sstevel@tonic-gate */
14820Sstevel@tonic-gate if (enable) {
14830Sstevel@tonic-gate rval = scf_simple_walk_instances(SCF_STATE_ALL, iconf,
14840Sstevel@tonic-gate list_callback);
14850Sstevel@tonic-gate free_inetconfent(iconf);
14860Sstevel@tonic-gate if (rval == SCF_FAILED) {
14870Sstevel@tonic-gate /* Only print msg if framework error */
14880Sstevel@tonic-gate if (scf_error() != SCF_ERROR_CALLBACK_FAILED)
14890Sstevel@tonic-gate (void) fprintf(stderr, gettext(
14900Sstevel@tonic-gate "Error walking instances: %s.\n"),
14910Sstevel@tonic-gate scf_strerror(scf_error()));
14920Sstevel@tonic-gate enable_err++;
14930Sstevel@tonic-gate break;
14940Sstevel@tonic-gate }
14950Sstevel@tonic-gate continue;
14960Sstevel@tonic-gate }
14970Sstevel@tonic-gate
14980Sstevel@tonic-gate /* Remainder of loop used for conversion & import */
14990Sstevel@tonic-gate if ((rval = open_dstfile(destdir, overwrite, iconf, &dstfinfo))
15000Sstevel@tonic-gate < 0) {
15010Sstevel@tonic-gate /*
15020Sstevel@tonic-gate * Only increment error counter if the failure was
15030Sstevel@tonic-gate * other than the file already existing.
15040Sstevel@tonic-gate */
15050Sstevel@tonic-gate if (rval == -2)
15060Sstevel@tonic-gate srcfinfo->failcnt++;
15070Sstevel@tonic-gate free_inetconfent(iconf);
15080Sstevel@tonic-gate continue;
15090Sstevel@tonic-gate }
15100Sstevel@tonic-gate rval = print_manifest(dstfinfo->fp, dstfinfo->filename, iconf);
15110Sstevel@tonic-gate (void) fclose(dstfinfo->fp);
15120Sstevel@tonic-gate if (rval == 0) {
15130Sstevel@tonic-gate if (import &&
15140Sstevel@tonic-gate (import_manifest(dstfinfo->filename) != 0))
15150Sstevel@tonic-gate import_err++;
15160Sstevel@tonic-gate } else {
15170Sstevel@tonic-gate (void) unlink(dstfinfo->filename);
15180Sstevel@tonic-gate srcfinfo->failcnt++;
15190Sstevel@tonic-gate }
15200Sstevel@tonic-gate free(dstfinfo->filename);
15210Sstevel@tonic-gate free(dstfinfo);
15220Sstevel@tonic-gate free_inetconfent(iconf);
15230Sstevel@tonic-gate }
15240Sstevel@tonic-gate (void) fclose(srcfinfo->fp);
15250Sstevel@tonic-gate convert_err = srcfinfo->failcnt;
15260Sstevel@tonic-gate
15270Sstevel@tonic-gate /* Update hash only if not in enable mode, and only if importing */
15280Sstevel@tonic-gate if (!enable && import && (update_hash(srcfinfo->filename) != 0))
15290Sstevel@tonic-gate import_err++;
15300Sstevel@tonic-gate
15310Sstevel@tonic-gate free(srcfinfo);
15320Sstevel@tonic-gate
15330Sstevel@tonic-gate if (enable_err != 0)
15340Sstevel@tonic-gate return (EXIT_ERROR_ENBL);
15350Sstevel@tonic-gate if (import_err != 0)
15360Sstevel@tonic-gate return (EXIT_ERROR_IMP);
15370Sstevel@tonic-gate if (convert_err != 0)
15380Sstevel@tonic-gate return (EXIT_ERROR_CONV);
15390Sstevel@tonic-gate return (EXIT_SUCCESS);
15400Sstevel@tonic-gate }
1541