xref: /onnv-gate/usr/src/cmd/svc/lsvcrun/lsvcrun.c (revision 12718:5d58bbec4ff6)
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
56073Sacruz  * Common Development and Distribution License (the "License").
66073Sacruz  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*12718SVladimir.Marek@Sun.COM  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /*
260Sstevel@tonic-gate  * lsvcrun - run an rc?.d script, modifying appropriate data in the
270Sstevel@tonic-gate  * repository to reflect legacy behavior.
280Sstevel@tonic-gate  *
290Sstevel@tonic-gate  * We try to keep track of what we can for the legacy scripts via
300Sstevel@tonic-gate  * property groups under the smf/legacy_run service.  Each property
310Sstevel@tonic-gate  * group identifies a service, named in the form 'rc2_d_S10foo'.
320Sstevel@tonic-gate  *
330Sstevel@tonic-gate  * Each group has the following properties: name, the script name
340Sstevel@tonic-gate  * displayed by svcs(1m); state_timestamp; contract, contract ID;
350Sstevel@tonic-gate  * inode, the inode of the script; and suffix, the suffix of the
360Sstevel@tonic-gate  * script name, e.g. 'foo'.
370Sstevel@tonic-gate  *
38*12718SVladimir.Marek@Sun.COM  * In order to support rc scripts which delete themselves upon invocation we
39*12718SVladimir.Marek@Sun.COM  * collect inode before running the script.
40*12718SVladimir.Marek@Sun.COM  *
410Sstevel@tonic-gate  * When we run a K script, we try to identify and remove the
420Sstevel@tonic-gate  * property group by means of examining the inode and script
430Sstevel@tonic-gate  * suffix.  The inode check means more than one script with the
440Sstevel@tonic-gate  * same suffix will still work as intended in the common case.
450Sstevel@tonic-gate  *
460Sstevel@tonic-gate  * If we cannot find a property group, or one already exists
470Sstevel@tonic-gate  * when we try to add one, then we print a suitable warning.  These
480Sstevel@tonic-gate  * are warnings because there was no strict requirement that K
490Sstevel@tonic-gate  * and S scripts be matched up.
500Sstevel@tonic-gate  *
510Sstevel@tonic-gate  * In the face of these assumptions being proved wrong, we always
520Sstevel@tonic-gate  * make sure to execute the script anyway in an attempt to keep
530Sstevel@tonic-gate  * things working as they used to.  If we can't execute the script,
540Sstevel@tonic-gate  * we try to leave the repository in the state it was before.
550Sstevel@tonic-gate  */
560Sstevel@tonic-gate 
570Sstevel@tonic-gate #include <sys/ctfs.h>
580Sstevel@tonic-gate #include <sys/types.h>
590Sstevel@tonic-gate #include <sys/wait.h>
600Sstevel@tonic-gate #include <sys/stat.h>
610Sstevel@tonic-gate #include <assert.h>
620Sstevel@tonic-gate #include <ctype.h>
630Sstevel@tonic-gate #include <errno.h>
640Sstevel@tonic-gate #include <fcntl.h>
650Sstevel@tonic-gate #include <fnmatch.h>
660Sstevel@tonic-gate #include <libcontract.h>
670Sstevel@tonic-gate #include <libcontract_priv.h>
680Sstevel@tonic-gate #include <libintl.h>
690Sstevel@tonic-gate #include <libscf.h>
700Sstevel@tonic-gate #include <libscf_priv.h>
710Sstevel@tonic-gate #include <libuutil.h>
720Sstevel@tonic-gate #include <signal.h>
730Sstevel@tonic-gate #include <stdio.h>
740Sstevel@tonic-gate #include <stdlib.h>
750Sstevel@tonic-gate #include <string.h>
760Sstevel@tonic-gate #include <strings.h>
770Sstevel@tonic-gate #include <time.h>
780Sstevel@tonic-gate #include <unistd.h>
790Sstevel@tonic-gate #include <limits.h>
800Sstevel@tonic-gate 
810Sstevel@tonic-gate 
820Sstevel@tonic-gate /* Environment variables to pass on.  See clean_environment(). */
830Sstevel@tonic-gate static char *evars_to_pass[] = { "LANG", "LC_ALL", "LC_COLLATE", "LC_CTYPE",
840Sstevel@tonic-gate 	"LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC", "LC_TIME", "PATH", "TZ"
850Sstevel@tonic-gate };
860Sstevel@tonic-gate 
870Sstevel@tonic-gate #define	EVARS_TO_PASS_NUM						\
880Sstevel@tonic-gate 	(sizeof (evars_to_pass) / sizeof (*evars_to_pass))
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 
910Sstevel@tonic-gate static void
usage()920Sstevel@tonic-gate usage()
930Sstevel@tonic-gate {
940Sstevel@tonic-gate 	(void) fprintf(stderr,
950Sstevel@tonic-gate 	    gettext("Usage: %s [-s] script {start | stop}\n"), uu_getpname());
960Sstevel@tonic-gate 	exit(UU_EXIT_USAGE);
970Sstevel@tonic-gate }
980Sstevel@tonic-gate 
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate  * Pick out the script name and convert it for use as an SMF property
1010Sstevel@tonic-gate  * group name.
1020Sstevel@tonic-gate  */
1030Sstevel@tonic-gate static char *
start_pg_name(const char * path)1040Sstevel@tonic-gate start_pg_name(const char *path)
1050Sstevel@tonic-gate {
1060Sstevel@tonic-gate 	char *out, *cp;
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 	if (fnmatch("/etc/rc[0-6S].d/S*", path, FNM_PATHNAME) != 0) {
1090Sstevel@tonic-gate 		uu_warn(gettext("couldn't parse name %s.\n"), path);
1100Sstevel@tonic-gate 		return (NULL);
1110Sstevel@tonic-gate 	}
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 	out = strdup(path + sizeof ("/etc/") - 1);
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	if (out == NULL) {
1160Sstevel@tonic-gate 		uu_warn(gettext("strdup() failed (%s).\n"), strerror(errno));
1170Sstevel@tonic-gate 		return (NULL);
1180Sstevel@tonic-gate 	}
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	/* Convert illegal characters to _. */
1210Sstevel@tonic-gate 	for (cp = out; *cp != '\0'; ++cp) {
1220Sstevel@tonic-gate 		/* locale problem? */
1230Sstevel@tonic-gate 		if (!isalnum(*cp) && *cp != '-')
1240Sstevel@tonic-gate 			*cp = '_';
1250Sstevel@tonic-gate 	}
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	return (out);
1280Sstevel@tonic-gate }
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate static char *
script_suffix(const char * path)1310Sstevel@tonic-gate script_suffix(const char *path)
1320Sstevel@tonic-gate {
1330Sstevel@tonic-gate 	const char *cp;
1340Sstevel@tonic-gate 	char *out;
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	if (fnmatch("/etc/rc[0-6S].d/[SK]*", path, FNM_PATHNAME) != 0) {
1370Sstevel@tonic-gate 		uu_warn(gettext("couldn't parse name %s.\n"), path);
1380Sstevel@tonic-gate 		return (NULL);
1390Sstevel@tonic-gate 	}
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	cp = path + sizeof ("/etc/rc0.d/S") - 1;
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	while (isdigit(*cp))
1440Sstevel@tonic-gate 		cp++;
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 	if (*cp == '\0') {
1470Sstevel@tonic-gate 		uu_warn(gettext("couldn't parse name %s.\n"), path);
1480Sstevel@tonic-gate 		return (NULL);
1490Sstevel@tonic-gate 	}
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 	out = strdup(cp);
1520Sstevel@tonic-gate 	if (out == NULL)
1530Sstevel@tonic-gate 		uu_warn(gettext("strdup() failed (%s).\n"), strerror(errno));
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	return (out);
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate /*
1590Sstevel@tonic-gate  * Convert a path to an acceptable SMF (service) name.
1600Sstevel@tonic-gate  */
1610Sstevel@tonic-gate static char *
path_to_svc_name(const char * path)1620Sstevel@tonic-gate path_to_svc_name(const char *path)
1630Sstevel@tonic-gate {
1640Sstevel@tonic-gate 	char *out, *cp;
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	out = strdup(path);
1670Sstevel@tonic-gate 	if (out == NULL) {
1680Sstevel@tonic-gate 		uu_warn(gettext("strdup() failed (%s).\n"), strerror(errno));
1690Sstevel@tonic-gate 		return (NULL);
1700Sstevel@tonic-gate 	}
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 	/* Convert illegal characters to _. */
1730Sstevel@tonic-gate 	for (cp = out; *cp != '\0'; ++cp) {
1740Sstevel@tonic-gate 		/* locale problem? */
1750Sstevel@tonic-gate 		if (!isalnum(*cp) && *cp != '-' && *cp != '/')
1760Sstevel@tonic-gate 			*cp = '_';
1770Sstevel@tonic-gate 	}
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	/* If the first character is _, use a instead. */
1800Sstevel@tonic-gate 	if (*out == '_')
1810Sstevel@tonic-gate 		*out = 'a';
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	return (out);
1840Sstevel@tonic-gate }
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate static void
scferr(const char * func)1870Sstevel@tonic-gate scferr(const char *func)
1880Sstevel@tonic-gate {
1890Sstevel@tonic-gate 	uu_warn(gettext("%s failed (%s).  Repository will not be modified.\n"),
1900Sstevel@tonic-gate 	    func, scf_strerror(scf_error()));
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate static scf_propertygroup_t *
get_start_pg(const char * script,scf_handle_t * h,scf_service_t * svc,boolean_t * ok)1940Sstevel@tonic-gate get_start_pg(const char *script, scf_handle_t *h, scf_service_t *svc,
1950Sstevel@tonic-gate     boolean_t *ok)
1960Sstevel@tonic-gate {
1970Sstevel@tonic-gate 	char *pg_name = NULL;
1980Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
1990Sstevel@tonic-gate 	scf_property_t *prop = NULL;
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	if ((pg_name = start_pg_name(script)) == NULL)
2020Sstevel@tonic-gate 		return (NULL);
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	if ((pg = scf_pg_create(h)) == NULL) {
2050Sstevel@tonic-gate 		scferr("scf_pg_create()");
2060Sstevel@tonic-gate 		goto out;
2070Sstevel@tonic-gate 	}
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate add:
2100Sstevel@tonic-gate 	if (scf_service_add_pg(svc, pg_name, SCF_GROUP_FRAMEWORK,
2110Sstevel@tonic-gate 	    SCF_PG_FLAG_NONPERSISTENT, pg) == 0) {
2120Sstevel@tonic-gate 		*ok = 1;
2130Sstevel@tonic-gate 		free(pg_name);
2140Sstevel@tonic-gate 		return (pg);
2150Sstevel@tonic-gate 	}
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	switch (scf_error()) {
2180Sstevel@tonic-gate 	case SCF_ERROR_INVALID_ARGUMENT:
2190Sstevel@tonic-gate 		assert(0);
2200Sstevel@tonic-gate 		abort();
2210Sstevel@tonic-gate 		/* NOTREACHED */
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 	case SCF_ERROR_EXISTS:
2240Sstevel@tonic-gate 		break;
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	case SCF_ERROR_PERMISSION_DENIED:
2270Sstevel@tonic-gate 		uu_die(gettext(
2280Sstevel@tonic-gate 		    "Insufficient privilege to add repository properties; "
2290Sstevel@tonic-gate 		    "not launching \"%s\".\n"), script);
2300Sstevel@tonic-gate 		/* NOTREACHED */
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	default:
2330Sstevel@tonic-gate 		scferr("scf_service_add_pg()");
2340Sstevel@tonic-gate 		scf_pg_destroy(pg);
2350Sstevel@tonic-gate 		pg = NULL;
2360Sstevel@tonic-gate 		goto out;
2370Sstevel@tonic-gate 	}
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	if (scf_service_get_pg(svc, pg_name, pg) != 0) {
2400Sstevel@tonic-gate 		switch (scf_error()) {
2410Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
2420Sstevel@tonic-gate 			assert(0);
2430Sstevel@tonic-gate 			abort();
2440Sstevel@tonic-gate 			/* NOTREACHED */
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
2470Sstevel@tonic-gate 			goto add;
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 		default:
2500Sstevel@tonic-gate 			scferr("scf_service_get_pg()");
2510Sstevel@tonic-gate 			scf_pg_destroy(pg);
2520Sstevel@tonic-gate 			pg = NULL;
2530Sstevel@tonic-gate 			goto out;
2540Sstevel@tonic-gate 		}
2550Sstevel@tonic-gate 	}
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	if ((prop = scf_property_create(h)) == NULL) {
2580Sstevel@tonic-gate 		scferr("scf_property_create()");
2590Sstevel@tonic-gate 		scf_pg_destroy(pg);
2600Sstevel@tonic-gate 		pg = NULL;
2610Sstevel@tonic-gate 		goto out;
2620Sstevel@tonic-gate 	}
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 	/*
2650Sstevel@tonic-gate 	 * See if the pg has the name property.  If it has, that
2660Sstevel@tonic-gate 	 * implies we successfully ran the same script before.  We
2670Sstevel@tonic-gate 	 * should re-run it anyway, but not modify the existing pg;
2680Sstevel@tonic-gate 	 * this might lose contract-control but there's not much we
2690Sstevel@tonic-gate 	 * can do.
2700Sstevel@tonic-gate 	 *
2710Sstevel@tonic-gate 	 * If there's no name property, then we probably couldn't
2720Sstevel@tonic-gate 	 * remove the pg fully after a script failed to run.
2730Sstevel@tonic-gate 	 */
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	if (scf_pg_get_property(pg, SCF_LEGACY_PROPERTY_NAME, prop) == 0) {
2760Sstevel@tonic-gate 		uu_warn(gettext("Service matching \"%s\" "
2770Sstevel@tonic-gate 		    "seems to be running.\n"), script);
2780Sstevel@tonic-gate 		scf_pg_destroy(pg);
2790Sstevel@tonic-gate 		pg = NULL;
2800Sstevel@tonic-gate 	} else if (scf_error() != SCF_ERROR_NOT_FOUND) {
2810Sstevel@tonic-gate 		scferr("scf_pg_get_property()");
2820Sstevel@tonic-gate 		scf_pg_destroy(pg);
2830Sstevel@tonic-gate 		pg = NULL;
2840Sstevel@tonic-gate 	} else {
2850Sstevel@tonic-gate 		uu_warn(gettext("Service \"%s\" has an invalid property "
2860Sstevel@tonic-gate 		    "group.\n"), script);
2870Sstevel@tonic-gate 	}
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate out:
2900Sstevel@tonic-gate 	free(pg_name);
2910Sstevel@tonic-gate 	scf_property_destroy(prop);
2920Sstevel@tonic-gate 	return (pg);
2930Sstevel@tonic-gate }
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate static scf_propertygroup_t *
pg_match(scf_handle_t * h,scf_service_t * svc,ino_t ino,const char * suffix)2960Sstevel@tonic-gate pg_match(scf_handle_t *h, scf_service_t *svc, ino_t ino, const char *suffix)
2970Sstevel@tonic-gate {
2980Sstevel@tonic-gate 	char buf[PATH_MAX];
2990Sstevel@tonic-gate 	scf_iter_t *iter = NULL;
3000Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
3010Sstevel@tonic-gate 	scf_property_t *prop = NULL;
3020Sstevel@tonic-gate 	scf_value_t *val = NULL;
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	if ((pg = scf_pg_create(h)) == NULL) {
3050Sstevel@tonic-gate 		scferr("scf_pg_create()");
3060Sstevel@tonic-gate 		goto err;
3070Sstevel@tonic-gate 	}
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	if ((iter = scf_iter_create(h)) == NULL) {
3100Sstevel@tonic-gate 		scferr("scf_iter_create()");
3110Sstevel@tonic-gate 		goto err;
3120Sstevel@tonic-gate 	}
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	if ((prop = scf_property_create(h)) == NULL) {
3150Sstevel@tonic-gate 		scferr("scf_property_create()");
3160Sstevel@tonic-gate 		goto err;
3170Sstevel@tonic-gate 	}
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	if ((val = scf_value_create(h)) == NULL) {
3200Sstevel@tonic-gate 		scferr("scf_value_create()");
3210Sstevel@tonic-gate 		goto err;
3220Sstevel@tonic-gate 	}
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	if (scf_iter_service_pgs_typed(iter, svc, SCF_GROUP_FRAMEWORK) !=
3250Sstevel@tonic-gate 	    0) {
3260Sstevel@tonic-gate 		scferr("scf_iter_service_pgs_typed()");
3270Sstevel@tonic-gate 		goto err;
3280Sstevel@tonic-gate 	}
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	while (scf_iter_next_pg(iter, pg) > 0) {
3310Sstevel@tonic-gate 		int match = 1;
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 		if (suffix != NULL) {
3340Sstevel@tonic-gate 			ssize_t len;
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 			if (scf_pg_get_property(pg, SCF_LEGACY_PROPERTY_SUFFIX,
3370Sstevel@tonic-gate 			    prop) != 0)
3380Sstevel@tonic-gate 				continue;
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 			if (scf_property_get_value(prop, val) != 0)
3410Sstevel@tonic-gate 				continue;
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 			len = scf_value_get_astring(val, buf, sizeof (buf));
3440Sstevel@tonic-gate 			if (len < 0) {
3450Sstevel@tonic-gate 				scferr("scf_value_get_astring()");
3460Sstevel@tonic-gate 				goto err;
3470Sstevel@tonic-gate 			}
3480Sstevel@tonic-gate 			if (len >= sizeof (buf))
3490Sstevel@tonic-gate 				continue;
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 			match = (strcmp(buf, suffix) == 0);
3520Sstevel@tonic-gate 		}
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 		if (ino != 0) {
3550Sstevel@tonic-gate 			uint64_t pval;
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 			if (scf_pg_get_property(pg, SCF_LEGACY_PROPERTY_INODE,
3580Sstevel@tonic-gate 			    prop) != 0)
3590Sstevel@tonic-gate 				continue;
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 			if (scf_property_get_value(prop, val) != 0)
3620Sstevel@tonic-gate 				continue;
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 			if (scf_value_get_count(val, &pval) != 0)
3650Sstevel@tonic-gate 				continue;
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 			match = (ino == pval) && match;
3680Sstevel@tonic-gate 		}
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 		if (match)
3710Sstevel@tonic-gate 			goto out;
3720Sstevel@tonic-gate 	}
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate err:
3750Sstevel@tonic-gate 	scf_pg_destroy(pg);
3760Sstevel@tonic-gate 	pg = NULL;
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate out:
3790Sstevel@tonic-gate 	scf_value_destroy(val);
3800Sstevel@tonic-gate 	scf_iter_destroy(iter);
3810Sstevel@tonic-gate 	scf_property_destroy(prop);
3820Sstevel@tonic-gate 	return (pg);
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate /*
3860Sstevel@tonic-gate  * Try and find the property group matching the service this script
3870Sstevel@tonic-gate  * stops.  First we look for a matching inode plus a matching suffix.
3880Sstevel@tonic-gate  * This commonly succeeds, but if not, we just search for inode.
3890Sstevel@tonic-gate  * Finally, we try for just the script suffix.
3900Sstevel@tonic-gate  */
3910Sstevel@tonic-gate static scf_propertygroup_t *
get_stop_pg(const char * script,scf_handle_t * h,scf_service_t * svc,boolean_t * ok)3920Sstevel@tonic-gate get_stop_pg(const char *script, scf_handle_t *h, scf_service_t *svc,
3930Sstevel@tonic-gate     boolean_t *ok)
3940Sstevel@tonic-gate {
3950Sstevel@tonic-gate 	struct stat st;
3960Sstevel@tonic-gate 	char *suffix;
3970Sstevel@tonic-gate 	scf_propertygroup_t *pg;
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	if (stat(script, &st) != 0) {
4000Sstevel@tonic-gate 		uu_warn(gettext("Couldn't stat %s (%s).\n"), script,
4010Sstevel@tonic-gate 		    strerror(errno));
4020Sstevel@tonic-gate 		return (NULL);
4030Sstevel@tonic-gate 	}
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 	if ((suffix = script_suffix(script)) == NULL) {
4060Sstevel@tonic-gate 		pg = pg_match(h, svc, st.st_ino, NULL);
4070Sstevel@tonic-gate 		if (pg != NULL)
4080Sstevel@tonic-gate 			goto out;
4090Sstevel@tonic-gate 		return (NULL);
4100Sstevel@tonic-gate 	}
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	if ((pg = pg_match(h, svc, st.st_ino, suffix)) != NULL)
4130Sstevel@tonic-gate 		goto out;
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	if ((pg = pg_match(h, svc, st.st_ino, NULL)) != NULL)
4160Sstevel@tonic-gate 		goto out;
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	if ((pg = pg_match(h, svc, 0, suffix)) == NULL) {
4190Sstevel@tonic-gate 		uu_warn(gettext("Service matching \"%s\" "
4200Sstevel@tonic-gate 		    "doesn't seem to be running.\n"), script);
4210Sstevel@tonic-gate 		free(suffix);
4220Sstevel@tonic-gate 		return (NULL);
4230Sstevel@tonic-gate 	}
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate out:
4260Sstevel@tonic-gate 	*ok = 1;
4270Sstevel@tonic-gate 	free(suffix);
4280Sstevel@tonic-gate 	return (pg);
4290Sstevel@tonic-gate }
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate static scf_propertygroup_t *
get_script_pg(const char * script,boolean_t start_flag,boolean_t * ok)4320Sstevel@tonic-gate get_script_pg(const char *script, boolean_t start_flag, boolean_t *ok)
4330Sstevel@tonic-gate {
4340Sstevel@tonic-gate 	scf_handle_t *h = NULL;
4350Sstevel@tonic-gate 	scf_scope_t *scope = NULL;
4360Sstevel@tonic-gate 	scf_service_t *svc = NULL;
4370Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	*ok = 0;
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	h = scf_handle_create(SCF_VERSION);
4420Sstevel@tonic-gate 	if (h == NULL) {
4430Sstevel@tonic-gate 		scferr("scf_handle_create()");
4440Sstevel@tonic-gate 		goto out;
4450Sstevel@tonic-gate 	}
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	if (scf_handle_bind(h) != 0) {
4480Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NO_SERVER) {
4490Sstevel@tonic-gate 			scferr("scf_handle_bind()");
4500Sstevel@tonic-gate 		} else {
4510Sstevel@tonic-gate 			uu_warn(gettext(
4520Sstevel@tonic-gate 			    "Could not connect to svc.configd.\n"));
4530Sstevel@tonic-gate 		}
4540Sstevel@tonic-gate 		goto out;
4550Sstevel@tonic-gate 	}
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	if ((scope = scf_scope_create(h)) == NULL) {
4580Sstevel@tonic-gate 		scferr("scf_scope_create()");
4590Sstevel@tonic-gate 		goto out;
4600Sstevel@tonic-gate 	}
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	if ((svc = scf_service_create(h)) == NULL) {
4630Sstevel@tonic-gate 		scferr("scf_service_create()");
4640Sstevel@tonic-gate 		goto out;
4650Sstevel@tonic-gate 	}
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 	if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, scope) != 0) {
4680Sstevel@tonic-gate 		scferr("scf_handle_get_local_scope()");
4690Sstevel@tonic-gate 		goto out;
4700Sstevel@tonic-gate 	}
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	if (scf_scope_get_service(scope, SCF_LEGACY_SERVICE, svc) != 0) {
4730Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND) {
4740Sstevel@tonic-gate 			scferr("scf_scope_get_service()");
4750Sstevel@tonic-gate 			goto out;
4760Sstevel@tonic-gate 		}
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 		if (scf_scope_add_service(scope, SCF_LEGACY_SERVICE, svc) !=
4790Sstevel@tonic-gate 		    0) {
4800Sstevel@tonic-gate 			scferr("scf_scope_add_service()");
4810Sstevel@tonic-gate 			goto out;
4820Sstevel@tonic-gate 		}
4830Sstevel@tonic-gate 	}
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	if (start_flag)
4860Sstevel@tonic-gate 		pg = get_start_pg(script, h, svc, ok);
4870Sstevel@tonic-gate 	else
4880Sstevel@tonic-gate 		pg = get_stop_pg(script, h, svc, ok);
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate out:
4910Sstevel@tonic-gate 	scf_service_destroy(svc);
4920Sstevel@tonic-gate 	scf_scope_destroy(scope);
4930Sstevel@tonic-gate 	return (pg);
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate static int
prepare_contract(const char * script,const char * action)4976073Sacruz prepare_contract(const char *script, const char *action)
4980Sstevel@tonic-gate {
4990Sstevel@tonic-gate 	int fd;
5006073Sacruz 	char *svc_name;
5016073Sacruz 	char *svc_strbuf;
5026073Sacruz 	int err = 0;
5030Sstevel@tonic-gate 
504*12718SVladimir.Marek@Sun.COM 	do {
5050Sstevel@tonic-gate 		fd = open64(CTFS_ROOT "/process/template", O_RDWR);
506*12718SVladimir.Marek@Sun.COM 	} while (fd < 0 && errno == EINTR);
5070Sstevel@tonic-gate 	if (fd < 0) {
5080Sstevel@tonic-gate 		uu_warn(gettext("Can not create contract"));
5090Sstevel@tonic-gate 		return (-1);
5100Sstevel@tonic-gate 	}
5110Sstevel@tonic-gate 
5126073Sacruz 	svc_strbuf = malloc(CT_PARAM_MAX_SIZE);
5136073Sacruz 	if (svc_strbuf == NULL) {
5146073Sacruz 		uu_warn(gettext("Can not allocate memory"));
5156073Sacruz 		err = -1;
5166073Sacruz 		goto cleanup;
5176073Sacruz 	}
5186073Sacruz 
5196073Sacruz 	(void) strlcpy(svc_strbuf, SCF_FMRI_LEGACY_PREFIX, CT_PARAM_MAX_SIZE);
5206073Sacruz 	svc_name = path_to_svc_name(script);
5216073Sacruz 	(void) strlcat(svc_strbuf, svc_name ? svc_name : script,
5226073Sacruz 	    CT_PARAM_MAX_SIZE);
5236073Sacruz 	if (svc_name != NULL) {
5246073Sacruz 		free(svc_name);
5256073Sacruz 	}
5266073Sacruz 
5276073Sacruz 	if ((errno = ct_pr_tmpl_set_svc_fmri(fd, svc_strbuf)) != 0) {
5286073Sacruz 		uu_warn(gettext("Can not set svc_fmri"));
5296073Sacruz 		err = -1;
5306073Sacruz 		goto cleanup;
5316073Sacruz 	}
5326073Sacruz 
5336073Sacruz 	(void) strlcpy(svc_strbuf, action, CT_PARAM_MAX_SIZE);
5346073Sacruz 	if ((errno = ct_pr_tmpl_set_svc_aux(fd, svc_strbuf)) != 0) {
5356073Sacruz 		uu_warn(gettext("Can not set svc_aux"));
5366073Sacruz 		err = -1;
5376073Sacruz 		goto cleanup;
5386073Sacruz 	}
5396073Sacruz 
5400Sstevel@tonic-gate 	/* Leave HWERR in fatal set. */
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	errno = ct_tmpl_activate(fd);
5430Sstevel@tonic-gate 	if (errno != 0) {
5440Sstevel@tonic-gate 		assert(errno == EPERM);
5450Sstevel@tonic-gate 		uu_warn(gettext("Can not activate contract template"));
5466073Sacruz 		err = -1;
5476073Sacruz 		goto cleanup;
5480Sstevel@tonic-gate 	}
5490Sstevel@tonic-gate 
5506073Sacruz cleanup:
5516073Sacruz 	if (svc_strbuf != NULL)
5526073Sacruz 		free(svc_strbuf);
5530Sstevel@tonic-gate 	(void) close(fd);
5546073Sacruz 
5556073Sacruz 	return (err);
5560Sstevel@tonic-gate }
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate static void
cleanup_pg(scf_propertygroup_t * pg)5590Sstevel@tonic-gate cleanup_pg(scf_propertygroup_t *pg)
5600Sstevel@tonic-gate {
5610Sstevel@tonic-gate 	scf_error_t err;
5620Sstevel@tonic-gate 	char buf[80];
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	if (scf_pg_delete(pg) == 0)
5650Sstevel@tonic-gate 		return;
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	err = scf_error();
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	if (scf_pg_to_fmri(pg, buf, sizeof (buf)) != 0)
5700Sstevel@tonic-gate 		(void) strcpy(buf, "?");
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	uu_warn(gettext("Could not remove property group %s: %s.\n"), buf,
5730Sstevel@tonic-gate 	    scf_strerror(err));
5740Sstevel@tonic-gate }
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate /*
5770Sstevel@tonic-gate  * Create a duplicate environment which only contains approved
5780Sstevel@tonic-gate  * variables---those in evars_to_pass and those beginning with "_INIT_".
5790Sstevel@tonic-gate  */
5800Sstevel@tonic-gate static char **
approved_env(char ** env)5810Sstevel@tonic-gate approved_env(char **env)
5820Sstevel@tonic-gate {
5830Sstevel@tonic-gate 	char **newenv;
5840Sstevel@tonic-gate 	int i, i_new, j;
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	for (i = 0; env[i] != NULL; ++i)
5870Sstevel@tonic-gate 		;
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	newenv = malloc(sizeof (*newenv) * (i + 1));
5900Sstevel@tonic-gate 	if (newenv == NULL)
5910Sstevel@tonic-gate 		return (NULL);
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 	i_new = 0;
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 	for (i = 0; env[i] != NULL; ++i) {
5960Sstevel@tonic-gate 		if (strncmp(env[i], "_INIT_", sizeof ("_INIT_") - 1) == 0) {
5970Sstevel@tonic-gate 			newenv[i_new++] = env[i];
5980Sstevel@tonic-gate 			continue;
5990Sstevel@tonic-gate 		}
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 		for (j = 0; j < EVARS_TO_PASS_NUM; ++j) {
6020Sstevel@tonic-gate 			size_t l = strlen(evars_to_pass[j]);
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 			if (env[i][l] == '=' &&
6050Sstevel@tonic-gate 			    strncmp(env[i], evars_to_pass[j], l) == 0)
6066073Sacruz 				newenv[i_new++] = env[i];
6070Sstevel@tonic-gate 		}
6080Sstevel@tonic-gate 	}
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	newenv[i_new] = NULL;
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 	return (newenv);
6130Sstevel@tonic-gate }
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate /*
6160Sstevel@tonic-gate  * Create a duplicate environment which does not contain any SMF_ variables.
6170Sstevel@tonic-gate  */
6180Sstevel@tonic-gate static char **
env_without_smf(char ** env)6190Sstevel@tonic-gate env_without_smf(char **env)
6200Sstevel@tonic-gate {
6210Sstevel@tonic-gate 	char **newenv;
6220Sstevel@tonic-gate 	int i, i_new;
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	for (i = 0; env[i] != NULL; ++i)
6250Sstevel@tonic-gate 		;
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	newenv = malloc(sizeof (*newenv) * (i + 1));
6280Sstevel@tonic-gate 	if (newenv == NULL)
6290Sstevel@tonic-gate 		return (NULL);
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	i_new = 0;
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	for (i = 0; env[i] != NULL; ++i) {
6340Sstevel@tonic-gate 		if (strncmp(env[i], "SMF_", sizeof ("SMF_") - 1) == 0)
6350Sstevel@tonic-gate 			continue;
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 		newenv[i_new++] = env[i];
6380Sstevel@tonic-gate 	}
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 	newenv[i_new] = NULL;
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 	return (newenv);
6430Sstevel@tonic-gate }
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate static int
add_new_property(scf_handle_t * h,scf_transaction_t * tx,const char * name,scf_type_t ty,const void * val)6460Sstevel@tonic-gate add_new_property(scf_handle_t *h, scf_transaction_t *tx, const char *name,
6470Sstevel@tonic-gate     scf_type_t ty, const void *val)
6480Sstevel@tonic-gate {
6490Sstevel@tonic-gate 	scf_transaction_entry_t *e;
6500Sstevel@tonic-gate 	scf_value_t *v;
6510Sstevel@tonic-gate 	const char *func;
6520Sstevel@tonic-gate 	const struct timeval *t;
6530Sstevel@tonic-gate 	int r;
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 	if ((e = scf_entry_create(h)) == NULL) {
6560Sstevel@tonic-gate 		func = "scf_entry_create()";
6570Sstevel@tonic-gate 		goto err;
6580Sstevel@tonic-gate 	}
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	if ((v = scf_value_create(h)) == NULL) {
6610Sstevel@tonic-gate 		func = "scf_value_create()";
6620Sstevel@tonic-gate 		goto err;
6630Sstevel@tonic-gate 	}
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 	r = scf_transaction_property_new(tx, e, name, ty);
6660Sstevel@tonic-gate 	if (r != 0) {
6670Sstevel@tonic-gate 		func = "scf_transaction_property_new()";
6680Sstevel@tonic-gate 		goto err;
6690Sstevel@tonic-gate 	}
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	switch (ty) {
6720Sstevel@tonic-gate 	case SCF_TYPE_COUNT:
673471Shg115875 		scf_value_set_count(v, (uint64_t)(uintptr_t)val);
6740Sstevel@tonic-gate 		break;
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 	case SCF_TYPE_TIME:
6770Sstevel@tonic-gate 		t = val;
6780Sstevel@tonic-gate 		r = scf_value_set_time(v, t->tv_sec, 1000 * t->tv_usec);
6790Sstevel@tonic-gate 		assert(r == 0);
6800Sstevel@tonic-gate 		break;
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	case SCF_TYPE_ASTRING:
6830Sstevel@tonic-gate 		r = scf_value_set_astring(v, val);
6840Sstevel@tonic-gate 		assert(r == 0);
6850Sstevel@tonic-gate 		break;
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	default:
6880Sstevel@tonic-gate 		assert(0);
6890Sstevel@tonic-gate 		abort();
6900Sstevel@tonic-gate 	}
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	if (scf_entry_add_value(e, v) == 0)
6930Sstevel@tonic-gate 		return (0);
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	func = "scf_entry_add_value()";
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate err:
6980Sstevel@tonic-gate 	uu_warn(gettext("%s failed (%s).\n"), func, scf_strerror(scf_error()));
6990Sstevel@tonic-gate 	return (-1);
7000Sstevel@tonic-gate }
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate static void
set_legacy_service(scf_propertygroup_t * pg,const char * script,ino_t inode)703*12718SVladimir.Marek@Sun.COM set_legacy_service(scf_propertygroup_t *pg, const char *script, ino_t inode)
7040Sstevel@tonic-gate {
7050Sstevel@tonic-gate 	scf_handle_t *h;
7060Sstevel@tonic-gate 	const char *func;
7070Sstevel@tonic-gate 	char *suffix;
7080Sstevel@tonic-gate 	scf_transaction_t *tx;
7090Sstevel@tonic-gate 	struct timeval tstamp;
7100Sstevel@tonic-gate 	ctid_t ctid;
7110Sstevel@tonic-gate 	char *svc_name = NULL;
7120Sstevel@tonic-gate 	int ret;
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 	h = scf_pg_handle(pg);
7150Sstevel@tonic-gate 	if (h == NULL) {
7160Sstevel@tonic-gate 		func = "scf_pg_handle()";
7170Sstevel@tonic-gate 		goto scferr;
7180Sstevel@tonic-gate 	}
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	ret = gettimeofday(&tstamp, NULL);
7210Sstevel@tonic-gate 	assert(ret == 0);
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 	if (errno = contract_latest(&ctid)) {
7240Sstevel@tonic-gate 		uu_warn(gettext("Could not get contract"));
7250Sstevel@tonic-gate 		goto err;
7260Sstevel@tonic-gate 	}
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	tx = scf_transaction_create(h);
7290Sstevel@tonic-gate 	if (tx == NULL) {
7300Sstevel@tonic-gate 		func = "scf_transaction_create()";
7310Sstevel@tonic-gate 		goto scferr;
7320Sstevel@tonic-gate 	}
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	if (scf_transaction_start(tx, pg) != 0) {
7350Sstevel@tonic-gate 		func = "scf_transaction_start()";
7360Sstevel@tonic-gate 		goto scferr;
7370Sstevel@tonic-gate 	}
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 	/*
7400Sstevel@tonic-gate 	 * We'd like to use the prettier svc_name, but if path_to_svc_name()
7410Sstevel@tonic-gate 	 * fails, we can use the script name anyway.
7420Sstevel@tonic-gate 	 */
7430Sstevel@tonic-gate 	svc_name = path_to_svc_name(script);
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 	if (add_new_property(h, tx, SCF_LEGACY_PROPERTY_NAME, SCF_TYPE_ASTRING,
7460Sstevel@tonic-gate 	    (void *)(svc_name ? svc_name : script)) != 0)
7470Sstevel@tonic-gate 		goto err;
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	if (add_new_property(h, tx, SCF_PROPERTY_STATE_TIMESTAMP,
7500Sstevel@tonic-gate 	    SCF_TYPE_TIME, &tstamp) != 0)
7510Sstevel@tonic-gate 		goto err;
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate 	if (add_new_property(h, tx, SCF_LEGACY_PROPERTY_INODE,
754*12718SVladimir.Marek@Sun.COM 	    SCF_TYPE_COUNT, (void *)inode) != 0)
7550Sstevel@tonic-gate 		goto err;
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	if ((suffix = script_suffix(script)) != NULL) {
7580Sstevel@tonic-gate 		if (add_new_property(h, tx, SCF_LEGACY_PROPERTY_SUFFIX,
7590Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, (void *)suffix) != 0)
7600Sstevel@tonic-gate 			goto err;
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 		free(suffix);
7630Sstevel@tonic-gate 	}
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 	if (add_new_property(h, tx, SCF_PROPERTY_CONTRACT, SCF_TYPE_COUNT,
7660Sstevel@tonic-gate 	    (void *)ctid) != 0)
7670Sstevel@tonic-gate 		goto err;
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 	for (;;) {
7700Sstevel@tonic-gate 		switch (scf_transaction_commit(tx)) {
7710Sstevel@tonic-gate 		case 1:
7720Sstevel@tonic-gate 			free(svc_name);
7730Sstevel@tonic-gate 			return;
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 		case 0:
7760Sstevel@tonic-gate 			if (scf_pg_update(pg) == -1) {
7770Sstevel@tonic-gate 				func = "scf_pg_update()";
7780Sstevel@tonic-gate 				goto scferr;
7790Sstevel@tonic-gate 			}
7800Sstevel@tonic-gate 			continue;
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 		case -1:
7830Sstevel@tonic-gate 			func = "scf_transaction_commit()";
7840Sstevel@tonic-gate 			goto scferr;
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 		default:
7870Sstevel@tonic-gate 			assert(0);
7880Sstevel@tonic-gate 			abort();
7890Sstevel@tonic-gate 		}
7900Sstevel@tonic-gate 	}
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate scferr:
7930Sstevel@tonic-gate 	uu_warn(gettext("%s failed (%s).\n"), func, scf_strerror(scf_error()));
7940Sstevel@tonic-gate err:
7950Sstevel@tonic-gate 	uu_die(gettext("Could not commit property values to repository.\n"));
7960Sstevel@tonic-gate }
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate int
main(int argc,char * argv[],char * envp[])7990Sstevel@tonic-gate main(int argc, char *argv[], char *envp[])
8000Sstevel@tonic-gate {
8010Sstevel@tonic-gate 	const char *restarter, *script, *action;
8020Sstevel@tonic-gate 	boolean_t source = 0;
8030Sstevel@tonic-gate 	int o;
8040Sstevel@tonic-gate 	boolean_t start_flag;
8050Sstevel@tonic-gate 	char **newenv;
8060Sstevel@tonic-gate 	pid_t pid;
8070Sstevel@tonic-gate 	int pipefds[2];
8080Sstevel@tonic-gate 	char c;
8090Sstevel@tonic-gate 	int exitstatus;
810*12718SVladimir.Marek@Sun.COM 	struct stat st;
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	scf_propertygroup_t *pg;
8130Sstevel@tonic-gate 	boolean_t pg_ok;
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	(void) uu_setpname(argv[0]);
8160Sstevel@tonic-gate 	uu_alt_exit(UU_PROFILE_LAUNCHER);
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	/* Make sure we were run by svc.startd. */
8190Sstevel@tonic-gate 	if ((restarter = getenv("SMF_RESTARTER")) == NULL ||
8200Sstevel@tonic-gate 	    strcmp(restarter, SCF_SERVICE_STARTD) != 0)
8210Sstevel@tonic-gate 		uu_die(gettext("invocation outside smf(5) inappropriate\n"));
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	while ((o = getopt(argc, argv, "s")) != -1) {
8240Sstevel@tonic-gate 		switch (o) {
8250Sstevel@tonic-gate 		case 's':
8260Sstevel@tonic-gate 			source = 1;
8270Sstevel@tonic-gate 			break;
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 		default:
8300Sstevel@tonic-gate 			usage();
8310Sstevel@tonic-gate 		}
8320Sstevel@tonic-gate 	}
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 	if (argc - optind != 2)
8350Sstevel@tonic-gate 		usage();
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	script = argv[optind];
8380Sstevel@tonic-gate 	action = argv[optind + 1];
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 	if (strcmp(action, "start") == 0)
8410Sstevel@tonic-gate 		start_flag = 1;
8420Sstevel@tonic-gate 	else if (strcmp(action, "stop") == 0)
8430Sstevel@tonic-gate 		start_flag = 0;
8440Sstevel@tonic-gate 	else
8450Sstevel@tonic-gate 		usage();
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	/*
8480Sstevel@tonic-gate 	 * Look for the pg & exit if appropriate.  Also, if we're starting,
8490Sstevel@tonic-gate 	 * add the pg now so we can exit before launching the script if we
8500Sstevel@tonic-gate 	 * have insufficient repository privilege.
8510Sstevel@tonic-gate 	 *
8520Sstevel@tonic-gate 	 * If any other problem occurs, we carry on anyway.
8530Sstevel@tonic-gate 	 */
8540Sstevel@tonic-gate 	pg = get_script_pg(script, start_flag, &pg_ok);
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 	/* Clean the environment.  Now so we can fail early. */
8570Sstevel@tonic-gate 	if (!source)
8580Sstevel@tonic-gate 		newenv = approved_env(envp);
8590Sstevel@tonic-gate 	else
8600Sstevel@tonic-gate 		newenv = env_without_smf(envp);
8610Sstevel@tonic-gate 	if (newenv == NULL)
8620Sstevel@tonic-gate 		uu_die(gettext(
8630Sstevel@tonic-gate 		    "Could not create new environment: out of memory.\n"));
8640Sstevel@tonic-gate 
8656073Sacruz 	if (prepare_contract(script, action) == -1) {
8660Sstevel@tonic-gate 		if (start_flag && pg != NULL)
8670Sstevel@tonic-gate 			cleanup_pg(pg);
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 		exit(UU_EXIT_FATAL);
8700Sstevel@tonic-gate 	}
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 	/* pipe to communicate exec success or failure */
8730Sstevel@tonic-gate 	if (pipe(pipefds) != 0) {
8740Sstevel@tonic-gate 		uu_warn(gettext("Could not create pipe"));
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 		if (start_flag && pg != NULL)
8770Sstevel@tonic-gate 			cleanup_pg(pg);
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 		exit(UU_EXIT_FATAL);
8800Sstevel@tonic-gate 	}
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	if (!pg_ok)
8830Sstevel@tonic-gate 		(void) printf(gettext("Executing legacy init script \"%s\" "
8840Sstevel@tonic-gate 		    "despite previous errors.\n"), script);
8850Sstevel@tonic-gate 	else
8860Sstevel@tonic-gate 		(void) printf(gettext("Executing legacy init script \"%s\".\n"),
8870Sstevel@tonic-gate 		    script);
8880Sstevel@tonic-gate 	(void) fflush(stdout);
8890Sstevel@tonic-gate 
890*12718SVladimir.Marek@Sun.COM 	if (stat(script, &st) != 0) {
891*12718SVladimir.Marek@Sun.COM 		uu_warn(gettext("Couldn't stat %s (%s).\n"), script,
892*12718SVladimir.Marek@Sun.COM 		    strerror(errno));
893*12718SVladimir.Marek@Sun.COM 		st.st_ino = (ino_t)0;
894*12718SVladimir.Marek@Sun.COM 	}
895*12718SVladimir.Marek@Sun.COM 
8960Sstevel@tonic-gate 	pid = fork();
8970Sstevel@tonic-gate 	if (pid < 0) {
8980Sstevel@tonic-gate 		uu_warn(gettext("Could not fork"));
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 		if (start_flag && pg != NULL)
9010Sstevel@tonic-gate 			cleanup_pg(pg);
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 		exit(UU_EXIT_FATAL);
9040Sstevel@tonic-gate 	}
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	if (pid == 0) {
9070Sstevel@tonic-gate 		/* child */
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 		const char *arg1, *arg2, *arg3;
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 		(void) close(pipefds[0]);
9120Sstevel@tonic-gate 		(void) fcntl(pipefds[1], F_SETFD, FD_CLOEXEC);
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 		if (!source) {
9150Sstevel@tonic-gate 			arg1 = "/bin/sh";
9160Sstevel@tonic-gate 			arg2 = script;
9170Sstevel@tonic-gate 			arg3 = action;
9180Sstevel@tonic-gate 		} else {
9190Sstevel@tonic-gate 			arg1 = "/bin/sh";
9200Sstevel@tonic-gate 			arg2 = "-c";
9210Sstevel@tonic-gate 			arg3 = script;
9220Sstevel@tonic-gate 		}
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 		(void) execle(arg1, arg1, arg2, arg3, NULL, newenv);
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate 		uu_warn(gettext("Could not exec \"%s %s %s\""), arg1,
9270Sstevel@tonic-gate 		    arg2, arg3);
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 		/* Notify parent of the failure. */
9310Sstevel@tonic-gate 		while (write(pipefds[1], &c, 1) != 1) {
9320Sstevel@tonic-gate 			switch (errno) {
9330Sstevel@tonic-gate 			case EAGAIN:
9340Sstevel@tonic-gate 				(void) sleep(1);
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 				/* FALLTHROUGH */
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 			case EINTR:
9390Sstevel@tonic-gate 				continue;
9400Sstevel@tonic-gate 			}
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 			uu_warn(gettext("Could not inform parent of error"));
9430Sstevel@tonic-gate 			break;
9440Sstevel@tonic-gate 		}
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 		exit(UU_EXIT_FATAL);
9470Sstevel@tonic-gate 	}
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	(void) close(pipefds[1]);
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 	if (read(pipefds[0], &c, sizeof (c)) > 0) {
9520Sstevel@tonic-gate 		if (!start_flag)
9530Sstevel@tonic-gate 			uu_die(gettext("exec() failed; leaving properties.\n"));
9540Sstevel@tonic-gate 		else {
9550Sstevel@tonic-gate 			uu_warn(gettext("exec() failed.\n"));
9560Sstevel@tonic-gate 			if (pg != NULL)
9570Sstevel@tonic-gate 				cleanup_pg(pg);
9580Sstevel@tonic-gate 			exit(UU_EXIT_FATAL);
9590Sstevel@tonic-gate 		}
9600Sstevel@tonic-gate 	}
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	while (waitpid(pid, &exitstatus, 0) == -1) {
9630Sstevel@tonic-gate 		assert(errno == EINTR);
9640Sstevel@tonic-gate 	}
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 	if (WIFSIGNALED(exitstatus)) {
9670Sstevel@tonic-gate 		char buf[SIG2STR_MAX];
9680Sstevel@tonic-gate 		(void) sig2str(WTERMSIG(exitstatus), buf);
9690Sstevel@tonic-gate 		(void) printf(gettext("Legacy init script \"%s\" failed due "
9700Sstevel@tonic-gate 		    "to signal %s.\n"), script, buf);
9710Sstevel@tonic-gate 	} else {
9720Sstevel@tonic-gate 		(void) printf(gettext("Legacy init script \"%s\" exited with "
9730Sstevel@tonic-gate 		    "return code %d.\n"), script, WEXITSTATUS(exitstatus));
9740Sstevel@tonic-gate 	}
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 	if (pg != NULL) {
9770Sstevel@tonic-gate 		if (start_flag)
978*12718SVladimir.Marek@Sun.COM 			set_legacy_service(pg, script, st.st_ino);
9790Sstevel@tonic-gate 		else
9800Sstevel@tonic-gate 			cleanup_pg(pg);
9810Sstevel@tonic-gate 		scf_pg_destroy(pg);
9820Sstevel@tonic-gate 	}
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 	return (UU_EXIT_OK);
9850Sstevel@tonic-gate }
986