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