1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * inetconv - convert inetd.conf entries into smf(5) service manifests, 31*0Sstevel@tonic-gate * import them into smf(5) repository 32*0Sstevel@tonic-gate */ 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate #include <sys/types.h> 35*0Sstevel@tonic-gate #include <sys/param.h> 36*0Sstevel@tonic-gate #include <sys/stat.h> 37*0Sstevel@tonic-gate #include <sys/wait.h> 38*0Sstevel@tonic-gate #include <stdio.h> 39*0Sstevel@tonic-gate #include <stdlib.h> 40*0Sstevel@tonic-gate #include <string.h> 41*0Sstevel@tonic-gate #include <unistd.h> 42*0Sstevel@tonic-gate #include <fcntl.h> 43*0Sstevel@tonic-gate #include <pwd.h> 44*0Sstevel@tonic-gate #include <grp.h> 45*0Sstevel@tonic-gate #include <errno.h> 46*0Sstevel@tonic-gate #include <limits.h> 47*0Sstevel@tonic-gate #include <locale.h> 48*0Sstevel@tonic-gate #include <libintl.h> 49*0Sstevel@tonic-gate #include <libscf.h> 50*0Sstevel@tonic-gate #include <inetsvc.h> 51*0Sstevel@tonic-gate #include <rpc/nettype.h> 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate /* exit codes */ 54*0Sstevel@tonic-gate #define EXIT_SUCCESS 0 /* succeeded */ 55*0Sstevel@tonic-gate #define EXIT_USAGE 1 /* bad options */ 56*0Sstevel@tonic-gate #define EXIT_ERROR_CONV 2 /* error(s) coverting inetd.conf entries */ 57*0Sstevel@tonic-gate #define EXIT_ERROR_IMP 3 /* error(s) importing manifests */ 58*0Sstevel@tonic-gate #define EXIT_ERROR_SYS 4 /* system error */ 59*0Sstevel@tonic-gate #define EXIT_ERROR_ENBL 5 /* error(s) enabling services */ 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate #ifndef TEXT_DOMAIN 62*0Sstevel@tonic-gate #define TEXT_DOMAIN "SUNW_OST_OSCMD" 63*0Sstevel@tonic-gate #endif 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate #define MAIN_CONFIG "/etc/inet/inetd.conf" 66*0Sstevel@tonic-gate #define ALT_CONFIG "/etc/inetd.conf" 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate #define MANIFEST_DIR "/var/svc/manifest/network" 69*0Sstevel@tonic-gate #define MANIFEST_RPC_DIR MANIFEST_DIR ## "/rpc" 70*0Sstevel@tonic-gate #define SVCCFG_PATH "/usr/sbin/svccfg" 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate /* maximum allowed length of an inetd.conf format line */ 73*0Sstevel@tonic-gate #define MAX_SRC_LINELEN 32768 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate /* Version of inetconv, used as a marker in services we generate */ 76*0Sstevel@tonic-gate #define INETCONV_VERSION 1 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate struct inetconfent { 79*0Sstevel@tonic-gate /* fields as read from inetd.conf format line */ 80*0Sstevel@tonic-gate char *service; 81*0Sstevel@tonic-gate char *endpoint; 82*0Sstevel@tonic-gate char *protocol; 83*0Sstevel@tonic-gate char *wait_status; 84*0Sstevel@tonic-gate char *username; 85*0Sstevel@tonic-gate char *server_program; 86*0Sstevel@tonic-gate char *server_args; 87*0Sstevel@tonic-gate /* information derived from above fields */ 88*0Sstevel@tonic-gate boolean_t wait; 89*0Sstevel@tonic-gate boolean_t isrpc; 90*0Sstevel@tonic-gate int rpc_low_version; 91*0Sstevel@tonic-gate int rpc_high_version; 92*0Sstevel@tonic-gate char *rpc_prog; 93*0Sstevel@tonic-gate char *groupname; 94*0Sstevel@tonic-gate char *exec; 95*0Sstevel@tonic-gate char *arg0; 96*0Sstevel@tonic-gate }; 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate struct fileinfo { 99*0Sstevel@tonic-gate FILE *fp; 100*0Sstevel@tonic-gate char *filename; 101*0Sstevel@tonic-gate int lineno; 102*0Sstevel@tonic-gate int failcnt; 103*0Sstevel@tonic-gate }; 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate static char *progname; 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate static boolean_t import = B_TRUE; 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate /* start of manifest XML template strings */ 110*0Sstevel@tonic-gate static const char xml_header[] = 111*0Sstevel@tonic-gate "<?xml version='1.0'?>\n" 112*0Sstevel@tonic-gate "<!DOCTYPE service_bundle SYSTEM " 113*0Sstevel@tonic-gate "'/usr/share/lib/xml/dtd/service_bundle.dtd.1'>\n"; 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate static const char xml_comment[] = 116*0Sstevel@tonic-gate "<!--\n" 117*0Sstevel@tonic-gate " Service manifest for the %s service.\n" 118*0Sstevel@tonic-gate "\n" 119*0Sstevel@tonic-gate " Generated by inetconv(1M) from inetd.conf(4).\n" 120*0Sstevel@tonic-gate "-->\n\n"; 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate static const char xml_service_bundle[] = 123*0Sstevel@tonic-gate "<service_bundle type='manifest' name='inetconv:%s'>\n\n"; 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate static const char xml_service_name[] = 126*0Sstevel@tonic-gate "<service\n" 127*0Sstevel@tonic-gate " name='network/%s'\n" 128*0Sstevel@tonic-gate " type='service'\n" 129*0Sstevel@tonic-gate " version='1'>\n\n"; 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate static const char xml_instance[] = 132*0Sstevel@tonic-gate " <create_default_instance enabled='true'/>\n\n"; 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate static const char xml_restarter[] = 135*0Sstevel@tonic-gate " <restarter>\n" 136*0Sstevel@tonic-gate " <service_fmri value='%s' />\n" 137*0Sstevel@tonic-gate " </restarter>\n\n"; 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate static const char xml_exec_method_start[] = 140*0Sstevel@tonic-gate " <!--\n" 141*0Sstevel@tonic-gate " Set a timeout of 0 to signify to inetd that we don't want to\n" 142*0Sstevel@tonic-gate " timeout this service, since the forked process is the one that\n" 143*0Sstevel@tonic-gate " does the service's work. This is the case for most/all legacy\n" 144*0Sstevel@tonic-gate " inetd services; for services written to take advantage of SMF\n" 145*0Sstevel@tonic-gate " capabilities, the start method should fork off a process to\n" 146*0Sstevel@tonic-gate " handle the request and return a success code.\n" 147*0Sstevel@tonic-gate " -->\n" 148*0Sstevel@tonic-gate " <exec_method\n" 149*0Sstevel@tonic-gate " type='method'\n" 150*0Sstevel@tonic-gate " name='%s'\n" 151*0Sstevel@tonic-gate " %s='%s'\n" 152*0Sstevel@tonic-gate " timeout_seconds='0'>\n" 153*0Sstevel@tonic-gate " <method_context>\n" 154*0Sstevel@tonic-gate " <method_credential %s='%s' group='%s' />\n" 155*0Sstevel@tonic-gate " </method_context>\n"; 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate static const char xml_arg0[] = 158*0Sstevel@tonic-gate " <propval name='%s' type='astring'\n" 159*0Sstevel@tonic-gate " value='%s' />\n"; 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate static const char xml_exec_method_end[] = 162*0Sstevel@tonic-gate " </exec_method>\n\n"; 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate static const char xml_exec_method_disable[] = 165*0Sstevel@tonic-gate " <!--\n" 166*0Sstevel@tonic-gate " Use inetd's built-in kill support to disable services.\n" 167*0Sstevel@tonic-gate " -->\n" 168*0Sstevel@tonic-gate " <exec_method\n" 169*0Sstevel@tonic-gate " type='method'\n" 170*0Sstevel@tonic-gate " name='%s'\n" 171*0Sstevel@tonic-gate " %s=':kill'\n" 172*0Sstevel@tonic-gate " timeout_seconds='0'>\n"; 173*0Sstevel@tonic-gate 174*0Sstevel@tonic-gate static const char xml_exec_method_offline[] = 175*0Sstevel@tonic-gate " <!--\n" 176*0Sstevel@tonic-gate " Use inetd's built-in process kill support to offline wait type\n" 177*0Sstevel@tonic-gate " services.\n" 178*0Sstevel@tonic-gate " -->\n" 179*0Sstevel@tonic-gate " <exec_method\n" 180*0Sstevel@tonic-gate " type='method'\n" 181*0Sstevel@tonic-gate " name='%s'\n" 182*0Sstevel@tonic-gate " %s=':kill_process'\n" 183*0Sstevel@tonic-gate " timeout_seconds='0'>\n"; 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate static const char xml_inetconv_group_start[] = 186*0Sstevel@tonic-gate " <!--\n" 187*0Sstevel@tonic-gate " This property group is used to record information about\n" 188*0Sstevel@tonic-gate " how this manifest was created. It is an implementation\n" 189*0Sstevel@tonic-gate " detail which should not be modified or deleted.\n" 190*0Sstevel@tonic-gate " -->\n" 191*0Sstevel@tonic-gate " <property_group name='%s' type='framework'>\n" 192*0Sstevel@tonic-gate " <propval name='%s' type='boolean' value='%s' />\n" 193*0Sstevel@tonic-gate " <propval name='%s' type='integer' value='%d' />\n" 194*0Sstevel@tonic-gate " <propval name='%s' type='astring' value=\n" 195*0Sstevel@tonic-gate "'%s %s %s %s %s %s%s%s'\n" 196*0Sstevel@tonic-gate " />\n"; 197*0Sstevel@tonic-gate 198*0Sstevel@tonic-gate static const char xml_property_group_start[] = 199*0Sstevel@tonic-gate " <property_group name='%s' type='framework'>\n" 200*0Sstevel@tonic-gate " <propval name='%s' type='astring' value='%s' />\n" 201*0Sstevel@tonic-gate " <propval name='%s' type='astring' value='%s' />\n" 202*0Sstevel@tonic-gate " <propval name='%s' type='astring' value='%s' />\n" 203*0Sstevel@tonic-gate " <propval name='%s' type='boolean' value='%s' />\n" 204*0Sstevel@tonic-gate " <propval name='%s' type='boolean' value='%s' />\n"; 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate static const char xml_property_group_rpc[] = 207*0Sstevel@tonic-gate " <propval name='%s' type='integer' value='%d' />\n" 208*0Sstevel@tonic-gate " <propval name='%s' type='integer' value='%d' />" 209*0Sstevel@tonic-gate "\n"; 210*0Sstevel@tonic-gate 211*0Sstevel@tonic-gate static const char xml_property_group_end[] = 212*0Sstevel@tonic-gate " </property_group>\n\n"; 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate static const char xml_stability[] = 215*0Sstevel@tonic-gate " <stability value='External' />\n\n"; 216*0Sstevel@tonic-gate 217*0Sstevel@tonic-gate static const char xml_template[] = 218*0Sstevel@tonic-gate " <template>\n" 219*0Sstevel@tonic-gate " <common_name>\n" 220*0Sstevel@tonic-gate " <loctext xml:lang='C'>\n" 221*0Sstevel@tonic-gate "%s\n" 222*0Sstevel@tonic-gate " </loctext>\n" 223*0Sstevel@tonic-gate " </common_name>\n" 224*0Sstevel@tonic-gate " </template>\n"; 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate static const char xml_footer[] = 227*0Sstevel@tonic-gate "</service>\n" 228*0Sstevel@tonic-gate "\n" 229*0Sstevel@tonic-gate "</service_bundle>\n"; 230*0Sstevel@tonic-gate /* end of manifest XML template strings */ 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate static void * 233*0Sstevel@tonic-gate safe_malloc(size_t size) 234*0Sstevel@tonic-gate { 235*0Sstevel@tonic-gate void *cp; 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate if ((cp = malloc(size)) == NULL) { 238*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: malloc failed: %s\n"), 239*0Sstevel@tonic-gate progname, strerror(errno)); 240*0Sstevel@tonic-gate exit(EXIT_ERROR_SYS); 241*0Sstevel@tonic-gate } 242*0Sstevel@tonic-gate return (cp); 243*0Sstevel@tonic-gate } 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate static char * 246*0Sstevel@tonic-gate safe_strdup(char *s) 247*0Sstevel@tonic-gate { 248*0Sstevel@tonic-gate char *cp; 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate if ((cp = strdup(s)) == NULL) { 251*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: strdup failed: %s\n"), 252*0Sstevel@tonic-gate progname, strerror(errno)); 253*0Sstevel@tonic-gate exit(EXIT_ERROR_SYS); 254*0Sstevel@tonic-gate } 255*0Sstevel@tonic-gate return (cp); 256*0Sstevel@tonic-gate } 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate static char * 259*0Sstevel@tonic-gate propertyname(char *name, char *prefix) 260*0Sstevel@tonic-gate { 261*0Sstevel@tonic-gate static char *buf; 262*0Sstevel@tonic-gate size_t len; 263*0Sstevel@tonic-gate int c; 264*0Sstevel@tonic-gate char *cp; 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate /* free any memory allocated by a previous call */ 267*0Sstevel@tonic-gate free(buf); 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate len = strlen(name) + strlen(prefix) + 1; 270*0Sstevel@tonic-gate buf = safe_malloc(len); 271*0Sstevel@tonic-gate buf[0] = '\0'; 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gate /* 274*0Sstevel@tonic-gate * Property names must match the regular expression: 275*0Sstevel@tonic-gate * ([A-Za-z][_A-Za-z0-9.-]*,)?[A-Za-z][_A-Za-z0-9-]* 276*0Sstevel@tonic-gate */ 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate /* 279*0Sstevel@tonic-gate * Make sure the first character is alphabetic, if not insert prefix. 280*0Sstevel@tonic-gate * Can't use isalpha() here as its locale dependent but the property 281*0Sstevel@tonic-gate * name regular expression isn't. 282*0Sstevel@tonic-gate */ 283*0Sstevel@tonic-gate c = name[0]; 284*0Sstevel@tonic-gate if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z')) { 285*0Sstevel@tonic-gate (void) strlcat(buf, prefix, len); 286*0Sstevel@tonic-gate } 287*0Sstevel@tonic-gate (void) strlcat(buf, name, len); 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate /* convert any dissallowed characters into '_' */ 290*0Sstevel@tonic-gate for (cp = buf; *cp != '\0'; cp++) { 291*0Sstevel@tonic-gate if ((*cp < 'A' || *cp > 'Z') && (*cp < 'a' || *cp > 'z') && 292*0Sstevel@tonic-gate (*cp < '0' || *cp > '9') && (*cp != '.') && (*cp != '-')) 293*0Sstevel@tonic-gate *cp = '_'; 294*0Sstevel@tonic-gate } 295*0Sstevel@tonic-gate return (buf); 296*0Sstevel@tonic-gate } 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate static char * 299*0Sstevel@tonic-gate servicename(struct inetconfent *iconf) 300*0Sstevel@tonic-gate { 301*0Sstevel@tonic-gate static char *buf; 302*0Sstevel@tonic-gate size_t len; 303*0Sstevel@tonic-gate char *proto; 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate /* free any memory allocated by a previous call */ 306*0Sstevel@tonic-gate free(buf); 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate len = strlen(iconf->service) + strlen(iconf->protocol) + 309*0Sstevel@tonic-gate sizeof ("rpc-/visible"); 310*0Sstevel@tonic-gate buf = safe_malloc(len); 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate /* 313*0Sstevel@tonic-gate * Combine the service and protocol fields to produce a unique 314*0Sstevel@tonic-gate * manifest service name. The syntax of a service name is: 315*0Sstevel@tonic-gate * prop(/prop)* 316*0Sstevel@tonic-gate */ 317*0Sstevel@tonic-gate (void) strlcpy(buf, propertyname(iconf->service, 318*0Sstevel@tonic-gate iconf->isrpc ? "rpc-": "s-"), len); 319*0Sstevel@tonic-gate (void) strlcat(buf, "/", len); 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate proto = iconf->protocol; 322*0Sstevel@tonic-gate if (iconf->isrpc && (strcmp(iconf->protocol, "rpc/*") == 0)) 323*0Sstevel@tonic-gate proto = "rpc/visible"; 324*0Sstevel@tonic-gate (void) strlcat(buf, propertyname(proto, "p-"), len); 325*0Sstevel@tonic-gate return (buf); 326*0Sstevel@tonic-gate } 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate static boolean_t 329*0Sstevel@tonic-gate is_v6only(char *protocol) 330*0Sstevel@tonic-gate { 331*0Sstevel@tonic-gate /* returns true if protocol is an IPv6 only protocol */ 332*0Sstevel@tonic-gate if ((strcmp(protocol, SOCKET_PROTO_TCP6_ONLY) == 0) || 333*0Sstevel@tonic-gate (strcmp(protocol, SOCKET_PROTO_UDP6_ONLY) == 0)) 334*0Sstevel@tonic-gate return (B_TRUE); 335*0Sstevel@tonic-gate return (B_FALSE); 336*0Sstevel@tonic-gate } 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate static char * 339*0Sstevel@tonic-gate invalid_props(inetd_prop_t *p) 340*0Sstevel@tonic-gate { 341*0Sstevel@tonic-gate static char 342*0Sstevel@tonic-gate buf[sizeof (" service-name endpoint-type protocol wait-status")]; 343*0Sstevel@tonic-gate 344*0Sstevel@tonic-gate buf[0] = '\0'; 345*0Sstevel@tonic-gate if ((p[PT_SVC_NAME_INDEX].ip_error == IVE_INVALID) || 346*0Sstevel@tonic-gate (p[PT_SVC_NAME_INDEX].ip_error == IVE_UNSET) || 347*0Sstevel@tonic-gate (p[PT_RPC_LW_VER_INDEX].ip_error == IVE_INVALID) || 348*0Sstevel@tonic-gate (p[PT_RPC_HI_VER_INDEX].ip_error == IVE_INVALID)) 349*0Sstevel@tonic-gate (void) strlcat(buf, " service-name", sizeof (buf)); 350*0Sstevel@tonic-gate if ((p[PT_SOCK_TYPE_INDEX].ip_error == IVE_INVALID) || 351*0Sstevel@tonic-gate (p[PT_SOCK_TYPE_INDEX].ip_error == IVE_UNSET)) 352*0Sstevel@tonic-gate (void) strlcat(buf, " endpoint-type", sizeof (buf)); 353*0Sstevel@tonic-gate if ((p[PT_PROTO_INDEX].ip_error == IVE_INVALID) || 354*0Sstevel@tonic-gate (p[PT_PROTO_INDEX].ip_error == IVE_UNSET) || 355*0Sstevel@tonic-gate (p[PT_ISRPC_INDEX].ip_error == IVE_INVALID)) 356*0Sstevel@tonic-gate (void) strlcat(buf, " protocol", sizeof (buf)); 357*0Sstevel@tonic-gate if (p[PT_ISWAIT_INDEX].ip_error == IVE_INVALID) 358*0Sstevel@tonic-gate (void) strlcat(buf, " wait-status", sizeof (buf)); 359*0Sstevel@tonic-gate return (buf); 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate /* 363*0Sstevel@tonic-gate * wrapper around put_prop_value() that errors and exits on malloc failures, 364*0Sstevel@tonic-gate * returns -1 on other failures, else returns 0. 365*0Sstevel@tonic-gate */ 366*0Sstevel@tonic-gate static int 367*0Sstevel@tonic-gate my_put_prop_value(inetd_prop_t *props, char *pname, void *value) 368*0Sstevel@tonic-gate { 369*0Sstevel@tonic-gate if (put_prop_value(props, pname, value) == 0) 370*0Sstevel@tonic-gate return (0); 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate if (errno == ENOMEM) { 373*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: malloc failed: %s\n"), 374*0Sstevel@tonic-gate progname, strerror(errno)); 375*0Sstevel@tonic-gate exit(EXIT_ERROR_SYS); 376*0Sstevel@tonic-gate } 377*0Sstevel@tonic-gate return (-1); 378*0Sstevel@tonic-gate } 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate static boolean_t 381*0Sstevel@tonic-gate valid_basic_properties(struct inetconfent *iconf, struct fileinfo *finfo) 382*0Sstevel@tonic-gate { 383*0Sstevel@tonic-gate size_t prop_size; 384*0Sstevel@tonic-gate inetd_prop_t *prop, *inetd_properties; 385*0Sstevel@tonic-gate boolean_t valid = B_TRUE; 386*0Sstevel@tonic-gate char *proto = iconf->protocol; 387*0Sstevel@tonic-gate char *svc_name = iconf->service; 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate inetd_properties = get_prop_table(&prop_size); 390*0Sstevel@tonic-gate prop = safe_malloc(prop_size * sizeof (inetd_prop_t)); 391*0Sstevel@tonic-gate (void) memcpy(prop, inetd_properties, 392*0Sstevel@tonic-gate prop_size * sizeof (inetd_prop_t)); 393*0Sstevel@tonic-gate 394*0Sstevel@tonic-gate (void) put_prop_value(prop, PR_ISRPC_NAME, &iconf->isrpc); 395*0Sstevel@tonic-gate (void) put_prop_value(prop, PR_ISWAIT_NAME, &iconf->wait); 396*0Sstevel@tonic-gate if (iconf->isrpc) { 397*0Sstevel@tonic-gate (void) put_prop_value(prop, PR_RPC_LW_VER_NAME, 398*0Sstevel@tonic-gate &iconf->rpc_low_version); 399*0Sstevel@tonic-gate (void) put_prop_value(prop, PR_RPC_HI_VER_NAME, 400*0Sstevel@tonic-gate &iconf->rpc_high_version); 401*0Sstevel@tonic-gate svc_name = iconf->rpc_prog; 402*0Sstevel@tonic-gate proto += 4; /* skip 'rpc/' */ 403*0Sstevel@tonic-gate } 404*0Sstevel@tonic-gate 405*0Sstevel@tonic-gate if ((my_put_prop_value(prop, PR_SOCK_TYPE_NAME, iconf->endpoint) 406*0Sstevel@tonic-gate != 0) || 407*0Sstevel@tonic-gate (my_put_prop_value(prop, PR_SVC_NAME_NAME, svc_name) != 0) || 408*0Sstevel@tonic-gate (my_put_prop_value(prop, PR_PROTO_NAME, proto) != 0)) 409*0Sstevel@tonic-gate valid = B_FALSE; 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate if (!valid_props(prop, NULL, NULL, NULL, NULL) || !valid) { 412*0Sstevel@tonic-gate valid = B_FALSE; 413*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error %s line %d " 414*0Sstevel@tonic-gate "invalid or inconsistent fields:%s\n"), progname, 415*0Sstevel@tonic-gate finfo->filename, finfo->lineno, 416*0Sstevel@tonic-gate invalid_props(prop)); 417*0Sstevel@tonic-gate } 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate free_instance_props(prop); 420*0Sstevel@tonic-gate return (valid); 421*0Sstevel@tonic-gate } 422*0Sstevel@tonic-gate 423*0Sstevel@tonic-gate static boolean_t 424*0Sstevel@tonic-gate valid_inetconfent(struct inetconfent *iconf, struct fileinfo *finfo) 425*0Sstevel@tonic-gate { 426*0Sstevel@tonic-gate boolean_t valid = B_TRUE; 427*0Sstevel@tonic-gate size_t len; 428*0Sstevel@tonic-gate char *cp, *endp; 429*0Sstevel@tonic-gate struct passwd *pwd; 430*0Sstevel@tonic-gate struct group *grp; 431*0Sstevel@tonic-gate struct stat statb; 432*0Sstevel@tonic-gate char *proto = iconf->protocol; 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate iconf->isrpc = B_FALSE; 435*0Sstevel@tonic-gate if (strncmp(iconf->protocol, "rpc/", 4) == 0) { 436*0Sstevel@tonic-gate iconf->isrpc = B_TRUE; 437*0Sstevel@tonic-gate iconf->rpc_prog = safe_strdup(iconf->service); 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate /* set RPC version numbers */ 440*0Sstevel@tonic-gate iconf->rpc_low_version = 1; 441*0Sstevel@tonic-gate iconf->rpc_high_version = 1; 442*0Sstevel@tonic-gate if ((cp = strrchr(iconf->rpc_prog, '/')) != NULL) { 443*0Sstevel@tonic-gate *cp = '\0'; 444*0Sstevel@tonic-gate if (*++cp != '\0') { 445*0Sstevel@tonic-gate errno = 0; 446*0Sstevel@tonic-gate iconf->rpc_low_version = strtol(cp, &endp, 10); 447*0Sstevel@tonic-gate if (errno != 0) 448*0Sstevel@tonic-gate goto vererr; 449*0Sstevel@tonic-gate cp = endp; 450*0Sstevel@tonic-gate if (*cp == '-') { 451*0Sstevel@tonic-gate if (*++cp == '\0') 452*0Sstevel@tonic-gate goto vererr; 453*0Sstevel@tonic-gate errno = 0; 454*0Sstevel@tonic-gate iconf->rpc_high_version = strtol(cp, 455*0Sstevel@tonic-gate &endp, 10); 456*0Sstevel@tonic-gate if ((errno != 0) || (*endp != '\0')) 457*0Sstevel@tonic-gate goto vererr; 458*0Sstevel@tonic-gate } else if (*cp == '\0') { 459*0Sstevel@tonic-gate iconf->rpc_high_version = 460*0Sstevel@tonic-gate iconf->rpc_low_version; 461*0Sstevel@tonic-gate } else { 462*0Sstevel@tonic-gate vererr: 463*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 464*0Sstevel@tonic-gate "%s: Error %s line %d invalid RPC " 465*0Sstevel@tonic-gate "version in service: %s\n"), 466*0Sstevel@tonic-gate progname, finfo->filename, 467*0Sstevel@tonic-gate finfo->lineno, iconf->service); 468*0Sstevel@tonic-gate valid = B_FALSE; 469*0Sstevel@tonic-gate } 470*0Sstevel@tonic-gate } 471*0Sstevel@tonic-gate } 472*0Sstevel@tonic-gate proto += 4; /* skip 'rpc/' */ 473*0Sstevel@tonic-gate } 474*0Sstevel@tonic-gate /* tcp6only and udp6only are not valid in inetd.conf */ 475*0Sstevel@tonic-gate if (is_v6only(proto)) { 476*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error %s line %d " 477*0Sstevel@tonic-gate "invalid protocol: %s\n"), progname, 478*0Sstevel@tonic-gate finfo->filename, finfo->lineno, proto); 479*0Sstevel@tonic-gate valid = B_FALSE; 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate if (strcmp(iconf->wait_status, "wait") == 0) { 483*0Sstevel@tonic-gate iconf->wait = B_TRUE; 484*0Sstevel@tonic-gate } else if (strcmp(iconf->wait_status, "nowait") == 0) { 485*0Sstevel@tonic-gate iconf->wait = B_FALSE; 486*0Sstevel@tonic-gate } else { 487*0Sstevel@tonic-gate (void) fprintf(stderr, 488*0Sstevel@tonic-gate gettext("%s: Error %s line %d invalid wait-status: %s\n"), 489*0Sstevel@tonic-gate progname, finfo->filename, finfo->lineno, 490*0Sstevel@tonic-gate iconf->wait_status); 491*0Sstevel@tonic-gate valid = B_FALSE; 492*0Sstevel@tonic-gate } 493*0Sstevel@tonic-gate 494*0Sstevel@tonic-gate /* look up the username to set the groupname */ 495*0Sstevel@tonic-gate if ((pwd = getpwnam(iconf->username)) == NULL) { 496*0Sstevel@tonic-gate (void) fprintf(stderr, 497*0Sstevel@tonic-gate gettext("%s: Error %s line %d unknown user: %s\n"), 498*0Sstevel@tonic-gate progname, finfo->filename, finfo->lineno, 499*0Sstevel@tonic-gate iconf->username); 500*0Sstevel@tonic-gate valid = B_FALSE; 501*0Sstevel@tonic-gate } else { 502*0Sstevel@tonic-gate if ((grp = getgrgid(pwd->pw_gid)) != NULL) { 503*0Sstevel@tonic-gate iconf->groupname = safe_strdup(grp->gr_name); 504*0Sstevel@tonic-gate } else { 505*0Sstevel@tonic-gate /* use the group ID if no groupname */ 506*0Sstevel@tonic-gate char s[1]; 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate len = snprintf(s, 1, "%d", pwd->pw_gid) + 1; 509*0Sstevel@tonic-gate iconf->groupname = safe_malloc(len); 510*0Sstevel@tonic-gate (void) snprintf(iconf->groupname, len, "%d", 511*0Sstevel@tonic-gate pwd->pw_gid); 512*0Sstevel@tonic-gate } 513*0Sstevel@tonic-gate } 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gate /* check for internal services */ 516*0Sstevel@tonic-gate if (strcmp(iconf->server_program, "internal") == 0) { 517*0Sstevel@tonic-gate valid = B_FALSE; 518*0Sstevel@tonic-gate if ((strcmp(iconf->service, "echo") == 0) || 519*0Sstevel@tonic-gate (strcmp(iconf->service, "discard") == 0) || 520*0Sstevel@tonic-gate (strcmp(iconf->service, "time") == 0) || 521*0Sstevel@tonic-gate (strcmp(iconf->service, "daytime") == 0) || 522*0Sstevel@tonic-gate (strcmp(iconf->service, "chargen") == 0)) { 523*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 524*0Sstevel@tonic-gate "%s: Error %s line %d the SUNWcnsr and SUNWcnsu" 525*0Sstevel@tonic-gate " packages contain the internal services\n"), 526*0Sstevel@tonic-gate progname, finfo->filename, finfo->lineno); 527*0Sstevel@tonic-gate } else { 528*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error %s line %d " 529*0Sstevel@tonic-gate "unknown internal service: %s\n"), progname, 530*0Sstevel@tonic-gate finfo->filename, finfo->lineno, iconf->service); 531*0Sstevel@tonic-gate } 532*0Sstevel@tonic-gate } else if ((stat(iconf->server_program, &statb) == -1) && 533*0Sstevel@tonic-gate (errno == ENOENT)) { 534*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 535*0Sstevel@tonic-gate "%s: Error %s line %d server-program not found: %s\n"), 536*0Sstevel@tonic-gate progname, finfo->filename, finfo->lineno, 537*0Sstevel@tonic-gate iconf->server_program); 538*0Sstevel@tonic-gate valid = B_FALSE; 539*0Sstevel@tonic-gate } 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate return (valid && valid_basic_properties(iconf, finfo)); 542*0Sstevel@tonic-gate } 543*0Sstevel@tonic-gate 544*0Sstevel@tonic-gate static void 545*0Sstevel@tonic-gate free_inetconfent(struct inetconfent *iconf) 546*0Sstevel@tonic-gate { 547*0Sstevel@tonic-gate if (iconf == NULL) 548*0Sstevel@tonic-gate return; 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate free(iconf->service); 551*0Sstevel@tonic-gate free(iconf->endpoint); 552*0Sstevel@tonic-gate free(iconf->protocol); 553*0Sstevel@tonic-gate free(iconf->wait_status); 554*0Sstevel@tonic-gate free(iconf->username); 555*0Sstevel@tonic-gate free(iconf->server_program); 556*0Sstevel@tonic-gate free(iconf->server_args); 557*0Sstevel@tonic-gate free(iconf->rpc_prog); 558*0Sstevel@tonic-gate free(iconf->groupname); 559*0Sstevel@tonic-gate free(iconf->exec); 560*0Sstevel@tonic-gate free(iconf->arg0); 561*0Sstevel@tonic-gate 562*0Sstevel@tonic-gate free(iconf); 563*0Sstevel@tonic-gate } 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate static struct inetconfent * 566*0Sstevel@tonic-gate line_to_inetconfent(char *line) 567*0Sstevel@tonic-gate { 568*0Sstevel@tonic-gate char *cp; 569*0Sstevel@tonic-gate struct inetconfent *iconf; 570*0Sstevel@tonic-gate 571*0Sstevel@tonic-gate iconf = safe_malloc(sizeof (struct inetconfent)); 572*0Sstevel@tonic-gate (void) memset(iconf, 0, sizeof (struct inetconfent)); 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate if ((cp = strtok(line, " \t\n")) == NULL) 575*0Sstevel@tonic-gate goto fail; 576*0Sstevel@tonic-gate iconf->service = safe_strdup(cp); 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate if ((cp = strtok(NULL, " \t\n")) == NULL) 579*0Sstevel@tonic-gate goto fail; 580*0Sstevel@tonic-gate iconf->endpoint = safe_strdup(cp); 581*0Sstevel@tonic-gate 582*0Sstevel@tonic-gate if ((cp = strtok(NULL, " \t\n")) == NULL) 583*0Sstevel@tonic-gate goto fail; 584*0Sstevel@tonic-gate iconf->protocol = safe_strdup(cp); 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate if ((cp = strtok(NULL, " \t\n")) == NULL) 587*0Sstevel@tonic-gate goto fail; 588*0Sstevel@tonic-gate iconf->wait_status = safe_strdup(cp); 589*0Sstevel@tonic-gate 590*0Sstevel@tonic-gate if ((cp = strtok(NULL, " \t\n")) == NULL) 591*0Sstevel@tonic-gate goto fail; 592*0Sstevel@tonic-gate iconf->username = safe_strdup(cp); 593*0Sstevel@tonic-gate 594*0Sstevel@tonic-gate if ((cp = strtok(NULL, " \t\n")) == NULL) 595*0Sstevel@tonic-gate goto fail; 596*0Sstevel@tonic-gate iconf->server_program = safe_strdup(cp); 597*0Sstevel@tonic-gate 598*0Sstevel@tonic-gate /* last field is optional */ 599*0Sstevel@tonic-gate if ((cp = strtok(NULL, "\n")) != NULL) 600*0Sstevel@tonic-gate iconf->server_args = safe_strdup(cp); 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate /* Combine args and server name to construct exec and args fields */ 603*0Sstevel@tonic-gate if (iconf->server_args == NULL) { 604*0Sstevel@tonic-gate iconf->exec = safe_strdup(iconf->server_program); 605*0Sstevel@tonic-gate } else { 606*0Sstevel@tonic-gate int len; 607*0Sstevel@tonic-gate char *args, *endp; 608*0Sstevel@tonic-gate 609*0Sstevel@tonic-gate len = strlen(iconf->server_program) + 610*0Sstevel@tonic-gate strlen(iconf->server_args) + 1; 611*0Sstevel@tonic-gate iconf->exec = safe_malloc(len); 612*0Sstevel@tonic-gate (void) strlcpy(iconf->exec, iconf->server_program, len); 613*0Sstevel@tonic-gate 614*0Sstevel@tonic-gate args = safe_strdup(iconf->server_args); 615*0Sstevel@tonic-gate if ((cp = strtok(args, " \t")) != NULL) { 616*0Sstevel@tonic-gate if ((endp = strrchr(iconf->exec, '/')) == NULL) 617*0Sstevel@tonic-gate endp = iconf->exec; 618*0Sstevel@tonic-gate else 619*0Sstevel@tonic-gate endp++; 620*0Sstevel@tonic-gate /* only set arg0 property value if needed */ 621*0Sstevel@tonic-gate if (strcmp(endp, cp) != 0) 622*0Sstevel@tonic-gate iconf->arg0 = safe_strdup(cp); 623*0Sstevel@tonic-gate while ((cp = strtok(NULL, " \t")) != NULL) { 624*0Sstevel@tonic-gate (void) strlcat(iconf->exec, " ", len); 625*0Sstevel@tonic-gate (void) strlcat(iconf->exec, cp, len); 626*0Sstevel@tonic-gate } 627*0Sstevel@tonic-gate } 628*0Sstevel@tonic-gate free(args); 629*0Sstevel@tonic-gate } 630*0Sstevel@tonic-gate 631*0Sstevel@tonic-gate return (iconf); 632*0Sstevel@tonic-gate fail: 633*0Sstevel@tonic-gate free_inetconfent(iconf); 634*0Sstevel@tonic-gate return (NULL); 635*0Sstevel@tonic-gate } 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate static void 638*0Sstevel@tonic-gate skipline(FILE *fp) 639*0Sstevel@tonic-gate { 640*0Sstevel@tonic-gate int c; 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gate /* skip remainder of a line */ 643*0Sstevel@tonic-gate while (((c = getc(fp)) != EOF) && (c != '\n')) 644*0Sstevel@tonic-gate ; 645*0Sstevel@tonic-gate } 646*0Sstevel@tonic-gate 647*0Sstevel@tonic-gate static struct inetconfent * 648*0Sstevel@tonic-gate fgetinetconfent(struct fileinfo *finfo, boolean_t validate) 649*0Sstevel@tonic-gate { 650*0Sstevel@tonic-gate char *cp; 651*0Sstevel@tonic-gate struct inetconfent *iconf; 652*0Sstevel@tonic-gate char line[MAX_SRC_LINELEN]; 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gate while (fgets(line, sizeof (line), finfo->fp) != NULL) { 655*0Sstevel@tonic-gate finfo->lineno++; 656*0Sstevel@tonic-gate 657*0Sstevel@tonic-gate /* skip empty or commented out lines */ 658*0Sstevel@tonic-gate if (*line == '\n') 659*0Sstevel@tonic-gate continue; 660*0Sstevel@tonic-gate if (*line == '#') { 661*0Sstevel@tonic-gate if (line[strlen(line) - 1] != '\n') 662*0Sstevel@tonic-gate skipline(finfo->fp); 663*0Sstevel@tonic-gate continue; 664*0Sstevel@tonic-gate } 665*0Sstevel@tonic-gate /* check for lines which are too long */ 666*0Sstevel@tonic-gate if (line[strlen(line) - 1] != '\n') { 667*0Sstevel@tonic-gate (void) fprintf(stderr, 668*0Sstevel@tonic-gate gettext("%s: Error %s line %d too long, skipped\n"), 669*0Sstevel@tonic-gate progname, finfo->filename, finfo->lineno); 670*0Sstevel@tonic-gate skipline(finfo->fp); 671*0Sstevel@tonic-gate finfo->failcnt++; 672*0Sstevel@tonic-gate continue; 673*0Sstevel@tonic-gate } 674*0Sstevel@tonic-gate /* remove in line comments and newline character */ 675*0Sstevel@tonic-gate if ((cp = strchr(line, '#')) == NULL) 676*0Sstevel@tonic-gate cp = strchr(line, '\n'); 677*0Sstevel@tonic-gate if (cp) 678*0Sstevel@tonic-gate *cp = '\0'; 679*0Sstevel@tonic-gate 680*0Sstevel@tonic-gate if ((iconf = line_to_inetconfent(line)) == NULL) { 681*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 682*0Sstevel@tonic-gate "%s: Error %s line %d too few fields, skipped\n"), 683*0Sstevel@tonic-gate progname, finfo->filename, finfo->lineno); 684*0Sstevel@tonic-gate finfo->failcnt++; 685*0Sstevel@tonic-gate continue; 686*0Sstevel@tonic-gate } 687*0Sstevel@tonic-gate 688*0Sstevel@tonic-gate if (!validate || valid_inetconfent(iconf, finfo)) 689*0Sstevel@tonic-gate return (iconf); 690*0Sstevel@tonic-gate 691*0Sstevel@tonic-gate finfo->failcnt++; 692*0Sstevel@tonic-gate free_inetconfent(iconf); 693*0Sstevel@tonic-gate } 694*0Sstevel@tonic-gate return (NULL); 695*0Sstevel@tonic-gate } 696*0Sstevel@tonic-gate 697*0Sstevel@tonic-gate static char * 698*0Sstevel@tonic-gate boolstr(boolean_t val) 699*0Sstevel@tonic-gate { 700*0Sstevel@tonic-gate if (val) 701*0Sstevel@tonic-gate return ("true"); 702*0Sstevel@tonic-gate return ("false"); 703*0Sstevel@tonic-gate } 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate static int 706*0Sstevel@tonic-gate print_manifest(FILE *f, char *filename, struct inetconfent *iconf) 707*0Sstevel@tonic-gate { 708*0Sstevel@tonic-gate if (fprintf(f, xml_header) < 0) 709*0Sstevel@tonic-gate goto print_err; 710*0Sstevel@tonic-gate 711*0Sstevel@tonic-gate if (fprintf(f, xml_comment, 712*0Sstevel@tonic-gate iconf->isrpc ? iconf->rpc_prog : iconf->service) < 0) 713*0Sstevel@tonic-gate goto print_err; 714*0Sstevel@tonic-gate 715*0Sstevel@tonic-gate if (fprintf(f, xml_service_bundle, iconf->service) < 0) 716*0Sstevel@tonic-gate goto print_err; 717*0Sstevel@tonic-gate if (fprintf(f, xml_service_name, servicename(iconf)) < 0) 718*0Sstevel@tonic-gate goto print_err; 719*0Sstevel@tonic-gate if (fprintf(f, xml_instance) < 0) 720*0Sstevel@tonic-gate goto print_err; 721*0Sstevel@tonic-gate if (fprintf(f, xml_restarter, INETD_INSTANCE_FMRI) < 0) 722*0Sstevel@tonic-gate goto print_err; 723*0Sstevel@tonic-gate 724*0Sstevel@tonic-gate if (fprintf(f, xml_exec_method_start, START_METHOD_NAME, PR_EXEC_NAME, 725*0Sstevel@tonic-gate iconf->exec, PR_USER_NAME, iconf->username, iconf->groupname) < 0) 726*0Sstevel@tonic-gate goto print_err; 727*0Sstevel@tonic-gate if (iconf->arg0 != NULL) { 728*0Sstevel@tonic-gate if (fprintf(f, xml_arg0, PR_ARG0_NAME, iconf->arg0) < 0) 729*0Sstevel@tonic-gate goto print_err; 730*0Sstevel@tonic-gate } 731*0Sstevel@tonic-gate if (fprintf(f, xml_exec_method_end) < 0) 732*0Sstevel@tonic-gate goto print_err; 733*0Sstevel@tonic-gate 734*0Sstevel@tonic-gate if (fprintf(f, xml_exec_method_disable, DISABLE_METHOD_NAME, 735*0Sstevel@tonic-gate PR_EXEC_NAME) < 0) 736*0Sstevel@tonic-gate goto print_err; 737*0Sstevel@tonic-gate if (fprintf(f, xml_exec_method_end) < 0) 738*0Sstevel@tonic-gate goto print_err; 739*0Sstevel@tonic-gate 740*0Sstevel@tonic-gate if (iconf->wait) { 741*0Sstevel@tonic-gate if (fprintf(f, xml_exec_method_offline, OFFLINE_METHOD_NAME, 742*0Sstevel@tonic-gate PR_EXEC_NAME) < 0) 743*0Sstevel@tonic-gate goto print_err; 744*0Sstevel@tonic-gate if (fprintf(f, xml_exec_method_end) < 0) 745*0Sstevel@tonic-gate goto print_err; 746*0Sstevel@tonic-gate } 747*0Sstevel@tonic-gate 748*0Sstevel@tonic-gate if (fprintf(f, xml_inetconv_group_start, PG_NAME_INETCONV, 749*0Sstevel@tonic-gate PR_AUTO_CONVERTED_NAME, boolstr(B_TRUE), 750*0Sstevel@tonic-gate PR_VERSION_NAME, INETCONV_VERSION, 751*0Sstevel@tonic-gate PR_SOURCE_LINE_NAME, iconf->service, 752*0Sstevel@tonic-gate iconf->endpoint, iconf->protocol, iconf->wait_status, 753*0Sstevel@tonic-gate iconf->username, iconf->server_program, 754*0Sstevel@tonic-gate iconf->server_args == NULL ? "" : " ", 755*0Sstevel@tonic-gate iconf->server_args == NULL ? "" : iconf->server_args) < 0) 756*0Sstevel@tonic-gate goto print_err; 757*0Sstevel@tonic-gate if (fprintf(f, xml_property_group_end) < 0) 758*0Sstevel@tonic-gate goto print_err; 759*0Sstevel@tonic-gate 760*0Sstevel@tonic-gate if (fprintf(f, xml_property_group_start, PG_NAME_SERVICE_CONFIG, 761*0Sstevel@tonic-gate PR_SVC_NAME_NAME, iconf->isrpc ? iconf->rpc_prog : iconf->service, 762*0Sstevel@tonic-gate PR_SOCK_TYPE_NAME, iconf->endpoint, 763*0Sstevel@tonic-gate PR_PROTO_NAME, iconf->isrpc ? iconf->protocol + 4 : 764*0Sstevel@tonic-gate iconf->protocol, 765*0Sstevel@tonic-gate PR_ISWAIT_NAME, boolstr(iconf->wait), 766*0Sstevel@tonic-gate PR_ISRPC_NAME, boolstr(iconf->isrpc)) < 0) 767*0Sstevel@tonic-gate goto print_err; 768*0Sstevel@tonic-gate if (iconf->isrpc) { 769*0Sstevel@tonic-gate if (fprintf(f, xml_property_group_rpc, 770*0Sstevel@tonic-gate PR_RPC_LW_VER_NAME, iconf->rpc_low_version, 771*0Sstevel@tonic-gate PR_RPC_HI_VER_NAME, iconf->rpc_high_version) < 0) 772*0Sstevel@tonic-gate goto print_err; 773*0Sstevel@tonic-gate } 774*0Sstevel@tonic-gate if (fprintf(f, xml_property_group_end) < 0) 775*0Sstevel@tonic-gate goto print_err; 776*0Sstevel@tonic-gate 777*0Sstevel@tonic-gate if (fprintf(f, xml_stability) < 0) 778*0Sstevel@tonic-gate goto print_err; 779*0Sstevel@tonic-gate if (fprintf(f, xml_template, 780*0Sstevel@tonic-gate iconf->isrpc ? iconf->rpc_prog : iconf->service) < 0) 781*0Sstevel@tonic-gate goto print_err; 782*0Sstevel@tonic-gate if (fprintf(f, xml_footer) < 0) 783*0Sstevel@tonic-gate goto print_err; 784*0Sstevel@tonic-gate 785*0Sstevel@tonic-gate (void) printf("%s -> %s\n", iconf->service, filename); 786*0Sstevel@tonic-gate return (0); 787*0Sstevel@tonic-gate 788*0Sstevel@tonic-gate print_err: 789*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error writing manifest %s: %s\n"), 790*0Sstevel@tonic-gate progname, filename, strerror(errno)); 791*0Sstevel@tonic-gate return (-1); 792*0Sstevel@tonic-gate } 793*0Sstevel@tonic-gate 794*0Sstevel@tonic-gate static struct fileinfo * 795*0Sstevel@tonic-gate open_srcfile(char *filename) 796*0Sstevel@tonic-gate { 797*0Sstevel@tonic-gate struct fileinfo *finfo = NULL; 798*0Sstevel@tonic-gate FILE *fp; 799*0Sstevel@tonic-gate 800*0Sstevel@tonic-gate if (filename != NULL) { 801*0Sstevel@tonic-gate if ((fp = fopen(filename, "r")) == NULL) { 802*0Sstevel@tonic-gate (void) fprintf(stderr, 803*0Sstevel@tonic-gate gettext("%s: Error opening %s: %s\n"), 804*0Sstevel@tonic-gate progname, filename, strerror(errno)); 805*0Sstevel@tonic-gate } 806*0Sstevel@tonic-gate } else { 807*0Sstevel@tonic-gate /* 808*0Sstevel@tonic-gate * If no source file specified, do the same as inetd and first 809*0Sstevel@tonic-gate * try /etc/inet/inetd.conf, followed by /etc/inetd.conf. 810*0Sstevel@tonic-gate */ 811*0Sstevel@tonic-gate filename = MAIN_CONFIG; 812*0Sstevel@tonic-gate if ((fp = fopen(filename, "r")) == NULL) { 813*0Sstevel@tonic-gate (void) fprintf(stderr, 814*0Sstevel@tonic-gate gettext("%s: Error opening %s: %s\n"), 815*0Sstevel@tonic-gate progname, filename, strerror(errno)); 816*0Sstevel@tonic-gate filename = ALT_CONFIG; 817*0Sstevel@tonic-gate if ((fp = fopen(filename, "r")) == NULL) { 818*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 819*0Sstevel@tonic-gate "%s: Error opening %s: %s\n"), progname, 820*0Sstevel@tonic-gate filename, strerror(errno)); 821*0Sstevel@tonic-gate } 822*0Sstevel@tonic-gate } 823*0Sstevel@tonic-gate } 824*0Sstevel@tonic-gate if (fp != NULL) { 825*0Sstevel@tonic-gate finfo = safe_malloc(sizeof (struct fileinfo)); 826*0Sstevel@tonic-gate finfo->fp = fp; 827*0Sstevel@tonic-gate finfo->filename = filename; 828*0Sstevel@tonic-gate finfo->lineno = 0; 829*0Sstevel@tonic-gate finfo->failcnt = 0; 830*0Sstevel@tonic-gate (void) fcntl(fileno(fp), F_SETFD, FD_CLOEXEC); 831*0Sstevel@tonic-gate } 832*0Sstevel@tonic-gate return (finfo); 833*0Sstevel@tonic-gate } 834*0Sstevel@tonic-gate 835*0Sstevel@tonic-gate /* 836*0Sstevel@tonic-gate * Opens manifest output file. Returns 0 on success, -1 if the file 837*0Sstevel@tonic-gate * exists, -2 on other errors. 838*0Sstevel@tonic-gate */ 839*0Sstevel@tonic-gate static int 840*0Sstevel@tonic-gate open_dstfile( 841*0Sstevel@tonic-gate char *destdir, 842*0Sstevel@tonic-gate boolean_t overwrite, 843*0Sstevel@tonic-gate struct inetconfent *iconf, 844*0Sstevel@tonic-gate struct fileinfo **finfo) 845*0Sstevel@tonic-gate { 846*0Sstevel@tonic-gate int fd; 847*0Sstevel@tonic-gate size_t len; 848*0Sstevel@tonic-gate char *dstfile, *cp, *proto; 849*0Sstevel@tonic-gate FILE *fp; 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate /* if no destdir specified, use appropriate default */ 852*0Sstevel@tonic-gate if (destdir == NULL) { 853*0Sstevel@tonic-gate if (iconf->isrpc) 854*0Sstevel@tonic-gate destdir = MANIFEST_RPC_DIR; 855*0Sstevel@tonic-gate else 856*0Sstevel@tonic-gate destdir = MANIFEST_DIR; 857*0Sstevel@tonic-gate } 858*0Sstevel@tonic-gate 859*0Sstevel@tonic-gate len = strlen(destdir) + strlen(iconf->service) + 860*0Sstevel@tonic-gate strlen(iconf->protocol) + sizeof ("/-visible.xml"); 861*0Sstevel@tonic-gate dstfile = safe_malloc(len); 862*0Sstevel@tonic-gate 863*0Sstevel@tonic-gate (void) strlcpy(dstfile, destdir, len); 864*0Sstevel@tonic-gate if (dstfile[strlen(dstfile) - 1] != '/') 865*0Sstevel@tonic-gate (void) strlcat(dstfile, "/", len); 866*0Sstevel@tonic-gate cp = dstfile + strlen(dstfile); 867*0Sstevel@tonic-gate 868*0Sstevel@tonic-gate (void) strlcat(dstfile, iconf->service, len); 869*0Sstevel@tonic-gate (void) strlcat(dstfile, "-", len); 870*0Sstevel@tonic-gate 871*0Sstevel@tonic-gate proto = iconf->protocol; 872*0Sstevel@tonic-gate if (iconf->isrpc && (strcmp(iconf->protocol, "rpc/*") == 0)) 873*0Sstevel@tonic-gate proto = "rpc/visible"; 874*0Sstevel@tonic-gate 875*0Sstevel@tonic-gate (void) strlcat(dstfile, proto, len); 876*0Sstevel@tonic-gate (void) strlcat(dstfile, ".xml", len); 877*0Sstevel@tonic-gate 878*0Sstevel@tonic-gate /* convert any '/' chars in service or protocol to '_' chars */ 879*0Sstevel@tonic-gate while ((cp = strchr(cp, '/')) != NULL) 880*0Sstevel@tonic-gate *cp = '_'; 881*0Sstevel@tonic-gate 882*0Sstevel@tonic-gate fd = open(dstfile, O_WRONLY|O_CREAT|(overwrite ? O_TRUNC : O_EXCL), 883*0Sstevel@tonic-gate 0644); 884*0Sstevel@tonic-gate if (fd == -1) { 885*0Sstevel@tonic-gate if (!overwrite && (errno == EEXIST)) { 886*0Sstevel@tonic-gate (void) fprintf(stderr, 887*0Sstevel@tonic-gate gettext("%s: Notice: Service manifest for " 888*0Sstevel@tonic-gate "%s already generated as %s, skipped\n"), 889*0Sstevel@tonic-gate progname, iconf->service, dstfile); 890*0Sstevel@tonic-gate free(dstfile); 891*0Sstevel@tonic-gate return (-1); 892*0Sstevel@tonic-gate } else { 893*0Sstevel@tonic-gate (void) fprintf(stderr, 894*0Sstevel@tonic-gate gettext("%s: Error opening %s: %s\n"), 895*0Sstevel@tonic-gate progname, dstfile, strerror(errno)); 896*0Sstevel@tonic-gate free(dstfile); 897*0Sstevel@tonic-gate return (-2); 898*0Sstevel@tonic-gate } 899*0Sstevel@tonic-gate } 900*0Sstevel@tonic-gate /* Clear errno to catch the "no stdio streams" case */ 901*0Sstevel@tonic-gate errno = 0; 902*0Sstevel@tonic-gate if ((fp = fdopen(fd, "w")) == NULL) { 903*0Sstevel@tonic-gate char *s = strerror(errno); 904*0Sstevel@tonic-gate if (errno == 0) 905*0Sstevel@tonic-gate s = gettext("No stdio streams available"); 906*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error fdopen failed: %s\n"), 907*0Sstevel@tonic-gate progname, s); 908*0Sstevel@tonic-gate (void) close(fd); 909*0Sstevel@tonic-gate free(dstfile); 910*0Sstevel@tonic-gate return (-2); 911*0Sstevel@tonic-gate } 912*0Sstevel@tonic-gate *finfo = safe_malloc(sizeof (struct fileinfo)); 913*0Sstevel@tonic-gate (*finfo)->fp = fp; 914*0Sstevel@tonic-gate (*finfo)->filename = dstfile; 915*0Sstevel@tonic-gate (*finfo)->lineno = 0; 916*0Sstevel@tonic-gate (*finfo)->failcnt = 0; 917*0Sstevel@tonic-gate return (0); 918*0Sstevel@tonic-gate } 919*0Sstevel@tonic-gate 920*0Sstevel@tonic-gate static int 921*0Sstevel@tonic-gate import_manifest(char *filename) 922*0Sstevel@tonic-gate { 923*0Sstevel@tonic-gate int status; 924*0Sstevel@tonic-gate pid_t pid, wpid; 925*0Sstevel@tonic-gate char *cp; 926*0Sstevel@tonic-gate 927*0Sstevel@tonic-gate if ((cp = strrchr(filename, '/')) == NULL) 928*0Sstevel@tonic-gate cp = filename; 929*0Sstevel@tonic-gate else 930*0Sstevel@tonic-gate cp++; 931*0Sstevel@tonic-gate (void) printf(gettext("Importing %s ..."), cp); 932*0Sstevel@tonic-gate 933*0Sstevel@tonic-gate if ((pid = fork()) == -1) { 934*0Sstevel@tonic-gate (void) fprintf(stderr, 935*0Sstevel@tonic-gate gettext("\n%s: fork failed, %s not imported: %s\n"), 936*0Sstevel@tonic-gate progname, filename, strerror(errno)); 937*0Sstevel@tonic-gate exit(EXIT_ERROR_SYS); 938*0Sstevel@tonic-gate } 939*0Sstevel@tonic-gate if (pid == 0) { 940*0Sstevel@tonic-gate /* child */ 941*0Sstevel@tonic-gate (void) fclose(stdin); 942*0Sstevel@tonic-gate (void) setenv("SVCCFG_CHECKHASH", "1", 1); 943*0Sstevel@tonic-gate (void) execl(SVCCFG_PATH, "svccfg", "import", filename, NULL); 944*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("\n%s: exec of %s failed: %s"), 945*0Sstevel@tonic-gate progname, SVCCFG_PATH, strerror(errno)); 946*0Sstevel@tonic-gate _exit(EXIT_ERROR_SYS); 947*0Sstevel@tonic-gate } 948*0Sstevel@tonic-gate /* parent */ 949*0Sstevel@tonic-gate if ((wpid = waitpid(pid, &status, 0)) != pid) { 950*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 951*0Sstevel@tonic-gate "\n%s: unexpected wait (%d) from import of %s: %s\n"), 952*0Sstevel@tonic-gate progname, wpid, filename, strerror(errno)); 953*0Sstevel@tonic-gate return (-1); 954*0Sstevel@tonic-gate } 955*0Sstevel@tonic-gate if (WIFEXITED(status) && (WEXITSTATUS(status) != 0)) { 956*0Sstevel@tonic-gate (void) fprintf(stderr, 957*0Sstevel@tonic-gate gettext("\n%s: import failure (%d) for %s\n"), 958*0Sstevel@tonic-gate progname, WEXITSTATUS(status), filename); 959*0Sstevel@tonic-gate return (-1); 960*0Sstevel@tonic-gate } 961*0Sstevel@tonic-gate (void) printf(gettext("Done\n")); 962*0Sstevel@tonic-gate return (0); 963*0Sstevel@tonic-gate } 964*0Sstevel@tonic-gate 965*0Sstevel@tonic-gate static int 966*0Sstevel@tonic-gate inetd_config_path(char **path) 967*0Sstevel@tonic-gate { 968*0Sstevel@tonic-gate int fd; 969*0Sstevel@tonic-gate char *arg1, *configfile, *configstr; 970*0Sstevel@tonic-gate scf_simple_prop_t *sp; 971*0Sstevel@tonic-gate char cpath[PATH_MAX]; 972*0Sstevel@tonic-gate 973*0Sstevel@tonic-gate if ((sp = scf_simple_prop_get(NULL, INETD_INSTANCE_FMRI, "start", 974*0Sstevel@tonic-gate SCF_PROPERTY_EXEC)) == NULL) 975*0Sstevel@tonic-gate return (-1); 976*0Sstevel@tonic-gate if ((configstr = scf_simple_prop_next_astring(sp)) == NULL) { 977*0Sstevel@tonic-gate scf_simple_prop_free(sp); 978*0Sstevel@tonic-gate return (-1); 979*0Sstevel@tonic-gate } 980*0Sstevel@tonic-gate configstr = safe_strdup(configstr); 981*0Sstevel@tonic-gate scf_simple_prop_free(sp); 982*0Sstevel@tonic-gate 983*0Sstevel@tonic-gate /* 984*0Sstevel@tonic-gate * Look for the optional configuration file, the syntax is: 985*0Sstevel@tonic-gate * /usr/lib/inet/inetd [config-file] start|stop|refresh|disable|%m 986*0Sstevel@tonic-gate */ 987*0Sstevel@tonic-gate if (strtok(configstr, " \t") == NULL) { 988*0Sstevel@tonic-gate free(configstr); 989*0Sstevel@tonic-gate return (-1); 990*0Sstevel@tonic-gate } 991*0Sstevel@tonic-gate if ((arg1 = strtok(NULL, " \t")) == NULL) { 992*0Sstevel@tonic-gate free(configstr); 993*0Sstevel@tonic-gate return (-1); 994*0Sstevel@tonic-gate } 995*0Sstevel@tonic-gate if (strtok(NULL, " \t") == NULL) { 996*0Sstevel@tonic-gate /* 997*0Sstevel@tonic-gate * No configuration file specified, do the same as inetd and 998*0Sstevel@tonic-gate * first try /etc/inet/inetd.conf, followed by /etc/inetd.conf. 999*0Sstevel@tonic-gate */ 1000*0Sstevel@tonic-gate configfile = MAIN_CONFIG; 1001*0Sstevel@tonic-gate if ((fd = open(configfile, O_RDONLY)) >= 0) 1002*0Sstevel@tonic-gate (void) close(fd); 1003*0Sstevel@tonic-gate else 1004*0Sstevel@tonic-gate configfile = ALT_CONFIG; 1005*0Sstevel@tonic-gate 1006*0Sstevel@tonic-gate } else { 1007*0Sstevel@tonic-gate /* make sure there are no more arguments */ 1008*0Sstevel@tonic-gate if (strtok(NULL, " \t") != NULL) { 1009*0Sstevel@tonic-gate free(configstr); 1010*0Sstevel@tonic-gate return (-1); 1011*0Sstevel@tonic-gate } 1012*0Sstevel@tonic-gate configfile = arg1; 1013*0Sstevel@tonic-gate } 1014*0Sstevel@tonic-gate 1015*0Sstevel@tonic-gate /* configuration file must be an absolute pathname */ 1016*0Sstevel@tonic-gate if (*configfile != '/') { 1017*0Sstevel@tonic-gate free(configstr); 1018*0Sstevel@tonic-gate return (-1); 1019*0Sstevel@tonic-gate } 1020*0Sstevel@tonic-gate 1021*0Sstevel@tonic-gate if (realpath(configfile, cpath) == NULL) 1022*0Sstevel@tonic-gate (void) strlcpy(cpath, configfile, sizeof (cpath)); 1023*0Sstevel@tonic-gate 1024*0Sstevel@tonic-gate free(configstr); 1025*0Sstevel@tonic-gate *path = safe_strdup(cpath); 1026*0Sstevel@tonic-gate return (0); 1027*0Sstevel@tonic-gate } 1028*0Sstevel@tonic-gate 1029*0Sstevel@tonic-gate static int 1030*0Sstevel@tonic-gate update_hash(char *srcfile) 1031*0Sstevel@tonic-gate { 1032*0Sstevel@tonic-gate scf_error_t rval; 1033*0Sstevel@tonic-gate char *inetd_cpath, *hashstr; 1034*0Sstevel@tonic-gate char cpath[PATH_MAX]; 1035*0Sstevel@tonic-gate 1036*0Sstevel@tonic-gate /* determine the config file inetd is using */ 1037*0Sstevel@tonic-gate if (inetd_config_path(&inetd_cpath) == -1) { 1038*0Sstevel@tonic-gate (void) fprintf(stderr, 1039*0Sstevel@tonic-gate gettext("%s: Error reading from repository\n"), progname); 1040*0Sstevel@tonic-gate return (-1); 1041*0Sstevel@tonic-gate } 1042*0Sstevel@tonic-gate 1043*0Sstevel@tonic-gate /* resolve inetconv input filename */ 1044*0Sstevel@tonic-gate if (realpath(srcfile, cpath) == NULL) 1045*0Sstevel@tonic-gate (void) strlcpy(cpath, srcfile, sizeof (cpath)); 1046*0Sstevel@tonic-gate 1047*0Sstevel@tonic-gate /* if inetconv and inetd are using the same config file, update hash */ 1048*0Sstevel@tonic-gate if (strcmp(cpath, inetd_cpath) != 0) { 1049*0Sstevel@tonic-gate free(inetd_cpath); 1050*0Sstevel@tonic-gate return (0); 1051*0Sstevel@tonic-gate } 1052*0Sstevel@tonic-gate free(inetd_cpath); 1053*0Sstevel@tonic-gate 1054*0Sstevel@tonic-gate /* generic error message as use of hash is not exposed to the user */ 1055*0Sstevel@tonic-gate if (calculate_hash(cpath, &hashstr) != 0) { 1056*0Sstevel@tonic-gate (void) fprintf(stderr, 1057*0Sstevel@tonic-gate gettext("%s: Error unable to update repository\n"), 1058*0Sstevel@tonic-gate progname); 1059*0Sstevel@tonic-gate return (-1); 1060*0Sstevel@tonic-gate } 1061*0Sstevel@tonic-gate /* generic error message as use of hash is not exposed to the user */ 1062*0Sstevel@tonic-gate if ((rval = store_inetd_hash(hashstr)) != SCF_ERROR_NONE) { 1063*0Sstevel@tonic-gate (void) fprintf(stderr, 1064*0Sstevel@tonic-gate gettext("%s: Error updating repository: %s\n"), 1065*0Sstevel@tonic-gate progname, scf_strerror(rval)); 1066*0Sstevel@tonic-gate free(hashstr); 1067*0Sstevel@tonic-gate return (-1); 1068*0Sstevel@tonic-gate } 1069*0Sstevel@tonic-gate free(hashstr); 1070*0Sstevel@tonic-gate return (0); 1071*0Sstevel@tonic-gate } 1072*0Sstevel@tonic-gate 1073*0Sstevel@tonic-gate static void 1074*0Sstevel@tonic-gate property_error(const char *fmri, const char *prop) 1075*0Sstevel@tonic-gate { 1076*0Sstevel@tonic-gate (void) fprintf(stderr, 1077*0Sstevel@tonic-gate gettext("Error: Instance %1$s is missing property '%2$s'.\n"), 1078*0Sstevel@tonic-gate fmri, prop); 1079*0Sstevel@tonic-gate } 1080*0Sstevel@tonic-gate 1081*0Sstevel@tonic-gate /* 1082*0Sstevel@tonic-gate * modify_sprop takes a handle, an instance, a property group, a property, 1083*0Sstevel@tonic-gate * and an astring value, and modifies the instance (or service's) specified 1084*0Sstevel@tonic-gate * property in the repository to the submitted value. 1085*0Sstevel@tonic-gate * 1086*0Sstevel@tonic-gate * returns -1 on error, 1 on successful transaction completion. 1087*0Sstevel@tonic-gate */ 1088*0Sstevel@tonic-gate 1089*0Sstevel@tonic-gate static int 1090*0Sstevel@tonic-gate modify_sprop(scf_handle_t *h, const scf_instance_t *inst, 1091*0Sstevel@tonic-gate const char *pg, const char *prop, const char *value) 1092*0Sstevel@tonic-gate { 1093*0Sstevel@tonic-gate scf_transaction_t *tx = NULL; 1094*0Sstevel@tonic-gate scf_transaction_entry_t *ent = NULL; 1095*0Sstevel@tonic-gate scf_propertygroup_t *gpg = NULL; 1096*0Sstevel@tonic-gate scf_property_t *eprop = NULL; 1097*0Sstevel@tonic-gate scf_value_t *v = NULL; 1098*0Sstevel@tonic-gate scf_service_t *svc = NULL; 1099*0Sstevel@tonic-gate int ret = 0, create = 0; 1100*0Sstevel@tonic-gate 1101*0Sstevel@tonic-gate if ((gpg = scf_pg_create(h)) == NULL) 1102*0Sstevel@tonic-gate return (-1); 1103*0Sstevel@tonic-gate 1104*0Sstevel@tonic-gate /* Get the property group */ 1105*0Sstevel@tonic-gate if (scf_instance_get_pg(inst, pg, gpg) == -1) { 1106*0Sstevel@tonic-gate /* Not a property of the instance, try the service instead */ 1107*0Sstevel@tonic-gate if ((svc = scf_service_create(h)) == NULL) { 1108*0Sstevel@tonic-gate ret = -1; 1109*0Sstevel@tonic-gate goto out; 1110*0Sstevel@tonic-gate } 1111*0Sstevel@tonic-gate if ((scf_instance_get_parent(inst, svc) == -1) || 1112*0Sstevel@tonic-gate (scf_service_get_pg(svc, pg, gpg) == -1)) { 1113*0Sstevel@tonic-gate ret = -1; 1114*0Sstevel@tonic-gate goto out; 1115*0Sstevel@tonic-gate } 1116*0Sstevel@tonic-gate } 1117*0Sstevel@tonic-gate 1118*0Sstevel@tonic-gate if ((eprop = scf_property_create(h)) == NULL) { 1119*0Sstevel@tonic-gate ret = -1; 1120*0Sstevel@tonic-gate goto out; 1121*0Sstevel@tonic-gate } 1122*0Sstevel@tonic-gate 1123*0Sstevel@tonic-gate if (scf_pg_get_property(gpg, prop, eprop) == -1) { 1124*0Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND) { 1125*0Sstevel@tonic-gate ret = -1; 1126*0Sstevel@tonic-gate goto out; 1127*0Sstevel@tonic-gate } 1128*0Sstevel@tonic-gate 1129*0Sstevel@tonic-gate create = 1; 1130*0Sstevel@tonic-gate } 1131*0Sstevel@tonic-gate 1132*0Sstevel@tonic-gate if ((tx = scf_transaction_create(h)) == NULL || 1133*0Sstevel@tonic-gate (ent = scf_entry_create(h)) == NULL) { 1134*0Sstevel@tonic-gate ret = -1; 1135*0Sstevel@tonic-gate goto out; 1136*0Sstevel@tonic-gate } 1137*0Sstevel@tonic-gate 1138*0Sstevel@tonic-gate do { 1139*0Sstevel@tonic-gate if (scf_transaction_start(tx, gpg) == -1) { 1140*0Sstevel@tonic-gate ret = -1; 1141*0Sstevel@tonic-gate goto out; 1142*0Sstevel@tonic-gate } 1143*0Sstevel@tonic-gate 1144*0Sstevel@tonic-gate /* Modify the property */ 1145*0Sstevel@tonic-gate if (create) 1146*0Sstevel@tonic-gate ret = scf_transaction_property_new(tx, ent, prop, 1147*0Sstevel@tonic-gate SCF_TYPE_ASTRING); 1148*0Sstevel@tonic-gate else 1149*0Sstevel@tonic-gate ret = scf_transaction_property_change_type(tx, ent, 1150*0Sstevel@tonic-gate prop, SCF_TYPE_ASTRING); 1151*0Sstevel@tonic-gate 1152*0Sstevel@tonic-gate if (ret == -1) 1153*0Sstevel@tonic-gate goto out; 1154*0Sstevel@tonic-gate 1155*0Sstevel@tonic-gate if ((v = scf_value_create(h)) == NULL) { 1156*0Sstevel@tonic-gate ret = -1; 1157*0Sstevel@tonic-gate goto out; 1158*0Sstevel@tonic-gate } 1159*0Sstevel@tonic-gate 1160*0Sstevel@tonic-gate if (scf_value_set_astring(v, value) == -1) { 1161*0Sstevel@tonic-gate ret = -1; 1162*0Sstevel@tonic-gate goto out; 1163*0Sstevel@tonic-gate } 1164*0Sstevel@tonic-gate 1165*0Sstevel@tonic-gate if (scf_entry_add_value(ent, v) == -1) { 1166*0Sstevel@tonic-gate ret = -1; 1167*0Sstevel@tonic-gate goto out; 1168*0Sstevel@tonic-gate } 1169*0Sstevel@tonic-gate 1170*0Sstevel@tonic-gate ret = scf_transaction_commit(tx); 1171*0Sstevel@tonic-gate 1172*0Sstevel@tonic-gate if (ret == 0) { 1173*0Sstevel@tonic-gate /* Property group was stale, retry */ 1174*0Sstevel@tonic-gate if (scf_pg_update(gpg) == -1) { 1175*0Sstevel@tonic-gate ret = -1; 1176*0Sstevel@tonic-gate goto out; 1177*0Sstevel@tonic-gate } 1178*0Sstevel@tonic-gate scf_transaction_reset(tx); 1179*0Sstevel@tonic-gate } 1180*0Sstevel@tonic-gate 1181*0Sstevel@tonic-gate } while (ret == 0); 1182*0Sstevel@tonic-gate out: 1183*0Sstevel@tonic-gate scf_value_destroy(v); 1184*0Sstevel@tonic-gate scf_entry_destroy(ent); 1185*0Sstevel@tonic-gate scf_transaction_destroy(tx); 1186*0Sstevel@tonic-gate scf_property_destroy(eprop); 1187*0Sstevel@tonic-gate scf_service_destroy(svc); 1188*0Sstevel@tonic-gate scf_pg_destroy(gpg); 1189*0Sstevel@tonic-gate 1190*0Sstevel@tonic-gate return (ret); 1191*0Sstevel@tonic-gate } 1192*0Sstevel@tonic-gate 1193*0Sstevel@tonic-gate /* 1194*0Sstevel@tonic-gate * list_callback is the callback function to be handed to simple_walk_instances 1195*0Sstevel@tonic-gate * in main. It is called once on every instance on a machine. If that 1196*0Sstevel@tonic-gate * instance is controlled by inetd, we test whether it's the same 1197*0Sstevel@tonic-gate * service that we're looking at from the inetd.conf file, and enable it if 1198*0Sstevel@tonic-gate * they are the same. 1199*0Sstevel@tonic-gate */ 1200*0Sstevel@tonic-gate 1201*0Sstevel@tonic-gate /*ARGSUSED*/ 1202*0Sstevel@tonic-gate static int 1203*0Sstevel@tonic-gate list_callback(scf_handle_t *h, scf_instance_t *inst, void *buf) 1204*0Sstevel@tonic-gate { 1205*0Sstevel@tonic-gate ssize_t max_name_length; 1206*0Sstevel@tonic-gate char *svc_name; 1207*0Sstevel@tonic-gate scf_simple_prop_t *prop = NULL; 1208*0Sstevel@tonic-gate scf_simple_prop_t *sockprop = NULL; 1209*0Sstevel@tonic-gate scf_simple_prop_t *rpcprop = NULL; 1210*0Sstevel@tonic-gate scf_simple_prop_t *progprop = NULL; 1211*0Sstevel@tonic-gate const char *name, *endpoint, *restart_str, *prog; 1212*0Sstevel@tonic-gate struct inetconfent *iconf = (struct inetconfent *)buf; 1213*0Sstevel@tonic-gate uint8_t *isrpc; 1214*0Sstevel@tonic-gate 1215*0Sstevel@tonic-gate max_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 1216*0Sstevel@tonic-gate if ((svc_name = malloc(max_name_length + 1)) == NULL) { 1217*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("Error: Out of memory.\n")); 1218*0Sstevel@tonic-gate return (SCF_FAILED); 1219*0Sstevel@tonic-gate } 1220*0Sstevel@tonic-gate 1221*0Sstevel@tonic-gate /* 1222*0Sstevel@tonic-gate * Get the FMRI of the instance, and check if its delegated restarter 1223*0Sstevel@tonic-gate * is inetd. A missing or empty restarter property implies that 1224*0Sstevel@tonic-gate * svc.startd is the restarter. 1225*0Sstevel@tonic-gate */ 1226*0Sstevel@tonic-gate 1227*0Sstevel@tonic-gate if (scf_instance_to_fmri(inst, svc_name, max_name_length) < 0) { 1228*0Sstevel@tonic-gate (void) fprintf(stderr, 1229*0Sstevel@tonic-gate gettext("Error: Unable to obtain FMRI for service %1$s."), 1230*0Sstevel@tonic-gate svc_name); 1231*0Sstevel@tonic-gate free(svc_name); 1232*0Sstevel@tonic-gate return (SCF_FAILED); 1233*0Sstevel@tonic-gate } 1234*0Sstevel@tonic-gate 1235*0Sstevel@tonic-gate if ((prop = scf_simple_prop_get(h, svc_name, SCF_PG_GENERAL, 1236*0Sstevel@tonic-gate SCF_PROPERTY_RESTARTER)) == NULL) 1237*0Sstevel@tonic-gate goto out; 1238*0Sstevel@tonic-gate 1239*0Sstevel@tonic-gate if ((restart_str = scf_simple_prop_next_ustring(prop)) == NULL) 1240*0Sstevel@tonic-gate goto out; 1241*0Sstevel@tonic-gate 1242*0Sstevel@tonic-gate if (strcmp(restart_str, INETD_INSTANCE_FMRI) != 0) 1243*0Sstevel@tonic-gate goto out; 1244*0Sstevel@tonic-gate 1245*0Sstevel@tonic-gate /* Free restarter prop so it can be reused below */ 1246*0Sstevel@tonic-gate scf_simple_prop_free(prop); 1247*0Sstevel@tonic-gate 1248*0Sstevel@tonic-gate /* 1249*0Sstevel@tonic-gate * We know that this instance is managed by inetd. 1250*0Sstevel@tonic-gate * Now get the properties needed to decide if it matches this 1251*0Sstevel@tonic-gate * line in the old config file. 1252*0Sstevel@tonic-gate */ 1253*0Sstevel@tonic-gate 1254*0Sstevel@tonic-gate if (((prop = scf_simple_prop_get(h, svc_name, PG_NAME_SERVICE_CONFIG, 1255*0Sstevel@tonic-gate PR_SVC_NAME_NAME)) == NULL) || 1256*0Sstevel@tonic-gate ((name = scf_simple_prop_next_astring(prop)) == NULL)) { 1257*0Sstevel@tonic-gate property_error(svc_name, PR_SVC_NAME_NAME); 1258*0Sstevel@tonic-gate goto out; 1259*0Sstevel@tonic-gate } 1260*0Sstevel@tonic-gate 1261*0Sstevel@tonic-gate if (((sockprop = scf_simple_prop_get(h, svc_name, 1262*0Sstevel@tonic-gate PG_NAME_SERVICE_CONFIG, PR_SOCK_TYPE_NAME)) == NULL) || 1263*0Sstevel@tonic-gate ((endpoint = scf_simple_prop_next_astring(sockprop)) == NULL)) { 1264*0Sstevel@tonic-gate property_error(svc_name, PR_SOCK_TYPE_NAME); 1265*0Sstevel@tonic-gate goto out; 1266*0Sstevel@tonic-gate } 1267*0Sstevel@tonic-gate 1268*0Sstevel@tonic-gate if (((rpcprop = scf_simple_prop_get(h, svc_name, 1269*0Sstevel@tonic-gate PG_NAME_SERVICE_CONFIG, PR_ISRPC_NAME)) == NULL) || 1270*0Sstevel@tonic-gate ((isrpc = scf_simple_prop_next_boolean(rpcprop)) == NULL)) { 1271*0Sstevel@tonic-gate property_error(svc_name, PR_ISRPC_NAME); 1272*0Sstevel@tonic-gate goto out; 1273*0Sstevel@tonic-gate } 1274*0Sstevel@tonic-gate 1275*0Sstevel@tonic-gate if (((progprop = scf_simple_prop_get(h, svc_name, START_METHOD_NAME, 1276*0Sstevel@tonic-gate PR_EXEC_NAME)) == NULL) || 1277*0Sstevel@tonic-gate ((prog = scf_simple_prop_next_astring(progprop)) == NULL)) { 1278*0Sstevel@tonic-gate property_error(svc_name, PR_EXEC_NAME); 1279*0Sstevel@tonic-gate } 1280*0Sstevel@tonic-gate 1281*0Sstevel@tonic-gate 1282*0Sstevel@tonic-gate /* If it's RPC, we truncate off the version portion for comparison */ 1283*0Sstevel@tonic-gate if (*isrpc) { 1284*0Sstevel@tonic-gate char *cp; 1285*0Sstevel@tonic-gate 1286*0Sstevel@tonic-gate cp = strchr(iconf->service, '/'); 1287*0Sstevel@tonic-gate if (cp != NULL) 1288*0Sstevel@tonic-gate *cp = '\0'; 1289*0Sstevel@tonic-gate } 1290*0Sstevel@tonic-gate 1291*0Sstevel@tonic-gate /* 1292*0Sstevel@tonic-gate * If name of this service and endpoint are equal to values from 1293*0Sstevel@tonic-gate * iconf fields, and they're either both RPC or both non-RPC, 1294*0Sstevel@tonic-gate * then we have a match; update the exec and arg0 properties if 1295*0Sstevel@tonic-gate * necessary, then enable it. 1296*0Sstevel@tonic-gate * We don't return an error if either operation fails so that we 1297*0Sstevel@tonic-gate * continue to try all the other services. 1298*0Sstevel@tonic-gate */ 1299*0Sstevel@tonic-gate if (strcmp(name, iconf->service) == 0 && 1300*0Sstevel@tonic-gate strcmp(endpoint, iconf->endpoint) == 0 && 1301*0Sstevel@tonic-gate *isrpc == (strncmp(iconf->protocol, "rpc/", 4) == 0)) { 1302*0Sstevel@tonic-gate /* Can't update exec on internal services */ 1303*0Sstevel@tonic-gate if ((strcmp(iconf->server_program, "internal") != 0) && 1304*0Sstevel@tonic-gate (strcmp(iconf->exec, prog) != 0)) { 1305*0Sstevel@tonic-gate /* User had edited the command */ 1306*0Sstevel@tonic-gate if (!import) { 1307*0Sstevel@tonic-gate /* Dry run only */ 1308*0Sstevel@tonic-gate (void) printf( 1309*0Sstevel@tonic-gate gettext("Would update %s to %s %s"), 1310*0Sstevel@tonic-gate svc_name, PR_EXEC_NAME, iconf->exec); 1311*0Sstevel@tonic-gate if (iconf->arg0 != NULL) { 1312*0Sstevel@tonic-gate (void) printf( 1313*0Sstevel@tonic-gate gettext(" with %s of %s\n"), 1314*0Sstevel@tonic-gate PR_ARG0_NAME, iconf->arg0); 1315*0Sstevel@tonic-gate } else { 1316*0Sstevel@tonic-gate (void) printf("\n"); 1317*0Sstevel@tonic-gate } 1318*0Sstevel@tonic-gate } else { 1319*0Sstevel@tonic-gate /* Update instance's exec property */ 1320*0Sstevel@tonic-gate if (modify_sprop(h, inst, START_METHOD_NAME, 1321*0Sstevel@tonic-gate PR_EXEC_NAME, iconf->exec) != 1) 1322*0Sstevel@tonic-gate (void) fprintf(stderr, 1323*0Sstevel@tonic-gate gettext("Error: Unable to update " 1324*0Sstevel@tonic-gate "%s property of %s, %s\n"), 1325*0Sstevel@tonic-gate PR_EXEC_NAME, svc_name, 1326*0Sstevel@tonic-gate scf_strerror(scf_error())); 1327*0Sstevel@tonic-gate else 1328*0Sstevel@tonic-gate (void) printf("%s will %s %s\n", 1329*0Sstevel@tonic-gate svc_name, PR_EXEC_NAME, 1330*0Sstevel@tonic-gate iconf->exec); 1331*0Sstevel@tonic-gate 1332*0Sstevel@tonic-gate /* Update arg0 prop, if needed */ 1333*0Sstevel@tonic-gate if (iconf->arg0 != NULL) { 1334*0Sstevel@tonic-gate if (modify_sprop(h, inst, 1335*0Sstevel@tonic-gate START_METHOD_NAME, PR_ARG0_NAME, 1336*0Sstevel@tonic-gate iconf->arg0) != 1) { 1337*0Sstevel@tonic-gate (void) fprintf(stderr, 1338*0Sstevel@tonic-gate gettext("Error: Unable to " 1339*0Sstevel@tonic-gate "update %s property of " 1340*0Sstevel@tonic-gate "%s, %s\n"), PR_ARG0_NAME, 1341*0Sstevel@tonic-gate svc_name, 1342*0Sstevel@tonic-gate scf_strerror(scf_error())); 1343*0Sstevel@tonic-gate } else { 1344*0Sstevel@tonic-gate (void) printf("%s will have an " 1345*0Sstevel@tonic-gate "%s of %s\n", svc_name, 1346*0Sstevel@tonic-gate PR_ARG0_NAME, iconf->arg0); 1347*0Sstevel@tonic-gate } 1348*0Sstevel@tonic-gate } 1349*0Sstevel@tonic-gate } 1350*0Sstevel@tonic-gate } 1351*0Sstevel@tonic-gate 1352*0Sstevel@tonic-gate if (!import) { 1353*0Sstevel@tonic-gate /* Dry-run only */ 1354*0Sstevel@tonic-gate (void) printf("Would enable %s\n", svc_name); 1355*0Sstevel@tonic-gate } else { 1356*0Sstevel@tonic-gate if (smf_enable_instance(svc_name, 0) != 0) 1357*0Sstevel@tonic-gate (void) fprintf(stderr, 1358*0Sstevel@tonic-gate gettext("Error: Failed to enable %s\n"), 1359*0Sstevel@tonic-gate svc_name); 1360*0Sstevel@tonic-gate else 1361*0Sstevel@tonic-gate (void) printf("%s enabled\n", svc_name); 1362*0Sstevel@tonic-gate } 1363*0Sstevel@tonic-gate } 1364*0Sstevel@tonic-gate 1365*0Sstevel@tonic-gate out: 1366*0Sstevel@tonic-gate free(svc_name); 1367*0Sstevel@tonic-gate scf_simple_prop_free(prop); 1368*0Sstevel@tonic-gate scf_simple_prop_free(sockprop); 1369*0Sstevel@tonic-gate scf_simple_prop_free(rpcprop); 1370*0Sstevel@tonic-gate scf_simple_prop_free(progprop); 1371*0Sstevel@tonic-gate return (SCF_SUCCESS); 1372*0Sstevel@tonic-gate } 1373*0Sstevel@tonic-gate 1374*0Sstevel@tonic-gate static void 1375*0Sstevel@tonic-gate usage(void) 1376*0Sstevel@tonic-gate { 1377*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1378*0Sstevel@tonic-gate "Usage: %s [-fn] [-i srcfile] [-o destdir]\n" 1379*0Sstevel@tonic-gate " %1$s -e [-n] [-i srcfile]\n" 1380*0Sstevel@tonic-gate "-? Display this usage message\n" 1381*0Sstevel@tonic-gate "-e Enable smf services which are enabled in the input\n" 1382*0Sstevel@tonic-gate " file\n" 1383*0Sstevel@tonic-gate "-f Force overwrite of existing manifests\n" 1384*0Sstevel@tonic-gate "-n Do not import converted manifests,\n" 1385*0Sstevel@tonic-gate " or only display services which would be enabled\n" 1386*0Sstevel@tonic-gate "-i srcfile Alternate input file\n" 1387*0Sstevel@tonic-gate "-o destdir Alternate output directory for manifests\n"), 1388*0Sstevel@tonic-gate progname); 1389*0Sstevel@tonic-gate exit(EXIT_USAGE); 1390*0Sstevel@tonic-gate } 1391*0Sstevel@tonic-gate 1392*0Sstevel@tonic-gate int 1393*0Sstevel@tonic-gate main(int argc, char *argv[]) 1394*0Sstevel@tonic-gate { 1395*0Sstevel@tonic-gate int c, rval, convert_err, import_err = 0, enable_err = 0; 1396*0Sstevel@tonic-gate boolean_t overwrite = B_FALSE; 1397*0Sstevel@tonic-gate boolean_t enable = B_FALSE; 1398*0Sstevel@tonic-gate char *srcfile = NULL; 1399*0Sstevel@tonic-gate char *destdir = NULL; 1400*0Sstevel@tonic-gate struct fileinfo *srcfinfo, *dstfinfo; 1401*0Sstevel@tonic-gate struct inetconfent *iconf; 1402*0Sstevel@tonic-gate 1403*0Sstevel@tonic-gate setbuf(stdout, NULL); 1404*0Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1405*0Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 1406*0Sstevel@tonic-gate 1407*0Sstevel@tonic-gate if ((progname = strrchr(argv[0], '/')) == NULL) 1408*0Sstevel@tonic-gate progname = argv[0]; 1409*0Sstevel@tonic-gate else 1410*0Sstevel@tonic-gate progname++; 1411*0Sstevel@tonic-gate 1412*0Sstevel@tonic-gate while ((c = getopt(argc, argv, "?efni:o:")) != -1) { 1413*0Sstevel@tonic-gate switch (c) { 1414*0Sstevel@tonic-gate case 'e': 1415*0Sstevel@tonic-gate /* enable services based on existing file config */ 1416*0Sstevel@tonic-gate enable = B_TRUE; 1417*0Sstevel@tonic-gate break; 1418*0Sstevel@tonic-gate 1419*0Sstevel@tonic-gate case 'f': 1420*0Sstevel@tonic-gate /* overwrite existing manifests */ 1421*0Sstevel@tonic-gate overwrite = B_TRUE; 1422*0Sstevel@tonic-gate break; 1423*0Sstevel@tonic-gate case 'n': 1424*0Sstevel@tonic-gate /* don't import manifests, or dry-run enable */ 1425*0Sstevel@tonic-gate import = B_FALSE; 1426*0Sstevel@tonic-gate break; 1427*0Sstevel@tonic-gate case 'i': 1428*0Sstevel@tonic-gate /* alternate input file */ 1429*0Sstevel@tonic-gate if (srcfile != NULL) { 1430*0Sstevel@tonic-gate (void) fprintf(stderr, 1431*0Sstevel@tonic-gate gettext("%s: Error only one -%c allowed\n"), 1432*0Sstevel@tonic-gate progname, optopt); 1433*0Sstevel@tonic-gate usage(); 1434*0Sstevel@tonic-gate } 1435*0Sstevel@tonic-gate srcfile = optarg; 1436*0Sstevel@tonic-gate break; 1437*0Sstevel@tonic-gate case 'o': 1438*0Sstevel@tonic-gate /* alternate output directory */ 1439*0Sstevel@tonic-gate if (destdir != NULL) { 1440*0Sstevel@tonic-gate (void) fprintf(stderr, 1441*0Sstevel@tonic-gate gettext("%s: Error only one -%c allowed\n"), 1442*0Sstevel@tonic-gate progname, optopt); 1443*0Sstevel@tonic-gate usage(); 1444*0Sstevel@tonic-gate } 1445*0Sstevel@tonic-gate destdir = optarg; 1446*0Sstevel@tonic-gate break; 1447*0Sstevel@tonic-gate case '?': /*FALLTHROUGH*/ 1448*0Sstevel@tonic-gate default: 1449*0Sstevel@tonic-gate usage(); 1450*0Sstevel@tonic-gate break; 1451*0Sstevel@tonic-gate } 1452*0Sstevel@tonic-gate } 1453*0Sstevel@tonic-gate 1454*0Sstevel@tonic-gate /* 1455*0Sstevel@tonic-gate * Display usage if extraneous args supplied or enable specified in 1456*0Sstevel@tonic-gate * combination with overwrite or destdir 1457*0Sstevel@tonic-gate */ 1458*0Sstevel@tonic-gate if ((optind != argc) || (enable && (overwrite || destdir != NULL))) 1459*0Sstevel@tonic-gate usage(); 1460*0Sstevel@tonic-gate 1461*0Sstevel@tonic-gate if ((srcfinfo = open_srcfile(srcfile)) == NULL) 1462*0Sstevel@tonic-gate return (EXIT_ERROR_CONV); 1463*0Sstevel@tonic-gate 1464*0Sstevel@tonic-gate while ((iconf = fgetinetconfent(srcfinfo, !enable)) != NULL) { 1465*0Sstevel@tonic-gate /* 1466*0Sstevel@tonic-gate * If we're enabling, then just walk all the services for each 1467*0Sstevel@tonic-gate * line and enable those which match. 1468*0Sstevel@tonic-gate */ 1469*0Sstevel@tonic-gate if (enable) { 1470*0Sstevel@tonic-gate rval = scf_simple_walk_instances(SCF_STATE_ALL, iconf, 1471*0Sstevel@tonic-gate list_callback); 1472*0Sstevel@tonic-gate free_inetconfent(iconf); 1473*0Sstevel@tonic-gate if (rval == SCF_FAILED) { 1474*0Sstevel@tonic-gate /* Only print msg if framework error */ 1475*0Sstevel@tonic-gate if (scf_error() != SCF_ERROR_CALLBACK_FAILED) 1476*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1477*0Sstevel@tonic-gate "Error walking instances: %s.\n"), 1478*0Sstevel@tonic-gate scf_strerror(scf_error())); 1479*0Sstevel@tonic-gate enable_err++; 1480*0Sstevel@tonic-gate break; 1481*0Sstevel@tonic-gate } 1482*0Sstevel@tonic-gate continue; 1483*0Sstevel@tonic-gate } 1484*0Sstevel@tonic-gate 1485*0Sstevel@tonic-gate /* Remainder of loop used for conversion & import */ 1486*0Sstevel@tonic-gate if ((rval = open_dstfile(destdir, overwrite, iconf, &dstfinfo)) 1487*0Sstevel@tonic-gate < 0) { 1488*0Sstevel@tonic-gate /* 1489*0Sstevel@tonic-gate * Only increment error counter if the failure was 1490*0Sstevel@tonic-gate * other than the file already existing. 1491*0Sstevel@tonic-gate */ 1492*0Sstevel@tonic-gate if (rval == -2) 1493*0Sstevel@tonic-gate srcfinfo->failcnt++; 1494*0Sstevel@tonic-gate free_inetconfent(iconf); 1495*0Sstevel@tonic-gate continue; 1496*0Sstevel@tonic-gate } 1497*0Sstevel@tonic-gate rval = print_manifest(dstfinfo->fp, dstfinfo->filename, iconf); 1498*0Sstevel@tonic-gate (void) fclose(dstfinfo->fp); 1499*0Sstevel@tonic-gate if (rval == 0) { 1500*0Sstevel@tonic-gate if (import && 1501*0Sstevel@tonic-gate (import_manifest(dstfinfo->filename) != 0)) 1502*0Sstevel@tonic-gate import_err++; 1503*0Sstevel@tonic-gate } else { 1504*0Sstevel@tonic-gate (void) unlink(dstfinfo->filename); 1505*0Sstevel@tonic-gate srcfinfo->failcnt++; 1506*0Sstevel@tonic-gate } 1507*0Sstevel@tonic-gate free(dstfinfo->filename); 1508*0Sstevel@tonic-gate free(dstfinfo); 1509*0Sstevel@tonic-gate free_inetconfent(iconf); 1510*0Sstevel@tonic-gate } 1511*0Sstevel@tonic-gate (void) fclose(srcfinfo->fp); 1512*0Sstevel@tonic-gate convert_err = srcfinfo->failcnt; 1513*0Sstevel@tonic-gate 1514*0Sstevel@tonic-gate /* Update hash only if not in enable mode, and only if importing */ 1515*0Sstevel@tonic-gate if (!enable && import && (update_hash(srcfinfo->filename) != 0)) 1516*0Sstevel@tonic-gate import_err++; 1517*0Sstevel@tonic-gate 1518*0Sstevel@tonic-gate free(srcfinfo); 1519*0Sstevel@tonic-gate 1520*0Sstevel@tonic-gate if (enable_err != 0) 1521*0Sstevel@tonic-gate return (EXIT_ERROR_ENBL); 1522*0Sstevel@tonic-gate if (import_err != 0) 1523*0Sstevel@tonic-gate return (EXIT_ERROR_IMP); 1524*0Sstevel@tonic-gate if (convert_err != 0) 1525*0Sstevel@tonic-gate return (EXIT_ERROR_CONV); 1526*0Sstevel@tonic-gate return (EXIT_SUCCESS); 1527*0Sstevel@tonic-gate } 1528