xref: /illumos-gate/usr/src/cmd/svc/lsvcrun/lsvcrun.c (revision bbf21555)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57b209c2cSacruz  * Common Development and Distribution License (the "License").
67b209c2cSacruz  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22d28831b8SVladimir Marek  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate /*
267c478bd9Sstevel@tonic-gate  * lsvcrun - run an rc?.d script, modifying appropriate data in the
277c478bd9Sstevel@tonic-gate  * repository to reflect legacy behavior.
287c478bd9Sstevel@tonic-gate  *
297c478bd9Sstevel@tonic-gate  * We try to keep track of what we can for the legacy scripts via
307c478bd9Sstevel@tonic-gate  * property groups under the smf/legacy_run service.  Each property
317c478bd9Sstevel@tonic-gate  * group identifies a service, named in the form 'rc2_d_S10foo'.
327c478bd9Sstevel@tonic-gate  *
337c478bd9Sstevel@tonic-gate  * Each group has the following properties: name, the script name
34*bbf21555SRichard Lowe  * displayed by svcs(1); state_timestamp; contract, contract ID;
357c478bd9Sstevel@tonic-gate  * inode, the inode of the script; and suffix, the suffix of the
367c478bd9Sstevel@tonic-gate  * script name, e.g. 'foo'.
377c478bd9Sstevel@tonic-gate  *
38d28831b8SVladimir Marek  * In order to support rc scripts which delete themselves upon invocation we
39d28831b8SVladimir Marek  * collect inode before running the script.
40d28831b8SVladimir Marek  *
417c478bd9Sstevel@tonic-gate  * When we run a K script, we try to identify and remove the
427c478bd9Sstevel@tonic-gate  * property group by means of examining the inode and script
437c478bd9Sstevel@tonic-gate  * suffix.  The inode check means more than one script with the
447c478bd9Sstevel@tonic-gate  * same suffix will still work as intended in the common case.
457c478bd9Sstevel@tonic-gate  *
467c478bd9Sstevel@tonic-gate  * If we cannot find a property group, or one already exists
477c478bd9Sstevel@tonic-gate  * when we try to add one, then we print a suitable warning.  These
487c478bd9Sstevel@tonic-gate  * are warnings because there was no strict requirement that K
497c478bd9Sstevel@tonic-gate  * and S scripts be matched up.
507c478bd9Sstevel@tonic-gate  *
517c478bd9Sstevel@tonic-gate  * In the face of these assumptions being proved wrong, we always
527c478bd9Sstevel@tonic-gate  * make sure to execute the script anyway in an attempt to keep
537c478bd9Sstevel@tonic-gate  * things working as they used to.  If we can't execute the script,
547c478bd9Sstevel@tonic-gate  * we try to leave the repository in the state it was before.
557c478bd9Sstevel@tonic-gate  */
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate #include <sys/ctfs.h>
587c478bd9Sstevel@tonic-gate #include <sys/types.h>
597c478bd9Sstevel@tonic-gate #include <sys/wait.h>
607c478bd9Sstevel@tonic-gate #include <sys/stat.h>
617c478bd9Sstevel@tonic-gate #include <assert.h>
627c478bd9Sstevel@tonic-gate #include <ctype.h>
637c478bd9Sstevel@tonic-gate #include <errno.h>
647c478bd9Sstevel@tonic-gate #include <fcntl.h>
657c478bd9Sstevel@tonic-gate #include <fnmatch.h>
667c478bd9Sstevel@tonic-gate #include <libcontract.h>
677c478bd9Sstevel@tonic-gate #include <libcontract_priv.h>
687c478bd9Sstevel@tonic-gate #include <libintl.h>
697c478bd9Sstevel@tonic-gate #include <libscf.h>
707c478bd9Sstevel@tonic-gate #include <libscf_priv.h>
717c478bd9Sstevel@tonic-gate #include <libuutil.h>
727c478bd9Sstevel@tonic-gate #include <signal.h>
737c478bd9Sstevel@tonic-gate #include <stdio.h>
747c478bd9Sstevel@tonic-gate #include <stdlib.h>
757c478bd9Sstevel@tonic-gate #include <string.h>
767c478bd9Sstevel@tonic-gate #include <strings.h>
777c478bd9Sstevel@tonic-gate #include <time.h>
787c478bd9Sstevel@tonic-gate #include <unistd.h>
797c478bd9Sstevel@tonic-gate #include <limits.h>
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate /* Environment variables to pass on.  See clean_environment(). */
837c478bd9Sstevel@tonic-gate static char *evars_to_pass[] = { "LANG", "LC_ALL", "LC_COLLATE", "LC_CTYPE",
847c478bd9Sstevel@tonic-gate 	"LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC", "LC_TIME", "PATH", "TZ"
857c478bd9Sstevel@tonic-gate };
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate #define	EVARS_TO_PASS_NUM						\
887c478bd9Sstevel@tonic-gate 	(sizeof (evars_to_pass) / sizeof (*evars_to_pass))
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate static void
usage()927c478bd9Sstevel@tonic-gate usage()
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
957c478bd9Sstevel@tonic-gate 	    gettext("Usage: %s [-s] script {start | stop}\n"), uu_getpname());
967c478bd9Sstevel@tonic-gate 	exit(UU_EXIT_USAGE);
977c478bd9Sstevel@tonic-gate }
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate /*
1007c478bd9Sstevel@tonic-gate  * Pick out the script name and convert it for use as an SMF property
1017c478bd9Sstevel@tonic-gate  * group name.
1027c478bd9Sstevel@tonic-gate  */
1037c478bd9Sstevel@tonic-gate static char *
start_pg_name(const char * path)1047c478bd9Sstevel@tonic-gate start_pg_name(const char *path)
1057c478bd9Sstevel@tonic-gate {
1067c478bd9Sstevel@tonic-gate 	char *out, *cp;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	if (fnmatch("/etc/rc[0-6S].d/S*", path, FNM_PATHNAME) != 0) {
1097c478bd9Sstevel@tonic-gate 		uu_warn(gettext("couldn't parse name %s.\n"), path);
1107c478bd9Sstevel@tonic-gate 		return (NULL);
1117c478bd9Sstevel@tonic-gate 	}
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	out = strdup(path + sizeof ("/etc/") - 1);
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	if (out == NULL) {
1167c478bd9Sstevel@tonic-gate 		uu_warn(gettext("strdup() failed (%s).\n"), strerror(errno));
1177c478bd9Sstevel@tonic-gate 		return (NULL);
1187c478bd9Sstevel@tonic-gate 	}
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	/* Convert illegal characters to _. */
1217c478bd9Sstevel@tonic-gate 	for (cp = out; *cp != '\0'; ++cp) {
1227c478bd9Sstevel@tonic-gate 		/* locale problem? */
1237c478bd9Sstevel@tonic-gate 		if (!isalnum(*cp) && *cp != '-')
1247c478bd9Sstevel@tonic-gate 			*cp = '_';
1257c478bd9Sstevel@tonic-gate 	}
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	return (out);
1287c478bd9Sstevel@tonic-gate }
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate static char *
script_suffix(const char * path)1317c478bd9Sstevel@tonic-gate script_suffix(const char *path)
1327c478bd9Sstevel@tonic-gate {
1337c478bd9Sstevel@tonic-gate 	const char *cp;
1347c478bd9Sstevel@tonic-gate 	char *out;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	if (fnmatch("/etc/rc[0-6S].d/[SK]*", path, FNM_PATHNAME) != 0) {
1377c478bd9Sstevel@tonic-gate 		uu_warn(gettext("couldn't parse name %s.\n"), path);
1387c478bd9Sstevel@tonic-gate 		return (NULL);
1397c478bd9Sstevel@tonic-gate 	}
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	cp = path + sizeof ("/etc/rc0.d/S") - 1;
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	while (isdigit(*cp))
1447c478bd9Sstevel@tonic-gate 		cp++;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	if (*cp == '\0') {
1477c478bd9Sstevel@tonic-gate 		uu_warn(gettext("couldn't parse name %s.\n"), path);
1487c478bd9Sstevel@tonic-gate 		return (NULL);
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	out = strdup(cp);
1527c478bd9Sstevel@tonic-gate 	if (out == NULL)
1537c478bd9Sstevel@tonic-gate 		uu_warn(gettext("strdup() failed (%s).\n"), strerror(errno));
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	return (out);
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate /*
1597c478bd9Sstevel@tonic-gate  * Convert a path to an acceptable SMF (service) name.
1607c478bd9Sstevel@tonic-gate  */
1617c478bd9Sstevel@tonic-gate static char *
path_to_svc_name(const char * path)1627c478bd9Sstevel@tonic-gate path_to_svc_name(const char *path)
1637c478bd9Sstevel@tonic-gate {
1647c478bd9Sstevel@tonic-gate 	char *out, *cp;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	out = strdup(path);
1677c478bd9Sstevel@tonic-gate 	if (out == NULL) {
1687c478bd9Sstevel@tonic-gate 		uu_warn(gettext("strdup() failed (%s).\n"), strerror(errno));
1697c478bd9Sstevel@tonic-gate 		return (NULL);
1707c478bd9Sstevel@tonic-gate 	}
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	/* Convert illegal characters to _. */
1737c478bd9Sstevel@tonic-gate 	for (cp = out; *cp != '\0'; ++cp) {
1747c478bd9Sstevel@tonic-gate 		/* locale problem? */
1757c478bd9Sstevel@tonic-gate 		if (!isalnum(*cp) && *cp != '-' && *cp != '/')
1767c478bd9Sstevel@tonic-gate 			*cp = '_';
1777c478bd9Sstevel@tonic-gate 	}
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	/* If the first character is _, use a instead. */
1807c478bd9Sstevel@tonic-gate 	if (*out == '_')
1817c478bd9Sstevel@tonic-gate 		*out = 'a';
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	return (out);
1847c478bd9Sstevel@tonic-gate }
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate static void
scferr(const char * func)1877c478bd9Sstevel@tonic-gate scferr(const char *func)
1887c478bd9Sstevel@tonic-gate {
1897c478bd9Sstevel@tonic-gate 	uu_warn(gettext("%s failed (%s).  Repository will not be modified.\n"),
1907c478bd9Sstevel@tonic-gate 	    func, scf_strerror(scf_error()));
1917c478bd9Sstevel@tonic-gate }
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate static scf_propertygroup_t *
get_start_pg(const char * script,scf_handle_t * h,scf_service_t * svc,boolean_t * ok)1947c478bd9Sstevel@tonic-gate get_start_pg(const char *script, scf_handle_t *h, scf_service_t *svc,
1957c478bd9Sstevel@tonic-gate     boolean_t *ok)
1967c478bd9Sstevel@tonic-gate {
1977c478bd9Sstevel@tonic-gate 	char *pg_name = NULL;
1987c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
1997c478bd9Sstevel@tonic-gate 	scf_property_t *prop = NULL;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	if ((pg_name = start_pg_name(script)) == NULL)
2027c478bd9Sstevel@tonic-gate 		return (NULL);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	if ((pg = scf_pg_create(h)) == NULL) {
2057c478bd9Sstevel@tonic-gate 		scferr("scf_pg_create()");
2067c478bd9Sstevel@tonic-gate 		goto out;
2077c478bd9Sstevel@tonic-gate 	}
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate add:
2107c478bd9Sstevel@tonic-gate 	if (scf_service_add_pg(svc, pg_name, SCF_GROUP_FRAMEWORK,
2117c478bd9Sstevel@tonic-gate 	    SCF_PG_FLAG_NONPERSISTENT, pg) == 0) {
2127c478bd9Sstevel@tonic-gate 		*ok = 1;
2137c478bd9Sstevel@tonic-gate 		free(pg_name);
2147c478bd9Sstevel@tonic-gate 		return (pg);
2157c478bd9Sstevel@tonic-gate 	}
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	switch (scf_error()) {
2187c478bd9Sstevel@tonic-gate 	case SCF_ERROR_INVALID_ARGUMENT:
2197c478bd9Sstevel@tonic-gate 		assert(0);
2207c478bd9Sstevel@tonic-gate 		abort();
2217c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	case SCF_ERROR_EXISTS:
2247c478bd9Sstevel@tonic-gate 		break;
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	case SCF_ERROR_PERMISSION_DENIED:
2277c478bd9Sstevel@tonic-gate 		uu_die(gettext(
2287c478bd9Sstevel@tonic-gate 		    "Insufficient privilege to add repository properties; "
2297c478bd9Sstevel@tonic-gate 		    "not launching \"%s\".\n"), script);
2307c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	default:
2337c478bd9Sstevel@tonic-gate 		scferr("scf_service_add_pg()");
2347c478bd9Sstevel@tonic-gate 		scf_pg_destroy(pg);
2357c478bd9Sstevel@tonic-gate 		pg = NULL;
2367c478bd9Sstevel@tonic-gate 		goto out;
2377c478bd9Sstevel@tonic-gate 	}
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	if (scf_service_get_pg(svc, pg_name, pg) != 0) {
2407c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
2417c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
2427c478bd9Sstevel@tonic-gate 			assert(0);
2437c478bd9Sstevel@tonic-gate 			abort();
2447c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
2477c478bd9Sstevel@tonic-gate 			goto add;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 		default:
2507c478bd9Sstevel@tonic-gate 			scferr("scf_service_get_pg()");
2517c478bd9Sstevel@tonic-gate 			scf_pg_destroy(pg);
2527c478bd9Sstevel@tonic-gate 			pg = NULL;
2537c478bd9Sstevel@tonic-gate 			goto out;
2547c478bd9Sstevel@tonic-gate 		}
2557c478bd9Sstevel@tonic-gate 	}
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	if ((prop = scf_property_create(h)) == NULL) {
2587c478bd9Sstevel@tonic-gate 		scferr("scf_property_create()");
2597c478bd9Sstevel@tonic-gate 		scf_pg_destroy(pg);
2607c478bd9Sstevel@tonic-gate 		pg = NULL;
2617c478bd9Sstevel@tonic-gate 		goto out;
2627c478bd9Sstevel@tonic-gate 	}
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	/*
2657c478bd9Sstevel@tonic-gate 	 * See if the pg has the name property.  If it has, that
2667c478bd9Sstevel@tonic-gate 	 * implies we successfully ran the same script before.  We
2677c478bd9Sstevel@tonic-gate 	 * should re-run it anyway, but not modify the existing pg;
2687c478bd9Sstevel@tonic-gate 	 * this might lose contract-control but there's not much we
2697c478bd9Sstevel@tonic-gate 	 * can do.
2707c478bd9Sstevel@tonic-gate 	 *
2717c478bd9Sstevel@tonic-gate 	 * If there's no name property, then we probably couldn't
2727c478bd9Sstevel@tonic-gate 	 * remove the pg fully after a script failed to run.
2737c478bd9Sstevel@tonic-gate 	 */
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, SCF_LEGACY_PROPERTY_NAME, prop) == 0) {
2767c478bd9Sstevel@tonic-gate 		uu_warn(gettext("Service matching \"%s\" "
2777c478bd9Sstevel@tonic-gate 		    "seems to be running.\n"), script);
2787c478bd9Sstevel@tonic-gate 		scf_pg_destroy(pg);
2797c478bd9Sstevel@tonic-gate 		pg = NULL;
2807c478bd9Sstevel@tonic-gate 	} else if (scf_error() != SCF_ERROR_NOT_FOUND) {
2817c478bd9Sstevel@tonic-gate 		scferr("scf_pg_get_property()");
2827c478bd9Sstevel@tonic-gate 		scf_pg_destroy(pg);
2837c478bd9Sstevel@tonic-gate 		pg = NULL;
2847c478bd9Sstevel@tonic-gate 	} else {
2857c478bd9Sstevel@tonic-gate 		uu_warn(gettext("Service \"%s\" has an invalid property "
2867c478bd9Sstevel@tonic-gate 		    "group.\n"), script);
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate out:
2907c478bd9Sstevel@tonic-gate 	free(pg_name);
2917c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
2927c478bd9Sstevel@tonic-gate 	return (pg);
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate static scf_propertygroup_t *
pg_match(scf_handle_t * h,scf_service_t * svc,ino_t ino,const char * suffix)2967c478bd9Sstevel@tonic-gate pg_match(scf_handle_t *h, scf_service_t *svc, ino_t ino, const char *suffix)
2977c478bd9Sstevel@tonic-gate {
2987c478bd9Sstevel@tonic-gate 	char buf[PATH_MAX];
2997c478bd9Sstevel@tonic-gate 	scf_iter_t *iter = NULL;
3007c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
3017c478bd9Sstevel@tonic-gate 	scf_property_t *prop = NULL;
3027c478bd9Sstevel@tonic-gate 	scf_value_t *val = NULL;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	if ((pg = scf_pg_create(h)) == NULL) {
3057c478bd9Sstevel@tonic-gate 		scferr("scf_pg_create()");
3067c478bd9Sstevel@tonic-gate 		goto err;
3077c478bd9Sstevel@tonic-gate 	}
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	if ((iter = scf_iter_create(h)) == NULL) {
3107c478bd9Sstevel@tonic-gate 		scferr("scf_iter_create()");
3117c478bd9Sstevel@tonic-gate 		goto err;
3127c478bd9Sstevel@tonic-gate 	}
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	if ((prop = scf_property_create(h)) == NULL) {
3157c478bd9Sstevel@tonic-gate 		scferr("scf_property_create()");
3167c478bd9Sstevel@tonic-gate 		goto err;
3177c478bd9Sstevel@tonic-gate 	}
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	if ((val = scf_value_create(h)) == NULL) {
3207c478bd9Sstevel@tonic-gate 		scferr("scf_value_create()");
3217c478bd9Sstevel@tonic-gate 		goto err;
3227c478bd9Sstevel@tonic-gate 	}
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	if (scf_iter_service_pgs_typed(iter, svc, SCF_GROUP_FRAMEWORK) !=
3257c478bd9Sstevel@tonic-gate 	    0) {
3267c478bd9Sstevel@tonic-gate 		scferr("scf_iter_service_pgs_typed()");
3277c478bd9Sstevel@tonic-gate 		goto err;
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	while (scf_iter_next_pg(iter, pg) > 0) {
3317c478bd9Sstevel@tonic-gate 		int match = 1;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 		if (suffix != NULL) {
3347c478bd9Sstevel@tonic-gate 			ssize_t len;
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 			if (scf_pg_get_property(pg, SCF_LEGACY_PROPERTY_SUFFIX,
3377c478bd9Sstevel@tonic-gate 			    prop) != 0)
3387c478bd9Sstevel@tonic-gate 				continue;
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 			if (scf_property_get_value(prop, val) != 0)
3417c478bd9Sstevel@tonic-gate 				continue;
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 			len = scf_value_get_astring(val, buf, sizeof (buf));
3447c478bd9Sstevel@tonic-gate 			if (len < 0) {
3457c478bd9Sstevel@tonic-gate 				scferr("scf_value_get_astring()");
3467c478bd9Sstevel@tonic-gate 				goto err;
3477c478bd9Sstevel@tonic-gate 			}
3487c478bd9Sstevel@tonic-gate 			if (len >= sizeof (buf))
3497c478bd9Sstevel@tonic-gate 				continue;
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 			match = (strcmp(buf, suffix) == 0);
3527c478bd9Sstevel@tonic-gate 		}
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 		if (ino != 0) {
3557c478bd9Sstevel@tonic-gate 			uint64_t pval;
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 			if (scf_pg_get_property(pg, SCF_LEGACY_PROPERTY_INODE,
3587c478bd9Sstevel@tonic-gate 			    prop) != 0)
3597c478bd9Sstevel@tonic-gate 				continue;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 			if (scf_property_get_value(prop, val) != 0)
3627c478bd9Sstevel@tonic-gate 				continue;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 			if (scf_value_get_count(val, &pval) != 0)
3657c478bd9Sstevel@tonic-gate 				continue;
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 			match = (ino == pval) && match;
3687c478bd9Sstevel@tonic-gate 		}
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 		if (match)
3717c478bd9Sstevel@tonic-gate 			goto out;
3727c478bd9Sstevel@tonic-gate 	}
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate err:
3757c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
3767c478bd9Sstevel@tonic-gate 	pg = NULL;
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate out:
3797c478bd9Sstevel@tonic-gate 	scf_value_destroy(val);
3807c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
3817c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
3827c478bd9Sstevel@tonic-gate 	return (pg);
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate /*
3867c478bd9Sstevel@tonic-gate  * Try and find the property group matching the service this script
3877c478bd9Sstevel@tonic-gate  * stops.  First we look for a matching inode plus a matching suffix.
3887c478bd9Sstevel@tonic-gate  * This commonly succeeds, but if not, we just search for inode.
3897c478bd9Sstevel@tonic-gate  * Finally, we try for just the script suffix.
3907c478bd9Sstevel@tonic-gate  */
3917c478bd9Sstevel@tonic-gate static scf_propertygroup_t *
get_stop_pg(const char * script,scf_handle_t * h,scf_service_t * svc,boolean_t * ok)3927c478bd9Sstevel@tonic-gate get_stop_pg(const char *script, scf_handle_t *h, scf_service_t *svc,
3937c478bd9Sstevel@tonic-gate     boolean_t *ok)
3947c478bd9Sstevel@tonic-gate {
3957c478bd9Sstevel@tonic-gate 	struct stat st;
3967c478bd9Sstevel@tonic-gate 	char *suffix;
3977c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	if (stat(script, &st) != 0) {
4007c478bd9Sstevel@tonic-gate 		uu_warn(gettext("Couldn't stat %s (%s).\n"), script,
4017c478bd9Sstevel@tonic-gate 		    strerror(errno));
4027c478bd9Sstevel@tonic-gate 		return (NULL);
4037c478bd9Sstevel@tonic-gate 	}
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	if ((suffix = script_suffix(script)) == NULL) {
4067c478bd9Sstevel@tonic-gate 		pg = pg_match(h, svc, st.st_ino, NULL);
4077c478bd9Sstevel@tonic-gate 		if (pg != NULL)
4087c478bd9Sstevel@tonic-gate 			goto out;
4097c478bd9Sstevel@tonic-gate 		return (NULL);
4107c478bd9Sstevel@tonic-gate 	}
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	if ((pg = pg_match(h, svc, st.st_ino, suffix)) != NULL)
4137c478bd9Sstevel@tonic-gate 		goto out;
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	if ((pg = pg_match(h, svc, st.st_ino, NULL)) != NULL)
4167c478bd9Sstevel@tonic-gate 		goto out;
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	if ((pg = pg_match(h, svc, 0, suffix)) == NULL) {
4197c478bd9Sstevel@tonic-gate 		uu_warn(gettext("Service matching \"%s\" "
4207c478bd9Sstevel@tonic-gate 		    "doesn't seem to be running.\n"), script);
4217c478bd9Sstevel@tonic-gate 		free(suffix);
4227c478bd9Sstevel@tonic-gate 		return (NULL);
4237c478bd9Sstevel@tonic-gate 	}
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate out:
4267c478bd9Sstevel@tonic-gate 	*ok = 1;
4277c478bd9Sstevel@tonic-gate 	free(suffix);
4287c478bd9Sstevel@tonic-gate 	return (pg);
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate static scf_propertygroup_t *
get_script_pg(const char * script,boolean_t start_flag,boolean_t * ok)4327c478bd9Sstevel@tonic-gate get_script_pg(const char *script, boolean_t start_flag, boolean_t *ok)
4337c478bd9Sstevel@tonic-gate {
4347c478bd9Sstevel@tonic-gate 	scf_handle_t *h = NULL;
4357c478bd9Sstevel@tonic-gate 	scf_scope_t *scope = NULL;
4367c478bd9Sstevel@tonic-gate 	scf_service_t *svc = NULL;
4377c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	*ok = 0;
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	h = scf_handle_create(SCF_VERSION);
4427c478bd9Sstevel@tonic-gate 	if (h == NULL) {
4437c478bd9Sstevel@tonic-gate 		scferr("scf_handle_create()");
4447c478bd9Sstevel@tonic-gate 		goto out;
4457c478bd9Sstevel@tonic-gate 	}
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	if (scf_handle_bind(h) != 0) {
4487c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NO_SERVER) {
4497c478bd9Sstevel@tonic-gate 			scferr("scf_handle_bind()");
4507c478bd9Sstevel@tonic-gate 		} else {
4517c478bd9Sstevel@tonic-gate 			uu_warn(gettext(
4527c478bd9Sstevel@tonic-gate 			    "Could not connect to svc.configd.\n"));
4537c478bd9Sstevel@tonic-gate 		}
4547c478bd9Sstevel@tonic-gate 		goto out;
4557c478bd9Sstevel@tonic-gate 	}
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	if ((scope = scf_scope_create(h)) == NULL) {
4587c478bd9Sstevel@tonic-gate 		scferr("scf_scope_create()");
4597c478bd9Sstevel@tonic-gate 		goto out;
4607c478bd9Sstevel@tonic-gate 	}
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	if ((svc = scf_service_create(h)) == NULL) {
4637c478bd9Sstevel@tonic-gate 		scferr("scf_service_create()");
4647c478bd9Sstevel@tonic-gate 		goto out;
4657c478bd9Sstevel@tonic-gate 	}
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, scope) != 0) {
4687c478bd9Sstevel@tonic-gate 		scferr("scf_handle_get_local_scope()");
4697c478bd9Sstevel@tonic-gate 		goto out;
4707c478bd9Sstevel@tonic-gate 	}
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	if (scf_scope_get_service(scope, SCF_LEGACY_SERVICE, svc) != 0) {
4737c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND) {
4747c478bd9Sstevel@tonic-gate 			scferr("scf_scope_get_service()");
4757c478bd9Sstevel@tonic-gate 			goto out;
4767c478bd9Sstevel@tonic-gate 		}
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 		if (scf_scope_add_service(scope, SCF_LEGACY_SERVICE, svc) !=
4797c478bd9Sstevel@tonic-gate 		    0) {
4807c478bd9Sstevel@tonic-gate 			scferr("scf_scope_add_service()");
4817c478bd9Sstevel@tonic-gate 			goto out;
4827c478bd9Sstevel@tonic-gate 		}
4837c478bd9Sstevel@tonic-gate 	}
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	if (start_flag)
4867c478bd9Sstevel@tonic-gate 		pg = get_start_pg(script, h, svc, ok);
4877c478bd9Sstevel@tonic-gate 	else
4887c478bd9Sstevel@tonic-gate 		pg = get_stop_pg(script, h, svc, ok);
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate out:
4917c478bd9Sstevel@tonic-gate 	scf_service_destroy(svc);
4927c478bd9Sstevel@tonic-gate 	scf_scope_destroy(scope);
4937c478bd9Sstevel@tonic-gate 	return (pg);
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate static int
prepare_contract(const char * script,const char * action)4977b209c2cSacruz prepare_contract(const char *script, const char *action)
4987c478bd9Sstevel@tonic-gate {
4997c478bd9Sstevel@tonic-gate 	int fd;
5007b209c2cSacruz 	char *svc_name;
5017b209c2cSacruz 	char *svc_strbuf;
5027b209c2cSacruz 	int err = 0;
5037c478bd9Sstevel@tonic-gate 
504d28831b8SVladimir Marek 	do {
5057c478bd9Sstevel@tonic-gate 		fd = open64(CTFS_ROOT "/process/template", O_RDWR);
506d28831b8SVladimir Marek 	} while (fd < 0 && errno == EINTR);
5077c478bd9Sstevel@tonic-gate 	if (fd < 0) {
5087c478bd9Sstevel@tonic-gate 		uu_warn(gettext("Can not create contract"));
5097c478bd9Sstevel@tonic-gate 		return (-1);
5107c478bd9Sstevel@tonic-gate 	}
5117c478bd9Sstevel@tonic-gate 
5127b209c2cSacruz 	svc_strbuf = malloc(CT_PARAM_MAX_SIZE);
5137b209c2cSacruz 	if (svc_strbuf == NULL) {
5147b209c2cSacruz 		uu_warn(gettext("Can not allocate memory"));
5157b209c2cSacruz 		err = -1;
5167b209c2cSacruz 		goto cleanup;
5177b209c2cSacruz 	}
5187b209c2cSacruz 
5197b209c2cSacruz 	(void) strlcpy(svc_strbuf, SCF_FMRI_LEGACY_PREFIX, CT_PARAM_MAX_SIZE);
5207b209c2cSacruz 	svc_name = path_to_svc_name(script);
5217b209c2cSacruz 	(void) strlcat(svc_strbuf, svc_name ? svc_name : script,
5227b209c2cSacruz 	    CT_PARAM_MAX_SIZE);
5237b209c2cSacruz 	if (svc_name != NULL) {
5247b209c2cSacruz 		free(svc_name);
5257b209c2cSacruz 	}
5267b209c2cSacruz 
5277b209c2cSacruz 	if ((errno = ct_pr_tmpl_set_svc_fmri(fd, svc_strbuf)) != 0) {
5287b209c2cSacruz 		uu_warn(gettext("Can not set svc_fmri"));
5297b209c2cSacruz 		err = -1;
5307b209c2cSacruz 		goto cleanup;
5317b209c2cSacruz 	}
5327b209c2cSacruz 
5337b209c2cSacruz 	(void) strlcpy(svc_strbuf, action, CT_PARAM_MAX_SIZE);
5347b209c2cSacruz 	if ((errno = ct_pr_tmpl_set_svc_aux(fd, svc_strbuf)) != 0) {
5357b209c2cSacruz 		uu_warn(gettext("Can not set svc_aux"));
5367b209c2cSacruz 		err = -1;
5377b209c2cSacruz 		goto cleanup;
5387b209c2cSacruz 	}
5397b209c2cSacruz 
5407c478bd9Sstevel@tonic-gate 	/* Leave HWERR in fatal set. */
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	errno = ct_tmpl_activate(fd);
5437c478bd9Sstevel@tonic-gate 	if (errno != 0) {
5447c478bd9Sstevel@tonic-gate 		assert(errno == EPERM);
5457c478bd9Sstevel@tonic-gate 		uu_warn(gettext("Can not activate contract template"));
5467b209c2cSacruz 		err = -1;
5477b209c2cSacruz 		goto cleanup;
5487c478bd9Sstevel@tonic-gate 	}
5497c478bd9Sstevel@tonic-gate 
5507b209c2cSacruz cleanup:
5517b209c2cSacruz 	if (svc_strbuf != NULL)
5527b209c2cSacruz 		free(svc_strbuf);
5537c478bd9Sstevel@tonic-gate 	(void) close(fd);
5547b209c2cSacruz 
5557b209c2cSacruz 	return (err);
5567c478bd9Sstevel@tonic-gate }
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate static void
cleanup_pg(scf_propertygroup_t * pg)5597c478bd9Sstevel@tonic-gate cleanup_pg(scf_propertygroup_t *pg)
5607c478bd9Sstevel@tonic-gate {
5617c478bd9Sstevel@tonic-gate 	scf_error_t err;
5627c478bd9Sstevel@tonic-gate 	char buf[80];
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	if (scf_pg_delete(pg) == 0)
5657c478bd9Sstevel@tonic-gate 		return;
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	err = scf_error();
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	if (scf_pg_to_fmri(pg, buf, sizeof (buf)) != 0)
5707c478bd9Sstevel@tonic-gate 		(void) strcpy(buf, "?");
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	uu_warn(gettext("Could not remove property group %s: %s.\n"), buf,
5737c478bd9Sstevel@tonic-gate 	    scf_strerror(err));
5747c478bd9Sstevel@tonic-gate }
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate /*
5777c478bd9Sstevel@tonic-gate  * Create a duplicate environment which only contains approved
5787c478bd9Sstevel@tonic-gate  * variables---those in evars_to_pass and those beginning with "_INIT_".
5797c478bd9Sstevel@tonic-gate  */
5807c478bd9Sstevel@tonic-gate static char **
approved_env(char ** env)5817c478bd9Sstevel@tonic-gate approved_env(char **env)
5827c478bd9Sstevel@tonic-gate {
5837c478bd9Sstevel@tonic-gate 	char **newenv;
5847c478bd9Sstevel@tonic-gate 	int i, i_new, j;
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	for (i = 0; env[i] != NULL; ++i)
5877c478bd9Sstevel@tonic-gate 		;
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	newenv = malloc(sizeof (*newenv) * (i + 1));
5907c478bd9Sstevel@tonic-gate 	if (newenv == NULL)
5917c478bd9Sstevel@tonic-gate 		return (NULL);
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	i_new = 0;
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	for (i = 0; env[i] != NULL; ++i) {
5967c478bd9Sstevel@tonic-gate 		if (strncmp(env[i], "_INIT_", sizeof ("_INIT_") - 1) == 0) {
5977c478bd9Sstevel@tonic-gate 			newenv[i_new++] = env[i];
5987c478bd9Sstevel@tonic-gate 			continue;
5997c478bd9Sstevel@tonic-gate 		}
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 		for (j = 0; j < EVARS_TO_PASS_NUM; ++j) {
6027c478bd9Sstevel@tonic-gate 			size_t l = strlen(evars_to_pass[j]);
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 			if (env[i][l] == '=' &&
6057c478bd9Sstevel@tonic-gate 			    strncmp(env[i], evars_to_pass[j], l) == 0)
6067b209c2cSacruz 				newenv[i_new++] = env[i];
6077c478bd9Sstevel@tonic-gate 		}
6087c478bd9Sstevel@tonic-gate 	}
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	newenv[i_new] = NULL;
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	return (newenv);
6137c478bd9Sstevel@tonic-gate }
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate /*
6167c478bd9Sstevel@tonic-gate  * Create a duplicate environment which does not contain any SMF_ variables.
6177c478bd9Sstevel@tonic-gate  */
6187c478bd9Sstevel@tonic-gate static char **
env_without_smf(char ** env)6197c478bd9Sstevel@tonic-gate env_without_smf(char **env)
6207c478bd9Sstevel@tonic-gate {
6217c478bd9Sstevel@tonic-gate 	char **newenv;
6227c478bd9Sstevel@tonic-gate 	int i, i_new;
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	for (i = 0; env[i] != NULL; ++i)
6257c478bd9Sstevel@tonic-gate 		;
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	newenv = malloc(sizeof (*newenv) * (i + 1));
6287c478bd9Sstevel@tonic-gate 	if (newenv == NULL)
6297c478bd9Sstevel@tonic-gate 		return (NULL);
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	i_new = 0;
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 	for (i = 0; env[i] != NULL; ++i) {
6347c478bd9Sstevel@tonic-gate 		if (strncmp(env[i], "SMF_", sizeof ("SMF_") - 1) == 0)
6357c478bd9Sstevel@tonic-gate 			continue;
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 		newenv[i_new++] = env[i];
6387c478bd9Sstevel@tonic-gate 	}
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	newenv[i_new] = NULL;
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	return (newenv);
6437c478bd9Sstevel@tonic-gate }
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@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)6467c478bd9Sstevel@tonic-gate add_new_property(scf_handle_t *h, scf_transaction_t *tx, const char *name,
6477c478bd9Sstevel@tonic-gate     scf_type_t ty, const void *val)
6487c478bd9Sstevel@tonic-gate {
6497c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *e;
6507c478bd9Sstevel@tonic-gate 	scf_value_t *v;
6517c478bd9Sstevel@tonic-gate 	const char *func;
6527c478bd9Sstevel@tonic-gate 	const struct timeval *t;
6537c478bd9Sstevel@tonic-gate 	int r;
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	if ((e = scf_entry_create(h)) == NULL) {
6567c478bd9Sstevel@tonic-gate 		func = "scf_entry_create()";
6577c478bd9Sstevel@tonic-gate 		goto err;
6587c478bd9Sstevel@tonic-gate 	}
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	if ((v = scf_value_create(h)) == NULL) {
6617c478bd9Sstevel@tonic-gate 		func = "scf_value_create()";
6627c478bd9Sstevel@tonic-gate 		goto err;
6637c478bd9Sstevel@tonic-gate 	}
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	r = scf_transaction_property_new(tx, e, name, ty);
6667c478bd9Sstevel@tonic-gate 	if (r != 0) {
6677c478bd9Sstevel@tonic-gate 		func = "scf_transaction_property_new()";
6687c478bd9Sstevel@tonic-gate 		goto err;
6697c478bd9Sstevel@tonic-gate 	}
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	switch (ty) {
6727c478bd9Sstevel@tonic-gate 	case SCF_TYPE_COUNT:
6730b5c9250Shg 		scf_value_set_count(v, (uint64_t)(uintptr_t)val);
6747c478bd9Sstevel@tonic-gate 		break;
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	case SCF_TYPE_TIME:
6777c478bd9Sstevel@tonic-gate 		t = val;
6787c478bd9Sstevel@tonic-gate 		r = scf_value_set_time(v, t->tv_sec, 1000 * t->tv_usec);
6797c478bd9Sstevel@tonic-gate 		assert(r == 0);
6807c478bd9Sstevel@tonic-gate 		break;
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	case SCF_TYPE_ASTRING:
6837c478bd9Sstevel@tonic-gate 		r = scf_value_set_astring(v, val);
6847c478bd9Sstevel@tonic-gate 		assert(r == 0);
6857c478bd9Sstevel@tonic-gate 		break;
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	default:
6887c478bd9Sstevel@tonic-gate 		assert(0);
6897c478bd9Sstevel@tonic-gate 		abort();
6907c478bd9Sstevel@tonic-gate 	}
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 	if (scf_entry_add_value(e, v) == 0)
6937c478bd9Sstevel@tonic-gate 		return (0);
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	func = "scf_entry_add_value()";
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate err:
6987c478bd9Sstevel@tonic-gate 	uu_warn(gettext("%s failed (%s).\n"), func, scf_strerror(scf_error()));
6997c478bd9Sstevel@tonic-gate 	return (-1);
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate static void
set_legacy_service(scf_propertygroup_t * pg,const char * script,ino_t inode)703d28831b8SVladimir Marek set_legacy_service(scf_propertygroup_t *pg, const char *script, ino_t inode)
7047c478bd9Sstevel@tonic-gate {
7057c478bd9Sstevel@tonic-gate 	scf_handle_t *h;
7067c478bd9Sstevel@tonic-gate 	const char *func;
7077c478bd9Sstevel@tonic-gate 	char *suffix;
7087c478bd9Sstevel@tonic-gate 	scf_transaction_t *tx;
7097c478bd9Sstevel@tonic-gate 	struct timeval tstamp;
7107c478bd9Sstevel@tonic-gate 	ctid_t ctid;
7117c478bd9Sstevel@tonic-gate 	char *svc_name = NULL;
7127c478bd9Sstevel@tonic-gate 	int ret;
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 	h = scf_pg_handle(pg);
7157c478bd9Sstevel@tonic-gate 	if (h == NULL) {
7167c478bd9Sstevel@tonic-gate 		func = "scf_pg_handle()";
7177c478bd9Sstevel@tonic-gate 		goto scferr;
7187c478bd9Sstevel@tonic-gate 	}
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	ret = gettimeofday(&tstamp, NULL);
7217c478bd9Sstevel@tonic-gate 	assert(ret == 0);
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 	if (errno = contract_latest(&ctid)) {
7247c478bd9Sstevel@tonic-gate 		uu_warn(gettext("Could not get contract"));
7257c478bd9Sstevel@tonic-gate 		goto err;
7267c478bd9Sstevel@tonic-gate 	}
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 	tx = scf_transaction_create(h);
7297c478bd9Sstevel@tonic-gate 	if (tx == NULL) {
7307c478bd9Sstevel@tonic-gate 		func = "scf_transaction_create()";
7317c478bd9Sstevel@tonic-gate 		goto scferr;
7327c478bd9Sstevel@tonic-gate 	}
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 	if (scf_transaction_start(tx, pg) != 0) {
7357c478bd9Sstevel@tonic-gate 		func = "scf_transaction_start()";
7367c478bd9Sstevel@tonic-gate 		goto scferr;
7377c478bd9Sstevel@tonic-gate 	}
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 	/*
7407c478bd9Sstevel@tonic-gate 	 * We'd like to use the prettier svc_name, but if path_to_svc_name()
7417c478bd9Sstevel@tonic-gate 	 * fails, we can use the script name anyway.
7427c478bd9Sstevel@tonic-gate 	 */
7437c478bd9Sstevel@tonic-gate 	svc_name = path_to_svc_name(script);
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 	if (add_new_property(h, tx, SCF_LEGACY_PROPERTY_NAME, SCF_TYPE_ASTRING,
7467c478bd9Sstevel@tonic-gate 	    (void *)(svc_name ? svc_name : script)) != 0)
7477c478bd9Sstevel@tonic-gate 		goto err;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	if (add_new_property(h, tx, SCF_PROPERTY_STATE_TIMESTAMP,
7507c478bd9Sstevel@tonic-gate 	    SCF_TYPE_TIME, &tstamp) != 0)
7517c478bd9Sstevel@tonic-gate 		goto err;
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 	if (add_new_property(h, tx, SCF_LEGACY_PROPERTY_INODE,
754d28831b8SVladimir Marek 	    SCF_TYPE_COUNT, (void *)inode) != 0)
7557c478bd9Sstevel@tonic-gate 		goto err;
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	if ((suffix = script_suffix(script)) != NULL) {
7587c478bd9Sstevel@tonic-gate 		if (add_new_property(h, tx, SCF_LEGACY_PROPERTY_SUFFIX,
7597c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, (void *)suffix) != 0)
7607c478bd9Sstevel@tonic-gate 			goto err;
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 		free(suffix);
7637c478bd9Sstevel@tonic-gate 	}
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	if (add_new_property(h, tx, SCF_PROPERTY_CONTRACT, SCF_TYPE_COUNT,
7667c478bd9Sstevel@tonic-gate 	    (void *)ctid) != 0)
7677c478bd9Sstevel@tonic-gate 		goto err;
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	for (;;) {
7707c478bd9Sstevel@tonic-gate 		switch (scf_transaction_commit(tx)) {
7717c478bd9Sstevel@tonic-gate 		case 1:
7727c478bd9Sstevel@tonic-gate 			free(svc_name);
7737c478bd9Sstevel@tonic-gate 			return;
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 		case 0:
7767c478bd9Sstevel@tonic-gate 			if (scf_pg_update(pg) == -1) {
7777c478bd9Sstevel@tonic-gate 				func = "scf_pg_update()";
7787c478bd9Sstevel@tonic-gate 				goto scferr;
7797c478bd9Sstevel@tonic-gate 			}
7807c478bd9Sstevel@tonic-gate 			continue;
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 		case -1:
7837c478bd9Sstevel@tonic-gate 			func = "scf_transaction_commit()";
7847c478bd9Sstevel@tonic-gate 			goto scferr;
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 		default:
7877c478bd9Sstevel@tonic-gate 			assert(0);
7887c478bd9Sstevel@tonic-gate 			abort();
7897c478bd9Sstevel@tonic-gate 		}
7907c478bd9Sstevel@tonic-gate 	}
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate scferr:
7937c478bd9Sstevel@tonic-gate 	uu_warn(gettext("%s failed (%s).\n"), func, scf_strerror(scf_error()));
7947c478bd9Sstevel@tonic-gate err:
7957c478bd9Sstevel@tonic-gate 	uu_die(gettext("Could not commit property values to repository.\n"));
7967c478bd9Sstevel@tonic-gate }
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[],char * envp[])7997c478bd9Sstevel@tonic-gate main(int argc, char *argv[], char *envp[])
8007c478bd9Sstevel@tonic-gate {
8017c478bd9Sstevel@tonic-gate 	const char *restarter, *script, *action;
8027c478bd9Sstevel@tonic-gate 	boolean_t source = 0;
8037c478bd9Sstevel@tonic-gate 	int o;
8047c478bd9Sstevel@tonic-gate 	boolean_t start_flag;
8057c478bd9Sstevel@tonic-gate 	char **newenv;
8067c478bd9Sstevel@tonic-gate 	pid_t pid;
8077c478bd9Sstevel@tonic-gate 	int pipefds[2];
8087c478bd9Sstevel@tonic-gate 	char c;
8097c478bd9Sstevel@tonic-gate 	int exitstatus;
810d28831b8SVladimir Marek 	struct stat st;
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
8137c478bd9Sstevel@tonic-gate 	boolean_t pg_ok;
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 	(void) uu_setpname(argv[0]);
8167c478bd9Sstevel@tonic-gate 	uu_alt_exit(UU_PROFILE_LAUNCHER);
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 	/* Make sure we were run by svc.startd. */
8197c478bd9Sstevel@tonic-gate 	if ((restarter = getenv("SMF_RESTARTER")) == NULL ||
8207c478bd9Sstevel@tonic-gate 	    strcmp(restarter, SCF_SERVICE_STARTD) != 0)
821*bbf21555SRichard Lowe 		uu_die(gettext("invocation outside smf(7) inappropriate\n"));
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 	while ((o = getopt(argc, argv, "s")) != -1) {
8247c478bd9Sstevel@tonic-gate 		switch (o) {
8257c478bd9Sstevel@tonic-gate 		case 's':
8267c478bd9Sstevel@tonic-gate 			source = 1;
8277c478bd9Sstevel@tonic-gate 			break;
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 		default:
8307c478bd9Sstevel@tonic-gate 			usage();
8317c478bd9Sstevel@tonic-gate 		}
8327c478bd9Sstevel@tonic-gate 	}
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 	if (argc - optind != 2)
8357c478bd9Sstevel@tonic-gate 		usage();
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 	script = argv[optind];
8387c478bd9Sstevel@tonic-gate 	action = argv[optind + 1];
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 	if (strcmp(action, "start") == 0)
8417c478bd9Sstevel@tonic-gate 		start_flag = 1;
8427c478bd9Sstevel@tonic-gate 	else if (strcmp(action, "stop") == 0)
8437c478bd9Sstevel@tonic-gate 		start_flag = 0;
8447c478bd9Sstevel@tonic-gate 	else
8457c478bd9Sstevel@tonic-gate 		usage();
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	/*
8487c478bd9Sstevel@tonic-gate 	 * Look for the pg & exit if appropriate.  Also, if we're starting,
8497c478bd9Sstevel@tonic-gate 	 * add the pg now so we can exit before launching the script if we
8507c478bd9Sstevel@tonic-gate 	 * have insufficient repository privilege.
8517c478bd9Sstevel@tonic-gate 	 *
8527c478bd9Sstevel@tonic-gate 	 * If any other problem occurs, we carry on anyway.
8537c478bd9Sstevel@tonic-gate 	 */
8547c478bd9Sstevel@tonic-gate 	pg = get_script_pg(script, start_flag, &pg_ok);
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 	/* Clean the environment.  Now so we can fail early. */
8577c478bd9Sstevel@tonic-gate 	if (!source)
8587c478bd9Sstevel@tonic-gate 		newenv = approved_env(envp);
8597c478bd9Sstevel@tonic-gate 	else
8607c478bd9Sstevel@tonic-gate 		newenv = env_without_smf(envp);
8617c478bd9Sstevel@tonic-gate 	if (newenv == NULL)
8627c478bd9Sstevel@tonic-gate 		uu_die(gettext(
8637c478bd9Sstevel@tonic-gate 		    "Could not create new environment: out of memory.\n"));
8647c478bd9Sstevel@tonic-gate 
8657b209c2cSacruz 	if (prepare_contract(script, action) == -1) {
8667c478bd9Sstevel@tonic-gate 		if (start_flag && pg != NULL)
8677c478bd9Sstevel@tonic-gate 			cleanup_pg(pg);
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 		exit(UU_EXIT_FATAL);
8707c478bd9Sstevel@tonic-gate 	}
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 	/* pipe to communicate exec success or failure */
8737c478bd9Sstevel@tonic-gate 	if (pipe(pipefds) != 0) {
8747c478bd9Sstevel@tonic-gate 		uu_warn(gettext("Could not create pipe"));
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 		if (start_flag && pg != NULL)
8777c478bd9Sstevel@tonic-gate 			cleanup_pg(pg);
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 		exit(UU_EXIT_FATAL);
8807c478bd9Sstevel@tonic-gate 	}
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	if (!pg_ok)
8837c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Executing legacy init script \"%s\" "
8847c478bd9Sstevel@tonic-gate 		    "despite previous errors.\n"), script);
8857c478bd9Sstevel@tonic-gate 	else
8867c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Executing legacy init script \"%s\".\n"),
8877c478bd9Sstevel@tonic-gate 		    script);
8887c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
8897c478bd9Sstevel@tonic-gate 
890d28831b8SVladimir Marek 	if (stat(script, &st) != 0) {
891d28831b8SVladimir Marek 		uu_warn(gettext("Couldn't stat %s (%s).\n"), script,
892d28831b8SVladimir Marek 		    strerror(errno));
893d28831b8SVladimir Marek 		st.st_ino = (ino_t)0;
894d28831b8SVladimir Marek 	}
895d28831b8SVladimir Marek 
8967c478bd9Sstevel@tonic-gate 	pid = fork();
8977c478bd9Sstevel@tonic-gate 	if (pid < 0) {
8987c478bd9Sstevel@tonic-gate 		uu_warn(gettext("Could not fork"));
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 		if (start_flag && pg != NULL)
9017c478bd9Sstevel@tonic-gate 			cleanup_pg(pg);
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 		exit(UU_EXIT_FATAL);
9047c478bd9Sstevel@tonic-gate 	}
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	if (pid == 0) {
9077c478bd9Sstevel@tonic-gate 		/* child */
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 		const char *arg1, *arg2, *arg3;
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 		(void) close(pipefds[0]);
9127c478bd9Sstevel@tonic-gate 		(void) fcntl(pipefds[1], F_SETFD, FD_CLOEXEC);
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 		if (!source) {
9157c478bd9Sstevel@tonic-gate 			arg1 = "/bin/sh";
9167c478bd9Sstevel@tonic-gate 			arg2 = script;
9177c478bd9Sstevel@tonic-gate 			arg3 = action;
9187c478bd9Sstevel@tonic-gate 		} else {
9197c478bd9Sstevel@tonic-gate 			arg1 = "/bin/sh";
9207c478bd9Sstevel@tonic-gate 			arg2 = "-c";
9217c478bd9Sstevel@tonic-gate 			arg3 = script;
9227c478bd9Sstevel@tonic-gate 		}
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 		(void) execle(arg1, arg1, arg2, arg3, NULL, newenv);
9257c478bd9Sstevel@tonic-gate 
9267c478bd9Sstevel@tonic-gate 		uu_warn(gettext("Could not exec \"%s %s %s\""), arg1,
9277c478bd9Sstevel@tonic-gate 		    arg2, arg3);
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 		/* Notify parent of the failure. */
9317c478bd9Sstevel@tonic-gate 		while (write(pipefds[1], &c, 1) != 1) {
9327c478bd9Sstevel@tonic-gate 			switch (errno) {
9337c478bd9Sstevel@tonic-gate 			case EAGAIN:
9347c478bd9Sstevel@tonic-gate 				(void) sleep(1);
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate 				/* FALLTHROUGH */
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 			case EINTR:
9397c478bd9Sstevel@tonic-gate 				continue;
9407c478bd9Sstevel@tonic-gate 			}
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Could not inform parent of error"));
9437c478bd9Sstevel@tonic-gate 			break;
9447c478bd9Sstevel@tonic-gate 		}
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 		exit(UU_EXIT_FATAL);
9477c478bd9Sstevel@tonic-gate 	}
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 	(void) close(pipefds[1]);
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 	if (read(pipefds[0], &c, sizeof (c)) > 0) {
9527c478bd9Sstevel@tonic-gate 		if (!start_flag)
9537c478bd9Sstevel@tonic-gate 			uu_die(gettext("exec() failed; leaving properties.\n"));
9547c478bd9Sstevel@tonic-gate 		else {
9557c478bd9Sstevel@tonic-gate 			uu_warn(gettext("exec() failed.\n"));
9567c478bd9Sstevel@tonic-gate 			if (pg != NULL)
9577c478bd9Sstevel@tonic-gate 				cleanup_pg(pg);
9587c478bd9Sstevel@tonic-gate 			exit(UU_EXIT_FATAL);
9597c478bd9Sstevel@tonic-gate 		}
9607c478bd9Sstevel@tonic-gate 	}
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 	while (waitpid(pid, &exitstatus, 0) == -1) {
9637c478bd9Sstevel@tonic-gate 		assert(errno == EINTR);
9647c478bd9Sstevel@tonic-gate 	}
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	if (WIFSIGNALED(exitstatus)) {
9677c478bd9Sstevel@tonic-gate 		char buf[SIG2STR_MAX];
9687c478bd9Sstevel@tonic-gate 		(void) sig2str(WTERMSIG(exitstatus), buf);
9697c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Legacy init script \"%s\" failed due "
9707c478bd9Sstevel@tonic-gate 		    "to signal %s.\n"), script, buf);
9717c478bd9Sstevel@tonic-gate 	} else {
9727c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Legacy init script \"%s\" exited with "
9737c478bd9Sstevel@tonic-gate 		    "return code %d.\n"), script, WEXITSTATUS(exitstatus));
9747c478bd9Sstevel@tonic-gate 	}
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 	if (pg != NULL) {
9777c478bd9Sstevel@tonic-gate 		if (start_flag)
978d28831b8SVladimir Marek 			set_legacy_service(pg, script, st.st_ino);
9797c478bd9Sstevel@tonic-gate 		else
9807c478bd9Sstevel@tonic-gate 			cleanup_pg(pg);
9817c478bd9Sstevel@tonic-gate 		scf_pg_destroy(pg);
9827c478bd9Sstevel@tonic-gate 	}
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	return (UU_EXIT_OK);
9857c478bd9Sstevel@tonic-gate }
986