xref: /titanic_52/usr/src/cmd/svc/svccfg/svccfg_engine.c (revision 8c10095f78d4dd1f9617a2223a43e5c2dc3c0e8d)
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
51f1b4534Scasper  * Common Development and Distribution License (the "License").
61f1b4534Scasper  * 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  */
213eae19d9Swesolows 
227c478bd9Sstevel@tonic-gate /*
23adfc3118STruong Nguyen  *  Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * svccfg(1) interpreter and command execution engine.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <sys/mman.h>
327c478bd9Sstevel@tonic-gate #include <sys/stat.h>
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <assert.h>
357c478bd9Sstevel@tonic-gate #include <errno.h>
369444c26fSTom Whitten #include <fcntl.h>
377c478bd9Sstevel@tonic-gate #include <libintl.h>
387c478bd9Sstevel@tonic-gate #include <libtecla.h>
397c478bd9Sstevel@tonic-gate #include <md5.h>
407c478bd9Sstevel@tonic-gate #include <string.h>
417c478bd9Sstevel@tonic-gate #include <stdlib.h>
427c478bd9Sstevel@tonic-gate #include <unistd.h>
437c478bd9Sstevel@tonic-gate 
449444c26fSTom Whitten #include "manifest_find.h"
457c478bd9Sstevel@tonic-gate #include "manifest_hash.h"
467c478bd9Sstevel@tonic-gate #include "svccfg.h"
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate #define	MS_PER_US		1000
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate engine_state_t *est;
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /*
537c478bd9Sstevel@tonic-gate  * Replacement lex(1) character retrieval routines.
547c478bd9Sstevel@tonic-gate  */
557c478bd9Sstevel@tonic-gate int
567c478bd9Sstevel@tonic-gate engine_cmd_getc(engine_state_t *E)
577c478bd9Sstevel@tonic-gate {
587c478bd9Sstevel@tonic-gate 	if (E->sc_cmd_file != NULL)
597c478bd9Sstevel@tonic-gate 		return (getc(E->sc_cmd_file));
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate 	if (E->sc_cmd_flags & SC_CMD_EOF)
627c478bd9Sstevel@tonic-gate 		return (EOF);
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate 	if (E->sc_cmd_bufoff < E->sc_cmd_bufsz)
657c478bd9Sstevel@tonic-gate 		return (*(E->sc_cmd_buf + E->sc_cmd_bufoff++));
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate 	if (!(E->sc_cmd_flags & SC_CMD_IACTIVE)) {
687c478bd9Sstevel@tonic-gate 		E->sc_cmd_flags |= SC_CMD_EOF;
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate 		return (EOF);
717c478bd9Sstevel@tonic-gate 	} else {
727c478bd9Sstevel@tonic-gate #ifdef NATIVE_BUILD
737c478bd9Sstevel@tonic-gate 		return (EOF);
747c478bd9Sstevel@tonic-gate #else
757c478bd9Sstevel@tonic-gate 		extern int parens;
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate 		if (parens <= 0) {
787c478bd9Sstevel@tonic-gate 			E->sc_cmd_flags |= SC_CMD_EOF;
797c478bd9Sstevel@tonic-gate 			return (EOF);
807c478bd9Sstevel@tonic-gate 		}
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 		for (;;) {
837c478bd9Sstevel@tonic-gate 			E->sc_cmd_buf = gl_get_line(E->sc_gl, "> ", NULL, -1);
847c478bd9Sstevel@tonic-gate 			if (E->sc_cmd_buf != NULL)
857c478bd9Sstevel@tonic-gate 				break;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 			switch (gl_return_status(E->sc_gl)) {
887c478bd9Sstevel@tonic-gate 			case GLR_SIGNAL:
897c478bd9Sstevel@tonic-gate 				gl_abandon_line(E->sc_gl);
907c478bd9Sstevel@tonic-gate 				continue;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 			case GLR_EOF:
937c478bd9Sstevel@tonic-gate 				E->sc_cmd_flags |= SC_CMD_EOF;
947c478bd9Sstevel@tonic-gate 				return (EOF);
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 			case GLR_ERROR:
977c478bd9Sstevel@tonic-gate 				uu_die(gettext("Error reading terminal: %s.\n"),
987c478bd9Sstevel@tonic-gate 				    gl_error_message(E->sc_gl, NULL, 0));
997c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 			default:
1027c478bd9Sstevel@tonic-gate #ifndef NDEBUG
1037c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s:%d: gl_get_line() "
1047c478bd9Sstevel@tonic-gate 				    "returned unexpected value %d.\n", __FILE__,
1057c478bd9Sstevel@tonic-gate 				    __LINE__, gl_return_status(E->sc_gl));
1067c478bd9Sstevel@tonic-gate #endif
1077c478bd9Sstevel@tonic-gate 				abort();
1087c478bd9Sstevel@tonic-gate 			}
1097c478bd9Sstevel@tonic-gate 		}
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 		E->sc_cmd_bufsz = strlen(E->sc_cmd_buf);
1127c478bd9Sstevel@tonic-gate 		E->sc_cmd_bufoff = 1;
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 		return (E->sc_cmd_buf[0]);
1157c478bd9Sstevel@tonic-gate #endif	/* NATIVE_BUILD */
1167c478bd9Sstevel@tonic-gate 	}
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate int
1207c478bd9Sstevel@tonic-gate engine_cmd_ungetc(engine_state_t *E, char c)
1217c478bd9Sstevel@tonic-gate {
1227c478bd9Sstevel@tonic-gate 	if (E->sc_cmd_file != NULL)
1237c478bd9Sstevel@tonic-gate 		return (ungetc(c, E->sc_cmd_file));
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	if (E->sc_cmd_buf != NULL)
1267c478bd9Sstevel@tonic-gate 		*(E->sc_cmd_buf + --E->sc_cmd_bufoff) = c;
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	return (c);
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1327c478bd9Sstevel@tonic-gate void
1337c478bd9Sstevel@tonic-gate engine_cmd_nputs(engine_state_t *E, char *c, size_t n)
1347c478bd9Sstevel@tonic-gate {
1357c478bd9Sstevel@tonic-gate 	/* our lexer shouldn't need this state */
1367c478bd9Sstevel@tonic-gate 	exit(11);
1377c478bd9Sstevel@tonic-gate }
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate int
1407c478bd9Sstevel@tonic-gate engine_exec(char *cmd)
1417c478bd9Sstevel@tonic-gate {
1427c478bd9Sstevel@tonic-gate 	est->sc_cmd_buf = cmd;
1437c478bd9Sstevel@tonic-gate 	est->sc_cmd_bufsz = strlen(cmd) + 1;
1447c478bd9Sstevel@tonic-gate 	est->sc_cmd_bufoff = 0;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	(void) yyparse();
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	return (0);
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate #ifndef NATIVE_BUILD
1527c478bd9Sstevel@tonic-gate /* ARGSUSED */
1537c478bd9Sstevel@tonic-gate static
1547c478bd9Sstevel@tonic-gate CPL_CHECK_FN(check_xml)
1557c478bd9Sstevel@tonic-gate {
1567c478bd9Sstevel@tonic-gate 	const char *ext;
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	if (strlen(pathname) < 4)
1597c478bd9Sstevel@tonic-gate 		return (0);
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	ext = pathname + strlen(pathname) - 4;
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	return (strcmp(ext, ".xml") == 0 ? 1 : 0);
1647c478bd9Sstevel@tonic-gate }
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate static const char * const whitespace = " \t";
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate static
1697c478bd9Sstevel@tonic-gate CPL_MATCH_FN(complete_single_xml_file_arg)
1707c478bd9Sstevel@tonic-gate {
1717c478bd9Sstevel@tonic-gate 	const char *arg1 = data;
1727c478bd9Sstevel@tonic-gate 	int arg1end_i, ret;
1737c478bd9Sstevel@tonic-gate 	CplFileConf *cfc;
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	arg1end_i = arg1 + strcspn(arg1, whitespace) - line;
1767c478bd9Sstevel@tonic-gate 	if (arg1end_i < word_end)
1777c478bd9Sstevel@tonic-gate 		return (0);
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	cfc = new_CplFileConf();
1807c478bd9Sstevel@tonic-gate 	if (cfc == NULL) {
1817c478bd9Sstevel@tonic-gate 		cpl_record_error(cpl, "Out of memory.");
1827c478bd9Sstevel@tonic-gate 		return (1);
1837c478bd9Sstevel@tonic-gate 	}
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	cfc_set_check_fn(cfc, check_xml, NULL);
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	ret = cpl_file_completions(cpl, cfc, line, word_end);
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	(void) del_CplFileConf(cfc);
1907c478bd9Sstevel@tonic-gate 	return (ret);
1917c478bd9Sstevel@tonic-gate }
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate static struct cmd_info {
1947c478bd9Sstevel@tonic-gate 	const char	*name;
1957c478bd9Sstevel@tonic-gate 	uint32_t	flags;
1967c478bd9Sstevel@tonic-gate 	CplMatchFn	*complete_args_f;
1977c478bd9Sstevel@tonic-gate } cmds[] = {
1987c478bd9Sstevel@tonic-gate 	{ "validate", CS_GLOBAL, complete_single_xml_file_arg },
1997c478bd9Sstevel@tonic-gate 	{ "import", CS_GLOBAL, complete_single_xml_file_arg },
2009444c26fSTom Whitten 	{ "cleanup", CS_GLOBAL, NULL},
2017c478bd9Sstevel@tonic-gate 	{ "export", CS_GLOBAL, NULL },
2027c478bd9Sstevel@tonic-gate 	{ "archive", CS_GLOBAL, NULL },
2037c478bd9Sstevel@tonic-gate 	{ "apply", CS_GLOBAL, complete_single_xml_file_arg },
2047c478bd9Sstevel@tonic-gate 	{ "extract", CS_GLOBAL, NULL },
2057c478bd9Sstevel@tonic-gate 	{ "repository", CS_GLOBAL, NULL },
2067c478bd9Sstevel@tonic-gate 	{ "inventory", CS_GLOBAL, complete_single_xml_file_arg },
2077c478bd9Sstevel@tonic-gate 	{ "set", CS_GLOBAL, NULL },
2087c478bd9Sstevel@tonic-gate 	{ "end", CS_GLOBAL, NULL },
2097c478bd9Sstevel@tonic-gate 	{ "exit", CS_GLOBAL, NULL },
2107c478bd9Sstevel@tonic-gate 	{ "quit", CS_GLOBAL, NULL },
2117c478bd9Sstevel@tonic-gate 	{ "help", CS_GLOBAL, NULL },
2127c478bd9Sstevel@tonic-gate 	{ "delete", CS_GLOBAL, NULL },
2137c478bd9Sstevel@tonic-gate 	{ "select", CS_GLOBAL, complete_select },
2147c478bd9Sstevel@tonic-gate 	{ "unselect", CS_SVC | CS_INST | CS_SNAP, NULL },
2157c478bd9Sstevel@tonic-gate 	{ "list", CS_SCOPE | CS_SVC | CS_SNAP, NULL },
2167c478bd9Sstevel@tonic-gate 	{ "add", CS_SCOPE | CS_SVC, NULL },
2177c478bd9Sstevel@tonic-gate 	{ "listpg", CS_SVC | CS_INST | CS_SNAP, NULL },
2187c478bd9Sstevel@tonic-gate 	{ "addpg", CS_SVC | CS_INST, NULL },
2197c478bd9Sstevel@tonic-gate 	{ "delpg", CS_SVC | CS_INST, NULL },
22070cbfe41SPhilippe Jung 	{ "delhash", CS_GLOBAL, complete_single_xml_file_arg },
2217c478bd9Sstevel@tonic-gate 	{ "listprop", CS_SVC | CS_INST | CS_SNAP, NULL },
2227c478bd9Sstevel@tonic-gate 	{ "setprop", CS_SVC | CS_INST, NULL },
2237c478bd9Sstevel@tonic-gate 	{ "delprop", CS_SVC | CS_INST, NULL },
2247c478bd9Sstevel@tonic-gate 	{ "editprop", CS_SVC | CS_INST, NULL },
2251f6eb021SLiane Praza 	{ "describe", CS_SVC | CS_INST | CS_SNAP, NULL },
2267c478bd9Sstevel@tonic-gate 	{ "listsnap", CS_INST | CS_SNAP, NULL },
2277c478bd9Sstevel@tonic-gate 	{ "selectsnap", CS_INST | CS_SNAP, NULL },
2287c478bd9Sstevel@tonic-gate 	{ "revert", CS_INST | CS_SNAP, NULL },
229347a77f2Samaguire 	{ "refresh", CS_INST, NULL },
2307c478bd9Sstevel@tonic-gate 	{ NULL }
2317c478bd9Sstevel@tonic-gate };
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate int
2347c478bd9Sstevel@tonic-gate add_cmd_matches(WordCompletion *cpl, const char *line, int word_end,
2357c478bd9Sstevel@tonic-gate     uint32_t scope)
2367c478bd9Sstevel@tonic-gate {
2377c478bd9Sstevel@tonic-gate 	int word_start, err;
2387c478bd9Sstevel@tonic-gate 	size_t len;
2397c478bd9Sstevel@tonic-gate 	const char *bol;
2407c478bd9Sstevel@tonic-gate 	struct cmd_info *cip;
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	word_start = strspn(line, whitespace);
2437c478bd9Sstevel@tonic-gate 	len = word_end - word_start;
2447c478bd9Sstevel@tonic-gate 	bol = line + word_end - len;
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	for (cip = cmds; cip->name != NULL; ++cip) {
2477c478bd9Sstevel@tonic-gate 		if ((cip->flags & scope) == 0)
2487c478bd9Sstevel@tonic-gate 			continue;
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 		if (strncmp(cip->name, bol, len) == 0) {
2517c478bd9Sstevel@tonic-gate 			err = cpl_add_completion(cpl, line, word_start,
2527c478bd9Sstevel@tonic-gate 			    word_end, cip->name + len, "", " ");
2537c478bd9Sstevel@tonic-gate 			if (err != 0)
2547c478bd9Sstevel@tonic-gate 				return (err);
2557c478bd9Sstevel@tonic-gate 		}
2567c478bd9Sstevel@tonic-gate 	}
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	return (0);
2597c478bd9Sstevel@tonic-gate }
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate /*
2627c478bd9Sstevel@tonic-gate  * Suggest completions.  We must first determine if the cursor is in command
2637c478bd9Sstevel@tonic-gate  * position or in argument position.  If the former, complete_command() finds
2647c478bd9Sstevel@tonic-gate  * matching commands.  If the latter, we tail-call the command-specific
2657c478bd9Sstevel@tonic-gate  * argument-completion routine in the cmds table.
2667c478bd9Sstevel@tonic-gate  */
2677c478bd9Sstevel@tonic-gate /* ARGSUSED */
2687c478bd9Sstevel@tonic-gate static
2697c478bd9Sstevel@tonic-gate CPL_MATCH_FN(complete)
2707c478bd9Sstevel@tonic-gate {
2717c478bd9Sstevel@tonic-gate 	const char *arg0, *arg1;
2727c478bd9Sstevel@tonic-gate 	size_t arg0len;
2737c478bd9Sstevel@tonic-gate 	struct cmd_info *cip;
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	arg0 = line + strspn(line, whitespace);
2767c478bd9Sstevel@tonic-gate 	arg0len = strcspn(arg0, whitespace);
2777c478bd9Sstevel@tonic-gate 	if ((arg0 + arg0len) - line >= word_end ||
2787c478bd9Sstevel@tonic-gate 	    (arg0[arg0len] != ' ' && arg0[arg0len] != '\t'))
2797c478bd9Sstevel@tonic-gate 		return (complete_command(cpl, (void *)arg0, line, word_end));
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	arg1 = arg0 + arg0len;
2827c478bd9Sstevel@tonic-gate 	arg1 += strspn(arg1, whitespace);
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	for (cip = cmds; cip->name != NULL; ++cip) {
2857c478bd9Sstevel@tonic-gate 		if (strlen(cip->name) != arg0len)
2867c478bd9Sstevel@tonic-gate 			continue;
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 		if (strncmp(cip->name, arg0, arg0len) != 0)
2897c478bd9Sstevel@tonic-gate 			continue;
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 		if (cip->complete_args_f == NULL)
2927c478bd9Sstevel@tonic-gate 			break;
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 		return (cip->complete_args_f(cpl, (void *)arg1, line,
2957c478bd9Sstevel@tonic-gate 		    word_end));
2967c478bd9Sstevel@tonic-gate 	}
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	return (0);
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate #endif	/* NATIVE_BUILD */
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate int
3037c478bd9Sstevel@tonic-gate engine_interp()
3047c478bd9Sstevel@tonic-gate {
3057c478bd9Sstevel@tonic-gate #ifdef NATIVE_BUILD
3067c478bd9Sstevel@tonic-gate 	uu_die("native build does not support interactive mode.");
3077c478bd9Sstevel@tonic-gate #else
3087c478bd9Sstevel@tonic-gate 	char *selfmri;
3097c478bd9Sstevel@tonic-gate 	size_t sfsz;
3107c478bd9Sstevel@tonic-gate 	int r;
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	extern int parens;
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	(void) sigset(SIGINT, SIG_IGN);
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	est->sc_gl = new_GetLine(512, 8000);
3177c478bd9Sstevel@tonic-gate 	if (est->sc_gl == NULL)
3187c478bd9Sstevel@tonic-gate 		uu_die(gettext("Out of memory.\n"));
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	/* The longest string is "[snapname]fmri[:instname]> ". */
3217c478bd9Sstevel@tonic-gate 	sfsz = 1 + max_scf_name_len + 1 + max_scf_fmri_len + 2 +
3227c478bd9Sstevel@tonic-gate 	    max_scf_name_len + 1 + 2 + 1;
3237c478bd9Sstevel@tonic-gate 	selfmri = safe_malloc(sfsz);
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	r = gl_customize_completion(est->sc_gl, NULL, complete);
3267c478bd9Sstevel@tonic-gate 	assert(r == 0);
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	for (;;) {
3297c478bd9Sstevel@tonic-gate 		lscf_get_selection_str(selfmri, sfsz - 2);
3307c478bd9Sstevel@tonic-gate 		(void) strcat(selfmri, "> ");
3317c478bd9Sstevel@tonic-gate 		est->sc_cmd_buf = gl_get_line(est->sc_gl, selfmri, NULL, -1);
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 		if (est->sc_cmd_buf == NULL) {
3347c478bd9Sstevel@tonic-gate 			switch (gl_return_status(est->sc_gl)) {
3357c478bd9Sstevel@tonic-gate 			case GLR_SIGNAL:
3367c478bd9Sstevel@tonic-gate 				gl_abandon_line(est->sc_gl);
3377c478bd9Sstevel@tonic-gate 				continue;
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 			case GLR_EOF:
3407c478bd9Sstevel@tonic-gate 				break;
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 			case GLR_ERROR:
3437c478bd9Sstevel@tonic-gate 				uu_die(gettext("Error reading terminal: %s.\n"),
3447c478bd9Sstevel@tonic-gate 				    gl_error_message(est->sc_gl, NULL, 0));
3457c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 			default:
3487c478bd9Sstevel@tonic-gate #ifndef NDEBUG
3497c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s:%d: gl_get_line() "
3507c478bd9Sstevel@tonic-gate 				    "returned unexpected value %d.\n", __FILE__,
3517c478bd9Sstevel@tonic-gate 				    __LINE__, gl_return_status(est->sc_gl));
3527c478bd9Sstevel@tonic-gate #endif
3537c478bd9Sstevel@tonic-gate 				abort();
3547c478bd9Sstevel@tonic-gate 			}
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 			break;
3577c478bd9Sstevel@tonic-gate 		}
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 		parens = 0;
3607c478bd9Sstevel@tonic-gate 		est->sc_cmd_bufsz = strlen(est->sc_cmd_buf);
3617c478bd9Sstevel@tonic-gate 		est->sc_cmd_bufoff = 0;
3627c478bd9Sstevel@tonic-gate 		est->sc_cmd_flags = SC_CMD_IACTIVE;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 		(void) yyparse();
3657c478bd9Sstevel@tonic-gate 	}
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	free(selfmri);
3687c478bd9Sstevel@tonic-gate 	est->sc_gl = del_GetLine(est->sc_gl);	/* returns NULL */
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate #endif	/* NATIVE_BUILD */
3717c478bd9Sstevel@tonic-gate 	return (0);
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate int
3757c478bd9Sstevel@tonic-gate engine_source(const char *name, boolean_t dont_exit)
3767c478bd9Sstevel@tonic-gate {
3777c478bd9Sstevel@tonic-gate 	engine_state_t *old = est;
3787c478bd9Sstevel@tonic-gate 	struct stat st;
3797c478bd9Sstevel@tonic-gate 	int ret;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	est = uu_zalloc(sizeof (engine_state_t));
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	/* first, copy the stuff set up in engine_init */
3847c478bd9Sstevel@tonic-gate 	est->sc_repo_pid = old->sc_repo_pid;
3857c478bd9Sstevel@tonic-gate 	if (old->sc_repo_filename != NULL)
3867c478bd9Sstevel@tonic-gate 		est->sc_repo_filename = safe_strdup(old->sc_repo_filename);
3877c478bd9Sstevel@tonic-gate 	if (old->sc_repo_doordir != NULL)
3887c478bd9Sstevel@tonic-gate 		est->sc_repo_doordir = safe_strdup(old->sc_repo_doordir);
3897c478bd9Sstevel@tonic-gate 	if (old->sc_repo_doorname != NULL)
3907c478bd9Sstevel@tonic-gate 		est->sc_repo_doorname = safe_strdup(old->sc_repo_doorname);
3917c478bd9Sstevel@tonic-gate 	if (old->sc_repo_server != NULL)
3927c478bd9Sstevel@tonic-gate 		est->sc_repo_server = safe_strdup(old->sc_repo_server);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	/* set up the new guy */
3957c478bd9Sstevel@tonic-gate 	est->sc_cmd_lineno = 1;
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	if (dont_exit)
3987c478bd9Sstevel@tonic-gate 		est->sc_cmd_flags |= SC_CMD_DONT_EXIT;
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	if (strcmp(name, "-") == 0) {
4017c478bd9Sstevel@tonic-gate 		est->sc_cmd_file = stdin;
4027c478bd9Sstevel@tonic-gate 		est->sc_cmd_filename = "<stdin>";
4037c478bd9Sstevel@tonic-gate 	} else {
4047c478bd9Sstevel@tonic-gate 		errno = 0;
4057c478bd9Sstevel@tonic-gate 		est->sc_cmd_filename = name;
4067c478bd9Sstevel@tonic-gate 		est->sc_cmd_file = fopen(name, "r");
4077c478bd9Sstevel@tonic-gate 		if (est->sc_cmd_file == NULL) {
4087c478bd9Sstevel@tonic-gate 			if (errno == 0)
4097c478bd9Sstevel@tonic-gate 				semerr(gettext("No free stdio streams.\n"));
4107c478bd9Sstevel@tonic-gate 			else
4117c478bd9Sstevel@tonic-gate 				semerr(gettext("Could not open %s"), name);
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 			ret = -1;
4147c478bd9Sstevel@tonic-gate 			goto fail;
4157c478bd9Sstevel@tonic-gate 		}
4167c478bd9Sstevel@tonic-gate 
4173eae19d9Swesolows 		do {
4187c478bd9Sstevel@tonic-gate 			ret = fstat(fileno(est->sc_cmd_file), &st);
4193eae19d9Swesolows 		} while (ret != 0 && errno == EINTR);
4207c478bd9Sstevel@tonic-gate 		if (ret != 0) {
4217c478bd9Sstevel@tonic-gate 			(void) fclose(est->sc_cmd_file);
4227c478bd9Sstevel@tonic-gate 			est->sc_cmd_file = NULL;	/* for semerr() */
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 			semerr(gettext("Could not stat %s"), name);
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 			ret = -1;
4277c478bd9Sstevel@tonic-gate 			goto fail;
4287c478bd9Sstevel@tonic-gate 		}
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 		if (!S_ISREG(st.st_mode)) {
4317c478bd9Sstevel@tonic-gate 			(void) fclose(est->sc_cmd_file);
4327c478bd9Sstevel@tonic-gate 			est->sc_cmd_file = NULL;	/* for semerr() */
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 			semerr(gettext("%s is not a regular file.\n"), name);
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 			ret = -1;
4377c478bd9Sstevel@tonic-gate 			goto fail;
4387c478bd9Sstevel@tonic-gate 		}
4397c478bd9Sstevel@tonic-gate 	}
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	(void) yyparse();
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	if (est->sc_cmd_file != stdin)
4447c478bd9Sstevel@tonic-gate 		(void) fclose(est->sc_cmd_file);
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	ret = 0;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate fail:
4497c478bd9Sstevel@tonic-gate 	if (est->sc_repo_pid != old->sc_repo_pid)
4507c478bd9Sstevel@tonic-gate 		lscf_cleanup();		/* clean up any new repository */
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	if (est->sc_repo_filename != NULL)
4537c478bd9Sstevel@tonic-gate 		free((void *)est->sc_repo_filename);
4547c478bd9Sstevel@tonic-gate 	if (est->sc_repo_doordir != NULL)
4557c478bd9Sstevel@tonic-gate 		free((void *)est->sc_repo_doordir);
4567c478bd9Sstevel@tonic-gate 	if (est->sc_repo_doorname != NULL)
4577c478bd9Sstevel@tonic-gate 		free((void *)est->sc_repo_doorname);
4587c478bd9Sstevel@tonic-gate 	if (est->sc_repo_server != NULL)
4597c478bd9Sstevel@tonic-gate 		free((void *)est->sc_repo_server);
4607c478bd9Sstevel@tonic-gate 	free(est);
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	est = old;
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	return (ret);
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate /*
4687c478bd9Sstevel@tonic-gate  * Initialize svccfg state.  We recognize four environment variables:
4697c478bd9Sstevel@tonic-gate  *
4707c478bd9Sstevel@tonic-gate  * SVCCFG_REPOSITORY	Create a private instance of svc.configd(1M) to answer
4717c478bd9Sstevel@tonic-gate  *			requests for the specified repository file.
4727c478bd9Sstevel@tonic-gate  * SVCCFG_DOOR_PATH	Directory for door creation.
4737c478bd9Sstevel@tonic-gate  *
4747c478bd9Sstevel@tonic-gate  * SVCCFG_DOOR		Rendezvous via an alternative repository door.
4757c478bd9Sstevel@tonic-gate  *
4767c478bd9Sstevel@tonic-gate  * SVCCFG_CONFIGD_PATH	Resolvable path to alternative svc.configd(1M) binary.
4777c478bd9Sstevel@tonic-gate  */
4787c478bd9Sstevel@tonic-gate void
4797c478bd9Sstevel@tonic-gate engine_init()
4807c478bd9Sstevel@tonic-gate {
4817c478bd9Sstevel@tonic-gate 	const char *cp;
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	est = uu_zalloc(sizeof (engine_state_t));
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	est->sc_cmd_lineno = 1;
4867c478bd9Sstevel@tonic-gate 	est->sc_repo_pid = -1;
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	cp = getenv("SVCCFG_REPOSITORY");
4897c478bd9Sstevel@tonic-gate 	est->sc_repo_filename = cp ? safe_strdup(cp) : NULL;
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	cp = getenv("SVCCFG_DOOR_PATH");
4927c478bd9Sstevel@tonic-gate 	est->sc_repo_doordir = cp ? cp : "/var/run";
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	cp = getenv("SVCCFG_DOOR");
4957c478bd9Sstevel@tonic-gate 	if (cp != NULL) {
4967c478bd9Sstevel@tonic-gate 		if (est->sc_repo_filename != NULL) {
4977c478bd9Sstevel@tonic-gate 			uu_warn(gettext("SVCCFG_DOOR unused when "
4987c478bd9Sstevel@tonic-gate 			    "SVCCFG_REPOSITORY specified\n"));
4997c478bd9Sstevel@tonic-gate 		} else {
5007c478bd9Sstevel@tonic-gate 			est->sc_repo_doorname = safe_strdup(cp);
5017c478bd9Sstevel@tonic-gate 		}
5027c478bd9Sstevel@tonic-gate 	}
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	cp = getenv("SVCCFG_CONFIGD_PATH");
5057c478bd9Sstevel@tonic-gate 	est->sc_repo_server = cp ? cp : "/lib/svc/bin/svc.configd";
5069444c26fSTom Whitten 
507f329b923SSean Wilcox 	est->sc_miss_type = B_FALSE;
5089444c26fSTom Whitten 	est->sc_in_emi = 0;
5099444c26fSTom Whitten 	cp = getenv("SMF_FMRI");
5109444c26fSTom Whitten 	if ((cp != NULL) && (strcmp(cp, SCF_INSTANCE_EMI) == 0))
5119444c26fSTom Whitten 		est->sc_in_emi = 1;
5129444c26fSTom Whitten 
5139444c26fSTom Whitten 	cp = smf_get_state(SCF_INSTANCE_FS_MINIMAL);
5149444c26fSTom Whitten 	if (cp && (strcmp(cp, SCF_STATE_STRING_ONLINE) == 0))
5159444c26fSTom Whitten 		est->sc_fs_minimal = B_TRUE;
5169444c26fSTom Whitten 	free((void *) cp);
5177c478bd9Sstevel@tonic-gate }
5187c478bd9Sstevel@tonic-gate 
5199444c26fSTom Whitten static int
5209444c26fSTom Whitten import_manifest_file(manifest_info_t *info, boolean_t validate, FILE *pout,
5219444c26fSTom Whitten     uint_t flags)
5227c478bd9Sstevel@tonic-gate {
5237c478bd9Sstevel@tonic-gate 	bundle_t *b;
5241f6eb021SLiane Praza 	tmpl_errors_t *errs;
5259444c26fSTom Whitten 	const char *file;
5269444c26fSTom Whitten 	tmpl_validate_status_t vr;
5277c478bd9Sstevel@tonic-gate 
5289444c26fSTom Whitten 	file = info->mi_path;
5297c478bd9Sstevel@tonic-gate 
5309444c26fSTom Whitten 	/* Load the manifest */
5317c478bd9Sstevel@tonic-gate 	b = internal_bundle_new();
5327c478bd9Sstevel@tonic-gate 
5333eae19d9Swesolows 	if (lxml_get_bundle_file(b, file, SVCCFG_OP_IMPORT) != 0) {
5347c478bd9Sstevel@tonic-gate 		internal_bundle_free(b);
5357c478bd9Sstevel@tonic-gate 		return (-1);
5367c478bd9Sstevel@tonic-gate 	}
5377c478bd9Sstevel@tonic-gate 
5381f6eb021SLiane Praza 	/* Validate */
5391f6eb021SLiane Praza 	if ((vr = tmpl_validate_bundle(b, &errs)) != TVS_SUCCESS) {
5401f6eb021SLiane Praza 		char *prefix;
5411f6eb021SLiane Praza 
5421f6eb021SLiane Praza 		if ((validate == 0) || (vr == TVS_WARN)) {
5431f6eb021SLiane Praza 			prefix = gettext("Warning: ");
5441f6eb021SLiane Praza 		} else {
5451f6eb021SLiane Praza 			prefix = "";
5461f6eb021SLiane Praza 		}
5471f6eb021SLiane Praza 		tmpl_errors_print(stderr, errs, prefix);
5481f6eb021SLiane Praza 		if (validate && (vr != TVS_WARN)) {
5491f6eb021SLiane Praza 			tmpl_errors_destroy(errs);
5509444c26fSTom Whitten 			semerr(gettext("Import of %s failed.\n"),
5519444c26fSTom Whitten 			    info->mi_path);
5529444c26fSTom Whitten 			if (pout != NULL) {
5539444c26fSTom Whitten 				(void) fprintf(pout, gettext("WARNING: svccfg "
5549444c26fSTom Whitten 				    "import of %s failed.\n"), info->mi_path);
5559444c26fSTom Whitten 			}
5569444c26fSTom Whitten 
5571f6eb021SLiane Praza 			return (-1);
5581f6eb021SLiane Praza 		}
5591f6eb021SLiane Praza 	}
5601f6eb021SLiane Praza 	tmpl_errors_destroy(errs);
5611f6eb021SLiane Praza 
5627c478bd9Sstevel@tonic-gate 	/* Import */
5637c478bd9Sstevel@tonic-gate 	if (lscf_bundle_import(b, file, flags) != 0) {
5647c478bd9Sstevel@tonic-gate 		internal_bundle_free(b);
5659444c26fSTom Whitten 		semerr(gettext("Import of %s failed.\n"), info->mi_path);
5669444c26fSTom Whitten 		if (pout != NULL) {
5679444c26fSTom Whitten 			(void) fprintf(pout, gettext("WARNING: svccfg import "
5689444c26fSTom Whitten 			    "of %s failed.\n"), info->mi_path);
5699444c26fSTom Whitten 		}
5707c478bd9Sstevel@tonic-gate 		return (-1);
5717c478bd9Sstevel@tonic-gate 	}
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	internal_bundle_free(b);
5747c478bd9Sstevel@tonic-gate 
5759444c26fSTom Whitten 	if (info->mi_prop) {
5767c478bd9Sstevel@tonic-gate 		char *errstr;
5777c478bd9Sstevel@tonic-gate 
5789444c26fSTom Whitten 		if (mhash_store_entry(g_hndl, info->mi_prop, file,
5799444c26fSTom Whitten 		    info->mi_hash, APPLY_NONE, &errstr)) {
5807c478bd9Sstevel@tonic-gate 			if (errstr)
5819444c26fSTom Whitten 				semerr(gettext("Could not store hash for %s. "
5829444c26fSTom Whitten 				    "%s\n"), info->mi_path, errstr);
5837c478bd9Sstevel@tonic-gate 			else
5847c478bd9Sstevel@tonic-gate 				semerr(gettext("Unknown error from "
5859444c26fSTom Whitten 				    "mhash_store_entry() for %s\n"),
5869444c26fSTom Whitten 				    info->mi_path);
5877c478bd9Sstevel@tonic-gate 		}
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	}
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	return (0);
5927c478bd9Sstevel@tonic-gate }
5937c478bd9Sstevel@tonic-gate 
5949444c26fSTom Whitten /*
5959444c26fSTom Whitten  * Return values:
5969444c26fSTom Whitten  *	1	No manifests need to be imported.
5979444c26fSTom Whitten  *	0	Success
5989444c26fSTom Whitten  *	-1	Error
5999444c26fSTom Whitten  *	-2	Syntax error
6009444c26fSTom Whitten  */
6019444c26fSTom Whitten int
6029444c26fSTom Whitten engine_import(uu_list_t *args)
6039444c26fSTom Whitten {
6049444c26fSTom Whitten 	int argc, i, o;
6059444c26fSTom Whitten 	int dont_exit;
6069444c26fSTom Whitten 	int failed_manifests;
6079444c26fSTom Whitten 	int total_manifests;
6089444c26fSTom Whitten 	char *file;
6099444c26fSTom Whitten 	char **argv = NULL;
6109444c26fSTom Whitten 	string_list_t *slp;
6119444c26fSTom Whitten 	boolean_t validate = B_FALSE;
6129444c26fSTom Whitten 	uint_t flags = SCI_GENERALLAST;
6139444c26fSTom Whitten 	int dirarg = 0;
6149444c26fSTom Whitten 	int isdir;
6159444c26fSTom Whitten 	int rc = -1;
6169444c26fSTom Whitten 	struct stat sb;
6179444c26fSTom Whitten 	char **paths;
6189444c26fSTom Whitten 	manifest_info_t ***manifest_sets = NULL;
6199444c26fSTom Whitten 	manifest_info_t **manifests;
6209444c26fSTom Whitten 	char *progress_file = NULL;
6219444c26fSTom Whitten 	FILE *progress_out = NULL;
6229444c26fSTom Whitten 	int progress_count;
6239444c26fSTom Whitten 	int back_count;
6249444c26fSTom Whitten 	int count;
6259444c26fSTom Whitten 	int fm_flags;
6269444c26fSTom Whitten 
6279444c26fSTom Whitten 	argc = uu_list_numnodes(args);
6289444c26fSTom Whitten 	if (argc < 1)
6299444c26fSTom Whitten 		return (-2);
6309444c26fSTom Whitten 
6319444c26fSTom Whitten 	argv = calloc(argc + 1, sizeof (char *));
6329444c26fSTom Whitten 	if (argv == NULL)
6339444c26fSTom Whitten 		uu_die(gettext("Out of memory.\n"));
6349444c26fSTom Whitten 
6359444c26fSTom Whitten 	for (slp = uu_list_first(args), i = 0;
6369444c26fSTom Whitten 	    slp != NULL;
6379444c26fSTom Whitten 	    slp = uu_list_next(args, slp), ++i)
6389444c26fSTom Whitten 		argv[i] = slp->str;
6399444c26fSTom Whitten 
6409444c26fSTom Whitten 	argv[i] = NULL;
6419444c26fSTom Whitten 
6429444c26fSTom Whitten 	opterr = 0;
6439444c26fSTom Whitten 	optind = 0;				/* Remember, no argv[0]. */
6449444c26fSTom Whitten 	for (;;) {
6459444c26fSTom Whitten 		o = getopt(argc, argv, "np:V");
6469444c26fSTom Whitten 		if (o == -1)
6479444c26fSTom Whitten 			break;
6489444c26fSTom Whitten 
6499444c26fSTom Whitten 		switch (o) {
6509444c26fSTom Whitten 		case 'n':
6519444c26fSTom Whitten 			flags |= SCI_NOREFRESH;
6529444c26fSTom Whitten 			break;
6539444c26fSTom Whitten 
6549444c26fSTom Whitten 		case 'p':
6559444c26fSTom Whitten 			progress_file = optarg;
6569444c26fSTom Whitten 			break;
6579444c26fSTom Whitten 
6589444c26fSTom Whitten 		case 'V':
6599444c26fSTom Whitten 			validate = B_TRUE;
6609444c26fSTom Whitten 			break;
6619444c26fSTom Whitten 
6629444c26fSTom Whitten 		case '?':
6639444c26fSTom Whitten 			free(argv);
6649444c26fSTom Whitten 			return (-2);
6659444c26fSTom Whitten 
6669444c26fSTom Whitten 		default:
6679444c26fSTom Whitten 			bad_error("getopt", o);
6689444c26fSTom Whitten 		}
6699444c26fSTom Whitten 	}
6709444c26fSTom Whitten 
6719444c26fSTom Whitten 	argc -= optind;
6729444c26fSTom Whitten 	if (argc < 1) {
6739444c26fSTom Whitten 		free(argv);
6749444c26fSTom Whitten 		return (-2);
6759444c26fSTom Whitten 	}
6769444c26fSTom Whitten 
6779444c26fSTom Whitten 	/* Open device for progress messages */
6789444c26fSTom Whitten 	if (progress_file != NULL) {
6799444c26fSTom Whitten 		if (strcmp(progress_file, "-") == 0) {
6809444c26fSTom Whitten 			progress_out = stdout;
6819444c26fSTom Whitten 		} else {
6829444c26fSTom Whitten 			progress_out = fopen(progress_file, "w");
6839444c26fSTom Whitten 			if (progress_out == NULL) {
6849444c26fSTom Whitten 				semerr(gettext("Unable to open %s for "
6859444c26fSTom Whitten 				    "progress reporting.  %s\n"),
6869444c26fSTom Whitten 				    progress_file, strerror(errno));
6879444c26fSTom Whitten 				goto out;
6889444c26fSTom Whitten 			}
6899444c26fSTom Whitten 			setbuf(progress_out, NULL);
6909444c26fSTom Whitten 		}
6919444c26fSTom Whitten 	}
6929444c26fSTom Whitten 
6939444c26fSTom Whitten 	paths = argv+optind;
6949444c26fSTom Whitten 	manifest_sets = safe_malloc(argc * sizeof (*manifest_sets));
6959444c26fSTom Whitten 
6969444c26fSTom Whitten 	/* If we're in interactive mode, force strict validation. */
6979444c26fSTom Whitten 	if (est->sc_cmd_flags & SC_CMD_IACTIVE)
6989444c26fSTom Whitten 		validate = B_TRUE;
6999444c26fSTom Whitten 
7009444c26fSTom Whitten 	lscf_prep_hndl();
7019444c26fSTom Whitten 
7029444c26fSTom Whitten 	/* Determine which manifests must be imported. */
7039444c26fSTom Whitten 
7049444c26fSTom Whitten 	total_manifests = 0;
7059444c26fSTom Whitten 	for (i = 0; i < argc; i++) {
7069444c26fSTom Whitten 		file = *(paths + i);
7079444c26fSTom Whitten 		fm_flags = CHECKHASH;
7089444c26fSTom Whitten 
7099444c26fSTom Whitten 		/* Determine if argument is a directory or file. */
7109444c26fSTom Whitten 		if (stat(file, &sb) == -1) {
7119444c26fSTom Whitten 			semerr(gettext("Unable to stat file %s.  %s\n"), file,
7129444c26fSTom Whitten 			    strerror(errno));
7139444c26fSTom Whitten 			goto out;
7149444c26fSTom Whitten 		}
7159444c26fSTom Whitten 		if (sb.st_mode & S_IFDIR) {
7169444c26fSTom Whitten 			fm_flags |= CHECKEXT;
7179444c26fSTom Whitten 			dirarg = 1;
7189444c26fSTom Whitten 			isdir = 1;
7199444c26fSTom Whitten 		} else if (sb.st_mode & S_IFREG) {
7209444c26fSTom Whitten 			isdir = 0;
7219444c26fSTom Whitten 		} else {
7229444c26fSTom Whitten 			semerr(gettext("%s is not a directory or regular "
7239444c26fSTom Whitten 			    "file\n"), file);
7249444c26fSTom Whitten 			goto out;
7259444c26fSTom Whitten 		}
7269444c26fSTom Whitten 
7279444c26fSTom Whitten 		/* Get list of manifests that we should import for this path. */
728293e3ab3STruong Q. Nguyen 		if ((count = find_manifests(g_hndl, file, &manifests,
729293e3ab3STruong Q. Nguyen 		    fm_flags)) < 0) {
7309444c26fSTom Whitten 			if (isdir) {
7319444c26fSTom Whitten 				semerr(gettext("Could not hash directory %s\n"),
7329444c26fSTom Whitten 				    file);
7339444c26fSTom Whitten 			} else {
7349444c26fSTom Whitten 				semerr(gettext("Could not hash file %s\n"),
7359444c26fSTom Whitten 				    file);
7369444c26fSTom Whitten 			}
7379444c26fSTom Whitten 			free_manifest_array(manifests);
7389444c26fSTom Whitten 			goto out;
7399444c26fSTom Whitten 		}
7409444c26fSTom Whitten 		total_manifests += count;
7419444c26fSTom Whitten 		manifest_sets[i] = manifests;
7429444c26fSTom Whitten 	}
7439444c26fSTom Whitten 
7449444c26fSTom Whitten 	if (total_manifests == 0) {
7459444c26fSTom Whitten 		/* No manifests to process. */
7469444c26fSTom Whitten 		if (g_verbose) {
7479444c26fSTom Whitten 			warn(gettext("No changes were necessary\n"));
7489444c26fSTom Whitten 		}
7499444c26fSTom Whitten 		rc = 1;
7509444c26fSTom Whitten 		goto out;
7519444c26fSTom Whitten 	}
7529444c26fSTom Whitten 
7539444c26fSTom Whitten 	/*
7549444c26fSTom Whitten 	 * If we're processing more than one file, we don't want to exit if
7559444c26fSTom Whitten 	 * we encounter an error.  We should go ahead and process all of
7569444c26fSTom Whitten 	 * the manifests.
7579444c26fSTom Whitten 	 */
7589444c26fSTom Whitten 	dont_exit = est->sc_cmd_flags & SC_CMD_DONT_EXIT;
7599444c26fSTom Whitten 	if (total_manifests > 1)
7609444c26fSTom Whitten 		est->sc_cmd_flags |= SC_CMD_DONT_EXIT;
7619444c26fSTom Whitten 
7629444c26fSTom Whitten 	if (progress_out != NULL)
7639444c26fSTom Whitten 		(void) fprintf(progress_out,
7649444c26fSTom Whitten 		    "Loading smf(5) service descriptions: ");
7659444c26fSTom Whitten 
7669444c26fSTom Whitten 	failed_manifests = 0;
7679444c26fSTom Whitten 	progress_count = 0;
7689444c26fSTom Whitten 	for (i = 0; i < argc; i++) {
7699444c26fSTom Whitten 		manifests = manifest_sets[i];
7709444c26fSTom Whitten 		if (manifests == NULL)
7719444c26fSTom Whitten 			continue;
7729444c26fSTom Whitten 		for (; *manifests != NULL; manifests++) {
7739444c26fSTom Whitten 			progress_count++;
7749444c26fSTom Whitten 			if (progress_out != NULL) {
7759444c26fSTom Whitten 				back_count = fprintf(progress_out, "%d/%d",
7769444c26fSTom Whitten 				    progress_count, total_manifests);
7779444c26fSTom Whitten 				while (back_count-- > 0) {
7789444c26fSTom Whitten 					(void) fputc('\b', progress_out);
7799444c26fSTom Whitten 				}
7809444c26fSTom Whitten 			}
7819444c26fSTom Whitten 			if (import_manifest_file(*manifests, validate,
7829444c26fSTom Whitten 			    progress_out, flags) != 0) {
7839444c26fSTom Whitten 				failed_manifests++;
7849444c26fSTom Whitten 			}
7859444c26fSTom Whitten 		}
7869444c26fSTom Whitten 	}
7879444c26fSTom Whitten 	if (progress_out != NULL)
7889444c26fSTom Whitten 		(void) fputc('\n', progress_out);
7899444c26fSTom Whitten 
7909444c26fSTom Whitten 	if ((total_manifests > 1) && (dont_exit == 0))
7919444c26fSTom Whitten 		est->sc_cmd_flags &= ~SC_CMD_DONT_EXIT;
7929444c26fSTom Whitten 
7939444c26fSTom Whitten 	if (dirarg && total_manifests > 0) {
7949444c26fSTom Whitten 		char *msg;
7959444c26fSTom Whitten 
7969444c26fSTom Whitten 		msg = "Loaded %d smf(5) service descriptions\n";
7979444c26fSTom Whitten 		warn(gettext(msg), progress_count);
7989444c26fSTom Whitten 
7999444c26fSTom Whitten 		if (failed_manifests) {
8009444c26fSTom Whitten 			msg = "%d smf(5) service descriptions failed to load\n";
8019444c26fSTom Whitten 			warn(gettext(msg), failed_manifests);
8029444c26fSTom Whitten 		}
8039444c26fSTom Whitten 	}
8049444c26fSTom Whitten 
8059444c26fSTom Whitten 	if (failed_manifests > 0)
8069444c26fSTom Whitten 		goto out;
8079444c26fSTom Whitten 
8089444c26fSTom Whitten 	if (g_verbose)
8099444c26fSTom Whitten 		warn(gettext("Successful import.\n"));
8109444c26fSTom Whitten 	rc = 0;
8119444c26fSTom Whitten 
8129444c26fSTom Whitten out:
8139444c26fSTom Whitten 	if ((progress_out != NULL) && (progress_out != stdout))
8149444c26fSTom Whitten 		(void) fclose(progress_out);
8159444c26fSTom Whitten 	free(argv);
8169444c26fSTom Whitten 	if (manifest_sets != NULL) {
8179444c26fSTom Whitten 		for (i = 0; i < argc; i++) {
8189444c26fSTom Whitten 			free_manifest_array(manifest_sets[i]);
8199444c26fSTom Whitten 		}
8209444c26fSTom Whitten 		free(manifest_sets);
8219444c26fSTom Whitten 	}
8229444c26fSTom Whitten 	return (rc);
8239444c26fSTom Whitten }
8249444c26fSTom Whitten 
8259444c26fSTom Whitten /*
8269444c26fSTom Whitten  * Walk each service and get its manifest file.
8279444c26fSTom Whitten  *
8289444c26fSTom Whitten  * If the file exists check instance support, and cleanup any
8299444c26fSTom Whitten  * stale instances.
8309444c26fSTom Whitten  *
8319444c26fSTom Whitten  * If the file doesn't exist tear down the service and/or instances
8329444c26fSTom Whitten  * that are no longer supported by files.
8339444c26fSTom Whitten  */
8349444c26fSTom Whitten int
8359444c26fSTom Whitten engine_cleanup(int flags)
8369444c26fSTom Whitten {
8379444c26fSTom Whitten 	boolean_t		activity = B_TRUE;
838*8c10095fSAlbert Lee 	int			dont_exit;
8399444c26fSTom Whitten 	int			r = -1;
8409444c26fSTom Whitten 
8419444c26fSTom Whitten 	lscf_prep_hndl();
8429444c26fSTom Whitten 
8439444c26fSTom Whitten 	if (flags == 1) {
8449444c26fSTom Whitten 		activity = B_FALSE;
8459444c26fSTom Whitten 	}
8469444c26fSTom Whitten 
847*8c10095fSAlbert Lee 	dont_exit = est->sc_cmd_flags & SC_CMD_DONT_EXIT;
848*8c10095fSAlbert Lee 	est->sc_cmd_flags |= SC_CMD_DONT_EXIT;
849*8c10095fSAlbert Lee 
8509444c26fSTom Whitten 	if (scf_walk_fmri(g_hndl, 0, NULL, SCF_WALK_SERVICE|SCF_WALK_NOINSTANCE,
8519444c26fSTom Whitten 	    lscf_service_cleanup, (void *)activity, NULL,
8529444c26fSTom Whitten 	    uu_warn) == SCF_SUCCESS)
8539444c26fSTom Whitten 		r = 0;
8549444c26fSTom Whitten 
855*8c10095fSAlbert Lee 	if (dont_exit == 0)
856*8c10095fSAlbert Lee 		est->sc_cmd_flags &= ~SC_CMD_DONT_EXIT;
857*8c10095fSAlbert Lee 
8589444c26fSTom Whitten 	(void) lscf_hash_cleanup();
8599444c26fSTom Whitten 
8609444c26fSTom Whitten 	return (r);
8619444c26fSTom Whitten }
8629444c26fSTom Whitten 
863adfc3118STruong Nguyen static int
864adfc3118STruong Nguyen apply_profile(manifest_info_t *info, int apply_changes)
8657c478bd9Sstevel@tonic-gate {
866adfc3118STruong Nguyen 	bundle_t *b = internal_bundle_new();
8677c478bd9Sstevel@tonic-gate 
868adfc3118STruong Nguyen 	if (lxml_get_bundle_file(b, info->mi_path, SVCCFG_OP_APPLY) != 0) {
8697c478bd9Sstevel@tonic-gate 		internal_bundle_free(b);
8707c478bd9Sstevel@tonic-gate 		return (-1);
8717c478bd9Sstevel@tonic-gate 	}
8727c478bd9Sstevel@tonic-gate 
873687293e1SAntonello Cruz 	if (!apply_changes) {	/* we don't want to apply, just test */
874687293e1SAntonello Cruz 		internal_bundle_free(b);
875687293e1SAntonello Cruz 		return (0);
876687293e1SAntonello Cruz 	}
877687293e1SAntonello Cruz 
878adfc3118STruong Nguyen 	if (lscf_bundle_apply(b, info->mi_path) != 0) {
8797c478bd9Sstevel@tonic-gate 		internal_bundle_free(b);
8807c478bd9Sstevel@tonic-gate 		return (-1);
8817c478bd9Sstevel@tonic-gate 	}
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 	internal_bundle_free(b);
8847c478bd9Sstevel@tonic-gate 
885adfc3118STruong Nguyen 	if (info->mi_prop) {
8869444c26fSTom Whitten 		apply_action_t apply;
8877c478bd9Sstevel@tonic-gate 		char *errstr;
8889444c26fSTom Whitten 
8899444c26fSTom Whitten 		apply = (est->sc_in_emi == 1) ? APPLY_LATE : APPLY_NONE;
890adfc3118STruong Nguyen 		if (mhash_store_entry(g_hndl, info->mi_prop, info->mi_path,
891adfc3118STruong Nguyen 		    info->mi_hash, apply, &errstr)) {
8927c478bd9Sstevel@tonic-gate 			semerr(errstr);
8939444c26fSTom Whitten 		}
8947c478bd9Sstevel@tonic-gate 	}
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	return (0);
8977c478bd9Sstevel@tonic-gate }
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate int
900adfc3118STruong Nguyen engine_apply(const char *file, int apply_changes)
901adfc3118STruong Nguyen {
902adfc3118STruong Nguyen 	int rc = 0;
903adfc3118STruong Nguyen 	int isdir;
904adfc3118STruong Nguyen 	int dont_exit;
905adfc3118STruong Nguyen 	int profile_count;
906adfc3118STruong Nguyen 	int fm_flags;
907adfc3118STruong Nguyen 	struct stat sb;
908adfc3118STruong Nguyen 	manifest_info_t **profiles = NULL;
909adfc3118STruong Nguyen 	manifest_info_t **entry;
910adfc3118STruong Nguyen 	manifest_info_t *pfile;
911adfc3118STruong Nguyen 
912adfc3118STruong Nguyen 	lscf_prep_hndl();
913adfc3118STruong Nguyen 
914adfc3118STruong Nguyen 	/* Determine which profile(s) must be applied. */
915adfc3118STruong Nguyen 
916adfc3118STruong Nguyen 	profile_count = 0;
917adfc3118STruong Nguyen 	fm_flags = BUNDLE_PROF | CHECKHASH;
918adfc3118STruong Nguyen 
919adfc3118STruong Nguyen 	/* Determine if argument is a directory or file. */
920adfc3118STruong Nguyen 	if (stat(file, &sb) == -1) {
921adfc3118STruong Nguyen 		semerr(gettext("Unable to stat file %s.  %s\n"), file,
922adfc3118STruong Nguyen 		    strerror(errno));
923adfc3118STruong Nguyen 		rc = -1;
924adfc3118STruong Nguyen 		goto out;
925adfc3118STruong Nguyen 	}
926adfc3118STruong Nguyen 
927adfc3118STruong Nguyen 	if (sb.st_mode & S_IFDIR) {
928adfc3118STruong Nguyen 		fm_flags |= CHECKEXT;
929adfc3118STruong Nguyen 		isdir = 1;
930adfc3118STruong Nguyen 	} else if (sb.st_mode & S_IFREG) {
931adfc3118STruong Nguyen 		isdir = 0;
932adfc3118STruong Nguyen 	} else {
933adfc3118STruong Nguyen 		semerr(gettext("%s is not a directory or regular "
934adfc3118STruong Nguyen 		    "file\n"), file);
935adfc3118STruong Nguyen 		rc = -1;
936adfc3118STruong Nguyen 		goto out;
937adfc3118STruong Nguyen 	}
938adfc3118STruong Nguyen 
939adfc3118STruong Nguyen 	/* Get list of profiles to be applied. */
940293e3ab3STruong Q. Nguyen 	if ((profile_count = find_manifests(g_hndl, file, &profiles,
941293e3ab3STruong Q. Nguyen 	    fm_flags)) < 0) {
942293e3ab3STruong Q. Nguyen 
943adfc3118STruong Nguyen 		if (isdir) {
944adfc3118STruong Nguyen 			semerr(gettext("Could not hash directory %s\n"), file);
945adfc3118STruong Nguyen 		} else {
946adfc3118STruong Nguyen 			semerr(gettext("Could not hash file %s\n"), file);
947adfc3118STruong Nguyen 		}
948adfc3118STruong Nguyen 		rc = -1;
949adfc3118STruong Nguyen 		goto out;
950adfc3118STruong Nguyen 	}
951adfc3118STruong Nguyen 
952adfc3118STruong Nguyen 	if (profile_count == 0) {
953adfc3118STruong Nguyen 		/* No profiles to process. */
954adfc3118STruong Nguyen 		if (g_verbose) {
955adfc3118STruong Nguyen 			warn(gettext("No changes were necessary\n"));
956adfc3118STruong Nguyen 		}
957adfc3118STruong Nguyen 		goto out;
958adfc3118STruong Nguyen 	}
959adfc3118STruong Nguyen 
960adfc3118STruong Nguyen 	/*
961adfc3118STruong Nguyen 	 * We don't want to exit if we encounter an error.  We should go ahead
962adfc3118STruong Nguyen 	 * and process all of the profiles.
963adfc3118STruong Nguyen 	 */
964adfc3118STruong Nguyen 	dont_exit = est->sc_cmd_flags & SC_CMD_DONT_EXIT;
965adfc3118STruong Nguyen 	est->sc_cmd_flags |= SC_CMD_DONT_EXIT;
966adfc3118STruong Nguyen 
967adfc3118STruong Nguyen 	for (entry = profiles; *entry != NULL; entry++) {
968adfc3118STruong Nguyen 		pfile = *entry;
969adfc3118STruong Nguyen 
970adfc3118STruong Nguyen 		if (apply_profile(pfile, apply_changes) == 0) {
971adfc3118STruong Nguyen 			if (g_verbose) {
972adfc3118STruong Nguyen 				warn(gettext("Successfully applied: %s\n"),
973adfc3118STruong Nguyen 				    pfile->mi_path);
974adfc3118STruong Nguyen 			}
975adfc3118STruong Nguyen 		} else {
976adfc3118STruong Nguyen 			warn(gettext("WARNING: Failed to apply %s\n"),
977adfc3118STruong Nguyen 			    pfile->mi_path);
978adfc3118STruong Nguyen 			rc = -1;
979adfc3118STruong Nguyen 		}
980adfc3118STruong Nguyen 	}
981adfc3118STruong Nguyen 
982adfc3118STruong Nguyen 	if (dont_exit == 0)
983adfc3118STruong Nguyen 		est->sc_cmd_flags &= ~SC_CMD_DONT_EXIT;
984adfc3118STruong Nguyen 
985adfc3118STruong Nguyen 	/* exit(1) appropriately if any profile failed to be applied. */
986adfc3118STruong Nguyen 	if ((rc == -1) &&
987adfc3118STruong Nguyen 	    (est->sc_cmd_flags & (SC_CMD_IACTIVE | SC_CMD_DONT_EXIT)) == 0) {
988adfc3118STruong Nguyen 		free_manifest_array(profiles);
989adfc3118STruong Nguyen 		exit(1);
990adfc3118STruong Nguyen 	}
991adfc3118STruong Nguyen 
992adfc3118STruong Nguyen out:
993adfc3118STruong Nguyen 	free_manifest_array(profiles);
994adfc3118STruong Nguyen 	return (rc);
995adfc3118STruong Nguyen }
996adfc3118STruong Nguyen 
997adfc3118STruong Nguyen int
9983eae19d9Swesolows engine_restore(const char *file)
9993eae19d9Swesolows {
10003eae19d9Swesolows 	bundle_t *b;
10013eae19d9Swesolows 
10023eae19d9Swesolows 	lscf_prep_hndl();
10033eae19d9Swesolows 
10043eae19d9Swesolows 	b = internal_bundle_new();
10053eae19d9Swesolows 
10063eae19d9Swesolows 	if (lxml_get_bundle_file(b, file, SVCCFG_OP_RESTORE) != 0) {
10073eae19d9Swesolows 		internal_bundle_free(b);
10083eae19d9Swesolows 		return (-1);
10093eae19d9Swesolows 	}
10103eae19d9Swesolows 
10113eae19d9Swesolows 	if (lscf_bundle_import(b, file, SCI_NOSNAP) != 0) {
10123eae19d9Swesolows 		internal_bundle_free(b);
10133eae19d9Swesolows 		return (-1);
10143eae19d9Swesolows 	}
10153eae19d9Swesolows 
10163eae19d9Swesolows 	internal_bundle_free(b);
10173eae19d9Swesolows 
10183eae19d9Swesolows 	return (0);
10193eae19d9Swesolows }
10203eae19d9Swesolows 
10213eae19d9Swesolows int
10227c478bd9Sstevel@tonic-gate engine_set(uu_list_t *args)
10237c478bd9Sstevel@tonic-gate {
10247c478bd9Sstevel@tonic-gate 	uu_list_walk_t *walk;
10257c478bd9Sstevel@tonic-gate 	string_list_t *slp;
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	if (uu_list_first(args) == NULL) {
10287c478bd9Sstevel@tonic-gate 		/* Display current options. */
10297c478bd9Sstevel@tonic-gate 		if (!g_verbose)
10307c478bd9Sstevel@tonic-gate 			(void) fputs("no", stdout);
10317c478bd9Sstevel@tonic-gate 		(void) puts("verbose");
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 		return (0);
10347c478bd9Sstevel@tonic-gate 	}
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	walk = uu_list_walk_start(args, UU_DEFAULT);
10377c478bd9Sstevel@tonic-gate 	if (walk == NULL)
10387c478bd9Sstevel@tonic-gate 		uu_die(gettext("Couldn't read arguments"));
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	/* Use getopt? */
10417c478bd9Sstevel@tonic-gate 	for (slp = uu_list_walk_next(walk);
10427c478bd9Sstevel@tonic-gate 	    slp != NULL;
10437c478bd9Sstevel@tonic-gate 	    slp = uu_list_walk_next(walk)) {
10447c478bd9Sstevel@tonic-gate 		if (slp->str[0] == '-') {
10457c478bd9Sstevel@tonic-gate 			char *op;
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 			for (op = &slp->str[1]; *op != '\0'; ++op) {
10487c478bd9Sstevel@tonic-gate 				switch (*op) {
10497c478bd9Sstevel@tonic-gate 				case 'v':
10507c478bd9Sstevel@tonic-gate 					g_verbose = 1;
10517c478bd9Sstevel@tonic-gate 					break;
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 				case 'V':
10547c478bd9Sstevel@tonic-gate 					g_verbose = 0;
10557c478bd9Sstevel@tonic-gate 					break;
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 				default:
10587c478bd9Sstevel@tonic-gate 					warn(gettext("Unknown option -%c.\n"),
10597c478bd9Sstevel@tonic-gate 					    *op);
10607c478bd9Sstevel@tonic-gate 				}
10617c478bd9Sstevel@tonic-gate 			}
10627c478bd9Sstevel@tonic-gate 		} else {
10637c478bd9Sstevel@tonic-gate 			warn(gettext("No non-flag arguments defined.\n"));
10647c478bd9Sstevel@tonic-gate 		}
10657c478bd9Sstevel@tonic-gate 	}
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate 	return (0);
10687c478bd9Sstevel@tonic-gate }
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate void
10717c478bd9Sstevel@tonic-gate help(int com)
10727c478bd9Sstevel@tonic-gate {
10737c478bd9Sstevel@tonic-gate 	int i;
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	if (com == 0) {
10767c478bd9Sstevel@tonic-gate 		warn(gettext("General commands:	 help set repository end\n"
10777c478bd9Sstevel@tonic-gate 		    "Manifest commands:	 inventory validate import export "
10787c478bd9Sstevel@tonic-gate 		    "archive\n"
10797c478bd9Sstevel@tonic-gate 		    "Profile commands:	 apply extract\n"
10801f6eb021SLiane Praza 		    "Entity commands:	 list select unselect add delete "
10811f6eb021SLiane Praza 		    "describe\n"
10827c478bd9Sstevel@tonic-gate 		    "Snapshot commands:	 listsnap selectsnap revert\n"
1083347a77f2Samaguire 		    "Instance commands:	 refresh\n"
10847c478bd9Sstevel@tonic-gate 		    "Property group commands: listpg addpg delpg\n"
10857c478bd9Sstevel@tonic-gate 		    "Property commands:	 listprop setprop delprop editprop\n"
10867c478bd9Sstevel@tonic-gate 		    "Property value commands: addpropvalue delpropvalue "
1087f6e214c7SGavin Maltby 		    "setenv unsetenv\n"
1088f6e214c7SGavin Maltby 		    "Notification parameters: "
1089f6e214c7SGavin Maltby 		    "listnotify setnotify delnotify\n"));
10907c478bd9Sstevel@tonic-gate 		return;
10917c478bd9Sstevel@tonic-gate 	}
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate 	for (i = 0; help_messages[i].message != NULL; ++i) {
10947c478bd9Sstevel@tonic-gate 		if (help_messages[i].token == com) {
10957c478bd9Sstevel@tonic-gate 			warn(gettext("Usage: %s\n"),
10967c478bd9Sstevel@tonic-gate 			    gettext(help_messages[i].message));
10977c478bd9Sstevel@tonic-gate 			return;
10987c478bd9Sstevel@tonic-gate 		}
10997c478bd9Sstevel@tonic-gate 	}
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate 	warn(gettext("Unknown command.\n"));
11027c478bd9Sstevel@tonic-gate }
1103