xref: /onnv-gate/usr/src/cmd/svc/svccfg/svccfg_engine.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * svccfg(1) interpreter and command execution engine.
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <sys/mman.h>
34*0Sstevel@tonic-gate #include <sys/stat.h>
35*0Sstevel@tonic-gate #include <sys/types.h>
36*0Sstevel@tonic-gate #include <assert.h>
37*0Sstevel@tonic-gate #include <errno.h>
38*0Sstevel@tonic-gate #include <libintl.h>
39*0Sstevel@tonic-gate #include <libtecla.h>
40*0Sstevel@tonic-gate #include <md5.h>
41*0Sstevel@tonic-gate #include <string.h>
42*0Sstevel@tonic-gate #include <stdlib.h>
43*0Sstevel@tonic-gate #include <unistd.h>
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate #include "manifest_hash.h"
46*0Sstevel@tonic-gate #include "svccfg.h"
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate #define	MS_PER_US		1000
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate engine_state_t *est;
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate /*
53*0Sstevel@tonic-gate  * Replacement lex(1) character retrieval routines.
54*0Sstevel@tonic-gate  */
55*0Sstevel@tonic-gate int
56*0Sstevel@tonic-gate engine_cmd_getc(engine_state_t *E)
57*0Sstevel@tonic-gate {
58*0Sstevel@tonic-gate 	if (E->sc_cmd_file != NULL)
59*0Sstevel@tonic-gate 		return (getc(E->sc_cmd_file));
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate 	if (E->sc_cmd_flags & SC_CMD_EOF)
62*0Sstevel@tonic-gate 		return (EOF);
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate 	if (E->sc_cmd_bufoff < E->sc_cmd_bufsz)
65*0Sstevel@tonic-gate 		return (*(E->sc_cmd_buf + E->sc_cmd_bufoff++));
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate 	if (!(E->sc_cmd_flags & SC_CMD_IACTIVE)) {
68*0Sstevel@tonic-gate 		E->sc_cmd_flags |= SC_CMD_EOF;
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate 		return (EOF);
71*0Sstevel@tonic-gate 	} else {
72*0Sstevel@tonic-gate #ifdef NATIVE_BUILD
73*0Sstevel@tonic-gate 		return (EOF);
74*0Sstevel@tonic-gate #else
75*0Sstevel@tonic-gate 		extern int parens;
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate 		if (parens <= 0) {
78*0Sstevel@tonic-gate 			E->sc_cmd_flags |= SC_CMD_EOF;
79*0Sstevel@tonic-gate 			return (EOF);
80*0Sstevel@tonic-gate 		}
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate 		for (;;) {
83*0Sstevel@tonic-gate 			E->sc_cmd_buf = gl_get_line(E->sc_gl, "> ", NULL, -1);
84*0Sstevel@tonic-gate 			if (E->sc_cmd_buf != NULL)
85*0Sstevel@tonic-gate 				break;
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate 			switch (gl_return_status(E->sc_gl)) {
88*0Sstevel@tonic-gate 			case GLR_SIGNAL:
89*0Sstevel@tonic-gate 				gl_abandon_line(E->sc_gl);
90*0Sstevel@tonic-gate 				continue;
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate 			case GLR_EOF:
93*0Sstevel@tonic-gate 				E->sc_cmd_flags |= SC_CMD_EOF;
94*0Sstevel@tonic-gate 				return (EOF);
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate 			case GLR_ERROR:
97*0Sstevel@tonic-gate 				uu_die(gettext("Error reading terminal: %s.\n"),
98*0Sstevel@tonic-gate 				    gl_error_message(E->sc_gl, NULL, 0));
99*0Sstevel@tonic-gate 				/* NOTREACHED */
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 			default:
102*0Sstevel@tonic-gate #ifndef NDEBUG
103*0Sstevel@tonic-gate 				(void) fprintf(stderr, "%s:%d: gl_get_line() "
104*0Sstevel@tonic-gate 				    "returned unexpected value %d.\n", __FILE__,
105*0Sstevel@tonic-gate 				    __LINE__, gl_return_status(E->sc_gl));
106*0Sstevel@tonic-gate #endif
107*0Sstevel@tonic-gate 				abort();
108*0Sstevel@tonic-gate 			}
109*0Sstevel@tonic-gate 		}
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 		E->sc_cmd_bufsz = strlen(E->sc_cmd_buf);
112*0Sstevel@tonic-gate 		E->sc_cmd_bufoff = 1;
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate 		return (E->sc_cmd_buf[0]);
115*0Sstevel@tonic-gate #endif	/* NATIVE_BUILD */
116*0Sstevel@tonic-gate 	}
117*0Sstevel@tonic-gate }
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate int
120*0Sstevel@tonic-gate engine_cmd_ungetc(engine_state_t *E, char c)
121*0Sstevel@tonic-gate {
122*0Sstevel@tonic-gate 	if (E->sc_cmd_file != NULL)
123*0Sstevel@tonic-gate 		return (ungetc(c, E->sc_cmd_file));
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate 	if (E->sc_cmd_buf != NULL)
126*0Sstevel@tonic-gate 		*(E->sc_cmd_buf + --E->sc_cmd_bufoff) = c;
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 	return (c);
129*0Sstevel@tonic-gate }
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate /*ARGSUSED*/
132*0Sstevel@tonic-gate void
133*0Sstevel@tonic-gate engine_cmd_nputs(engine_state_t *E, char *c, size_t n)
134*0Sstevel@tonic-gate {
135*0Sstevel@tonic-gate 	/* our lexer shouldn't need this state */
136*0Sstevel@tonic-gate 	exit(11);
137*0Sstevel@tonic-gate }
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate int
140*0Sstevel@tonic-gate engine_exec(char *cmd)
141*0Sstevel@tonic-gate {
142*0Sstevel@tonic-gate 	est->sc_cmd_buf = cmd;
143*0Sstevel@tonic-gate 	est->sc_cmd_bufsz = strlen(cmd) + 1;
144*0Sstevel@tonic-gate 	est->sc_cmd_bufoff = 0;
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate 	(void) yyparse();
147*0Sstevel@tonic-gate 
148*0Sstevel@tonic-gate 	return (0);
149*0Sstevel@tonic-gate }
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate #ifndef NATIVE_BUILD
152*0Sstevel@tonic-gate /* ARGSUSED */
153*0Sstevel@tonic-gate static
154*0Sstevel@tonic-gate CPL_CHECK_FN(check_xml)
155*0Sstevel@tonic-gate {
156*0Sstevel@tonic-gate 	const char *ext;
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate 	if (strlen(pathname) < 4)
159*0Sstevel@tonic-gate 		return (0);
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate 	ext = pathname + strlen(pathname) - 4;
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 	return (strcmp(ext, ".xml") == 0 ? 1 : 0);
164*0Sstevel@tonic-gate }
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate static const char * const whitespace = " \t";
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate static
169*0Sstevel@tonic-gate CPL_MATCH_FN(complete_single_xml_file_arg)
170*0Sstevel@tonic-gate {
171*0Sstevel@tonic-gate 	const char *arg1 = data;
172*0Sstevel@tonic-gate 	int arg1end_i, ret;
173*0Sstevel@tonic-gate 	CplFileConf *cfc;
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate 	arg1end_i = arg1 + strcspn(arg1, whitespace) - line;
176*0Sstevel@tonic-gate 	if (arg1end_i < word_end)
177*0Sstevel@tonic-gate 		return (0);
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate 	cfc = new_CplFileConf();
180*0Sstevel@tonic-gate 	if (cfc == NULL) {
181*0Sstevel@tonic-gate 		cpl_record_error(cpl, "Out of memory.");
182*0Sstevel@tonic-gate 		return (1);
183*0Sstevel@tonic-gate 	}
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate 	cfc_set_check_fn(cfc, check_xml, NULL);
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 	ret = cpl_file_completions(cpl, cfc, line, word_end);
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 	(void) del_CplFileConf(cfc);
190*0Sstevel@tonic-gate 	return (ret);
191*0Sstevel@tonic-gate }
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate static struct cmd_info {
194*0Sstevel@tonic-gate 	const char	*name;
195*0Sstevel@tonic-gate 	uint32_t	flags;
196*0Sstevel@tonic-gate 	CplMatchFn	*complete_args_f;
197*0Sstevel@tonic-gate } cmds[] = {
198*0Sstevel@tonic-gate 	{ "validate", CS_GLOBAL, complete_single_xml_file_arg },
199*0Sstevel@tonic-gate 	{ "import", CS_GLOBAL, complete_single_xml_file_arg },
200*0Sstevel@tonic-gate 	{ "export", CS_GLOBAL, NULL },
201*0Sstevel@tonic-gate 	{ "archive", CS_GLOBAL, NULL },
202*0Sstevel@tonic-gate 	{ "apply", CS_GLOBAL, complete_single_xml_file_arg },
203*0Sstevel@tonic-gate 	{ "extract", CS_GLOBAL, NULL },
204*0Sstevel@tonic-gate 	{ "repository", CS_GLOBAL, NULL },
205*0Sstevel@tonic-gate 	{ "inventory", CS_GLOBAL, complete_single_xml_file_arg },
206*0Sstevel@tonic-gate 	{ "set", CS_GLOBAL, NULL },
207*0Sstevel@tonic-gate 	{ "end", CS_GLOBAL, NULL },
208*0Sstevel@tonic-gate 	{ "exit", CS_GLOBAL, NULL },
209*0Sstevel@tonic-gate 	{ "quit", CS_GLOBAL, NULL },
210*0Sstevel@tonic-gate 	{ "help", CS_GLOBAL, NULL },
211*0Sstevel@tonic-gate 	{ "delete", CS_GLOBAL, NULL },
212*0Sstevel@tonic-gate 	{ "select", CS_GLOBAL, complete_select },
213*0Sstevel@tonic-gate 	{ "unselect", CS_SVC | CS_INST | CS_SNAP, NULL },
214*0Sstevel@tonic-gate 	{ "list", CS_SCOPE | CS_SVC | CS_SNAP, NULL },
215*0Sstevel@tonic-gate 	{ "add", CS_SCOPE | CS_SVC, NULL },
216*0Sstevel@tonic-gate 	{ "listpg", CS_SVC | CS_INST | CS_SNAP, NULL },
217*0Sstevel@tonic-gate 	{ "addpg", CS_SVC | CS_INST, NULL },
218*0Sstevel@tonic-gate 	{ "delpg", CS_SVC | CS_INST, NULL },
219*0Sstevel@tonic-gate 	{ "listprop", CS_SVC | CS_INST | CS_SNAP, NULL },
220*0Sstevel@tonic-gate 	{ "setprop", CS_SVC | CS_INST, NULL },
221*0Sstevel@tonic-gate 	{ "delprop", CS_SVC | CS_INST, NULL },
222*0Sstevel@tonic-gate 	{ "editprop", CS_SVC | CS_INST, NULL },
223*0Sstevel@tonic-gate 	{ "listsnap", CS_INST | CS_SNAP, NULL },
224*0Sstevel@tonic-gate 	{ "selectsnap", CS_INST | CS_SNAP, NULL },
225*0Sstevel@tonic-gate 	{ "revert", CS_INST | CS_SNAP, NULL },
226*0Sstevel@tonic-gate 	{ NULL }
227*0Sstevel@tonic-gate };
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate int
230*0Sstevel@tonic-gate add_cmd_matches(WordCompletion *cpl, const char *line, int word_end,
231*0Sstevel@tonic-gate     uint32_t scope)
232*0Sstevel@tonic-gate {
233*0Sstevel@tonic-gate 	int word_start, err;
234*0Sstevel@tonic-gate 	size_t len;
235*0Sstevel@tonic-gate 	const char *bol;
236*0Sstevel@tonic-gate 	struct cmd_info *cip;
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 	word_start = strspn(line, whitespace);
239*0Sstevel@tonic-gate 	len = word_end - word_start;
240*0Sstevel@tonic-gate 	bol = line + word_end - len;
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	for (cip = cmds; cip->name != NULL; ++cip) {
243*0Sstevel@tonic-gate 		if ((cip->flags & scope) == 0)
244*0Sstevel@tonic-gate 			continue;
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate 		if (strncmp(cip->name, bol, len) == 0) {
247*0Sstevel@tonic-gate 			err = cpl_add_completion(cpl, line, word_start,
248*0Sstevel@tonic-gate 			    word_end, cip->name + len, "", " ");
249*0Sstevel@tonic-gate 			if (err != 0)
250*0Sstevel@tonic-gate 				return (err);
251*0Sstevel@tonic-gate 		}
252*0Sstevel@tonic-gate 	}
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 	return (0);
255*0Sstevel@tonic-gate }
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate /*
258*0Sstevel@tonic-gate  * Suggest completions.  We must first determine if the cursor is in command
259*0Sstevel@tonic-gate  * position or in argument position.  If the former, complete_command() finds
260*0Sstevel@tonic-gate  * matching commands.  If the latter, we tail-call the command-specific
261*0Sstevel@tonic-gate  * argument-completion routine in the cmds table.
262*0Sstevel@tonic-gate  */
263*0Sstevel@tonic-gate /* ARGSUSED */
264*0Sstevel@tonic-gate static
265*0Sstevel@tonic-gate CPL_MATCH_FN(complete)
266*0Sstevel@tonic-gate {
267*0Sstevel@tonic-gate 	const char *arg0, *arg1;
268*0Sstevel@tonic-gate 	size_t arg0len;
269*0Sstevel@tonic-gate 	struct cmd_info *cip;
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	arg0 = line + strspn(line, whitespace);
272*0Sstevel@tonic-gate 	arg0len = strcspn(arg0, whitespace);
273*0Sstevel@tonic-gate 	if ((arg0 + arg0len) - line >= word_end ||
274*0Sstevel@tonic-gate 	    (arg0[arg0len] != ' ' && arg0[arg0len] != '\t'))
275*0Sstevel@tonic-gate 		return (complete_command(cpl, (void *)arg0, line, word_end));
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 	arg1 = arg0 + arg0len;
278*0Sstevel@tonic-gate 	arg1 += strspn(arg1, whitespace);
279*0Sstevel@tonic-gate 
280*0Sstevel@tonic-gate 	for (cip = cmds; cip->name != NULL; ++cip) {
281*0Sstevel@tonic-gate 		if (strlen(cip->name) != arg0len)
282*0Sstevel@tonic-gate 			continue;
283*0Sstevel@tonic-gate 
284*0Sstevel@tonic-gate 		if (strncmp(cip->name, arg0, arg0len) != 0)
285*0Sstevel@tonic-gate 			continue;
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 		if (cip->complete_args_f == NULL)
288*0Sstevel@tonic-gate 			break;
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 		return (cip->complete_args_f(cpl, (void *)arg1, line,
291*0Sstevel@tonic-gate 		    word_end));
292*0Sstevel@tonic-gate 	}
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 	return (0);
295*0Sstevel@tonic-gate }
296*0Sstevel@tonic-gate #endif	/* NATIVE_BUILD */
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate int
299*0Sstevel@tonic-gate engine_interp()
300*0Sstevel@tonic-gate {
301*0Sstevel@tonic-gate #ifdef NATIVE_BUILD
302*0Sstevel@tonic-gate 	uu_die("native build does not support interactive mode.");
303*0Sstevel@tonic-gate #else
304*0Sstevel@tonic-gate 	char *selfmri;
305*0Sstevel@tonic-gate 	size_t sfsz;
306*0Sstevel@tonic-gate 	int r;
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	extern int parens;
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate 	(void) sigset(SIGINT, SIG_IGN);
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 	est->sc_gl = new_GetLine(512, 8000);
313*0Sstevel@tonic-gate 	if (est->sc_gl == NULL)
314*0Sstevel@tonic-gate 		uu_die(gettext("Out of memory.\n"));
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	/* The longest string is "[snapname]fmri[:instname]> ". */
317*0Sstevel@tonic-gate 	sfsz = 1 + max_scf_name_len + 1 + max_scf_fmri_len + 2 +
318*0Sstevel@tonic-gate 	    max_scf_name_len + 1 + 2 + 1;
319*0Sstevel@tonic-gate 	selfmri = safe_malloc(sfsz);
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 	r = gl_customize_completion(est->sc_gl, NULL, complete);
322*0Sstevel@tonic-gate 	assert(r == 0);
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 	for (;;) {
325*0Sstevel@tonic-gate 		lscf_get_selection_str(selfmri, sfsz - 2);
326*0Sstevel@tonic-gate 		(void) strcat(selfmri, "> ");
327*0Sstevel@tonic-gate 		est->sc_cmd_buf = gl_get_line(est->sc_gl, selfmri, NULL, -1);
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 		if (est->sc_cmd_buf == NULL) {
330*0Sstevel@tonic-gate 			switch (gl_return_status(est->sc_gl)) {
331*0Sstevel@tonic-gate 			case GLR_SIGNAL:
332*0Sstevel@tonic-gate 				gl_abandon_line(est->sc_gl);
333*0Sstevel@tonic-gate 				continue;
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 			case GLR_EOF:
336*0Sstevel@tonic-gate 				break;
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 			case GLR_ERROR:
339*0Sstevel@tonic-gate 				uu_die(gettext("Error reading terminal: %s.\n"),
340*0Sstevel@tonic-gate 				    gl_error_message(est->sc_gl, NULL, 0));
341*0Sstevel@tonic-gate 				/* NOTREACHED */
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 			default:
344*0Sstevel@tonic-gate #ifndef NDEBUG
345*0Sstevel@tonic-gate 				(void) fprintf(stderr, "%s:%d: gl_get_line() "
346*0Sstevel@tonic-gate 				    "returned unexpected value %d.\n", __FILE__,
347*0Sstevel@tonic-gate 				    __LINE__, gl_return_status(est->sc_gl));
348*0Sstevel@tonic-gate #endif
349*0Sstevel@tonic-gate 				abort();
350*0Sstevel@tonic-gate 			}
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate 			break;
353*0Sstevel@tonic-gate 		}
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 		parens = 0;
356*0Sstevel@tonic-gate 		est->sc_cmd_bufsz = strlen(est->sc_cmd_buf);
357*0Sstevel@tonic-gate 		est->sc_cmd_bufoff = 0;
358*0Sstevel@tonic-gate 		est->sc_cmd_flags = SC_CMD_IACTIVE;
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 		(void) yyparse();
361*0Sstevel@tonic-gate 	}
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 	free(selfmri);
364*0Sstevel@tonic-gate 	est->sc_gl = del_GetLine(est->sc_gl);	/* returns NULL */
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate #endif	/* NATIVE_BUILD */
367*0Sstevel@tonic-gate 	return (0);
368*0Sstevel@tonic-gate }
369*0Sstevel@tonic-gate 
370*0Sstevel@tonic-gate int
371*0Sstevel@tonic-gate engine_source(const char *name, boolean_t dont_exit)
372*0Sstevel@tonic-gate {
373*0Sstevel@tonic-gate 	engine_state_t *old = est;
374*0Sstevel@tonic-gate 	struct stat st;
375*0Sstevel@tonic-gate 	int ret;
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 	est = uu_zalloc(sizeof (engine_state_t));
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 	/* first, copy the stuff set up in engine_init */
380*0Sstevel@tonic-gate 	est->sc_repo_pid = old->sc_repo_pid;
381*0Sstevel@tonic-gate 	if (old->sc_repo_filename != NULL)
382*0Sstevel@tonic-gate 		est->sc_repo_filename = safe_strdup(old->sc_repo_filename);
383*0Sstevel@tonic-gate 	if (old->sc_repo_doordir != NULL)
384*0Sstevel@tonic-gate 		est->sc_repo_doordir = safe_strdup(old->sc_repo_doordir);
385*0Sstevel@tonic-gate 	if (old->sc_repo_doorname != NULL)
386*0Sstevel@tonic-gate 		est->sc_repo_doorname = safe_strdup(old->sc_repo_doorname);
387*0Sstevel@tonic-gate 	if (old->sc_repo_server != NULL)
388*0Sstevel@tonic-gate 		est->sc_repo_server = safe_strdup(old->sc_repo_server);
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate 	/* set up the new guy */
391*0Sstevel@tonic-gate 	est->sc_cmd_lineno = 1;
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate 	if (dont_exit)
394*0Sstevel@tonic-gate 		est->sc_cmd_flags |= SC_CMD_DONT_EXIT;
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 	if (strcmp(name, "-") == 0) {
397*0Sstevel@tonic-gate 		est->sc_cmd_file = stdin;
398*0Sstevel@tonic-gate 		est->sc_cmd_filename = "<stdin>";
399*0Sstevel@tonic-gate 	} else {
400*0Sstevel@tonic-gate 		errno = 0;
401*0Sstevel@tonic-gate 		est->sc_cmd_filename = name;
402*0Sstevel@tonic-gate 		est->sc_cmd_file = fopen(name, "r");
403*0Sstevel@tonic-gate 		if (est->sc_cmd_file == NULL) {
404*0Sstevel@tonic-gate 			if (errno == 0)
405*0Sstevel@tonic-gate 				semerr(gettext("No free stdio streams.\n"));
406*0Sstevel@tonic-gate 			else
407*0Sstevel@tonic-gate 				semerr(gettext("Could not open %s"), name);
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate 			ret = -1;
410*0Sstevel@tonic-gate 			goto fail;
411*0Sstevel@tonic-gate 		}
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate 		do
414*0Sstevel@tonic-gate 			ret = fstat(fileno(est->sc_cmd_file), &st);
415*0Sstevel@tonic-gate 		while (ret != 0 && errno == EINTR);
416*0Sstevel@tonic-gate 		if (ret != 0) {
417*0Sstevel@tonic-gate 			(void) fclose(est->sc_cmd_file);
418*0Sstevel@tonic-gate 			est->sc_cmd_file = NULL;	/* for semerr() */
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 			semerr(gettext("Could not stat %s"), name);
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate 			ret = -1;
423*0Sstevel@tonic-gate 			goto fail;
424*0Sstevel@tonic-gate 		}
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 		if (!S_ISREG(st.st_mode)) {
427*0Sstevel@tonic-gate 			(void) fclose(est->sc_cmd_file);
428*0Sstevel@tonic-gate 			est->sc_cmd_file = NULL;	/* for semerr() */
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate 			semerr(gettext("%s is not a regular file.\n"), name);
431*0Sstevel@tonic-gate 
432*0Sstevel@tonic-gate 			ret = -1;
433*0Sstevel@tonic-gate 			goto fail;
434*0Sstevel@tonic-gate 		}
435*0Sstevel@tonic-gate 	}
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 	(void) yyparse();
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 	if (est->sc_cmd_file != stdin)
440*0Sstevel@tonic-gate 		(void) fclose(est->sc_cmd_file);
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate 	ret = 0;
443*0Sstevel@tonic-gate 
444*0Sstevel@tonic-gate fail:
445*0Sstevel@tonic-gate 	if (est->sc_repo_pid != old->sc_repo_pid)
446*0Sstevel@tonic-gate 		lscf_cleanup();		/* clean up any new repository */
447*0Sstevel@tonic-gate 
448*0Sstevel@tonic-gate 	if (est->sc_repo_filename != NULL)
449*0Sstevel@tonic-gate 		free((void *)est->sc_repo_filename);
450*0Sstevel@tonic-gate 	if (est->sc_repo_doordir != NULL)
451*0Sstevel@tonic-gate 		free((void *)est->sc_repo_doordir);
452*0Sstevel@tonic-gate 	if (est->sc_repo_doorname != NULL)
453*0Sstevel@tonic-gate 		free((void *)est->sc_repo_doorname);
454*0Sstevel@tonic-gate 	if (est->sc_repo_server != NULL)
455*0Sstevel@tonic-gate 		free((void *)est->sc_repo_server);
456*0Sstevel@tonic-gate 	free(est);
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate 	est = old;
459*0Sstevel@tonic-gate 
460*0Sstevel@tonic-gate 	return (ret);
461*0Sstevel@tonic-gate }
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate /*
464*0Sstevel@tonic-gate  * Initialize svccfg state.  We recognize four environment variables:
465*0Sstevel@tonic-gate  *
466*0Sstevel@tonic-gate  * SVCCFG_REPOSITORY	Create a private instance of svc.configd(1M) to answer
467*0Sstevel@tonic-gate  *			requests for the specified repository file.
468*0Sstevel@tonic-gate  * SVCCFG_DOOR_PATH	Directory for door creation.
469*0Sstevel@tonic-gate  *
470*0Sstevel@tonic-gate  * SVCCFG_DOOR		Rendezvous via an alternative repository door.
471*0Sstevel@tonic-gate  *
472*0Sstevel@tonic-gate  * SVCCFG_CONFIGD_PATH	Resolvable path to alternative svc.configd(1M) binary.
473*0Sstevel@tonic-gate  */
474*0Sstevel@tonic-gate void
475*0Sstevel@tonic-gate engine_init()
476*0Sstevel@tonic-gate {
477*0Sstevel@tonic-gate 	const char *cp;
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate 	est = uu_zalloc(sizeof (engine_state_t));
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate 	est->sc_cmd_lineno = 1;
482*0Sstevel@tonic-gate 	est->sc_repo_pid = -1;
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate 	cp = getenv("SVCCFG_REPOSITORY");
485*0Sstevel@tonic-gate 	est->sc_repo_filename = cp ? safe_strdup(cp) : NULL;
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate 	cp = getenv("SVCCFG_DOOR_PATH");
488*0Sstevel@tonic-gate 	est->sc_repo_doordir = cp ? cp : "/var/run";
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 	cp = getenv("SVCCFG_DOOR");
491*0Sstevel@tonic-gate 	if (cp != NULL) {
492*0Sstevel@tonic-gate 		if (est->sc_repo_filename != NULL) {
493*0Sstevel@tonic-gate 			uu_warn(gettext("SVCCFG_DOOR unused when "
494*0Sstevel@tonic-gate 			    "SVCCFG_REPOSITORY specified\n"));
495*0Sstevel@tonic-gate 		} else {
496*0Sstevel@tonic-gate 			est->sc_repo_doorname = safe_strdup(cp);
497*0Sstevel@tonic-gate 		}
498*0Sstevel@tonic-gate 	}
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate 	cp = getenv("SVCCFG_CONFIGD_PATH");
501*0Sstevel@tonic-gate 	est->sc_repo_server = cp ? cp : "/lib/svc/bin/svc.configd";
502*0Sstevel@tonic-gate }
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate int
505*0Sstevel@tonic-gate engine_import(uu_list_t *args)
506*0Sstevel@tonic-gate {
507*0Sstevel@tonic-gate 	int ret, argc, i, o;
508*0Sstevel@tonic-gate 	bundle_t *b;
509*0Sstevel@tonic-gate 	char *file, *pname;
510*0Sstevel@tonic-gate 	uchar_t hash[16];
511*0Sstevel@tonic-gate 	char **argv;
512*0Sstevel@tonic-gate 	string_list_t *slp;
513*0Sstevel@tonic-gate 	boolean_t verify = B_FALSE;
514*0Sstevel@tonic-gate 	uint_t flags = SCI_GENERALLAST;
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate 	argc = uu_list_numnodes(args);
517*0Sstevel@tonic-gate 	if (argc < 1)
518*0Sstevel@tonic-gate 		return (-2);
519*0Sstevel@tonic-gate 
520*0Sstevel@tonic-gate 	argv = calloc(argc + 1, sizeof (char *));
521*0Sstevel@tonic-gate 	if (argv == NULL)
522*0Sstevel@tonic-gate 		uu_die(gettext("Out of memory.\n"));
523*0Sstevel@tonic-gate 
524*0Sstevel@tonic-gate 	for (slp = uu_list_first(args), i = 0;
525*0Sstevel@tonic-gate 	    slp != NULL;
526*0Sstevel@tonic-gate 	    slp = uu_list_next(args, slp), ++i)
527*0Sstevel@tonic-gate 		argv[i] = slp->str;
528*0Sstevel@tonic-gate 
529*0Sstevel@tonic-gate 	argv[i] = NULL;
530*0Sstevel@tonic-gate 
531*0Sstevel@tonic-gate 	opterr = 0;
532*0Sstevel@tonic-gate 	optind = 0;				/* Remember, no argv[0]. */
533*0Sstevel@tonic-gate 	for (;;) {
534*0Sstevel@tonic-gate 		o = getopt(argc, argv, "nV");
535*0Sstevel@tonic-gate 		if (o == -1)
536*0Sstevel@tonic-gate 			break;
537*0Sstevel@tonic-gate 
538*0Sstevel@tonic-gate 		switch (o) {
539*0Sstevel@tonic-gate 		case 'n':
540*0Sstevel@tonic-gate 			flags |= SCI_NOREFRESH;
541*0Sstevel@tonic-gate 			break;
542*0Sstevel@tonic-gate 
543*0Sstevel@tonic-gate 		case 'V':
544*0Sstevel@tonic-gate 			verify = B_TRUE;
545*0Sstevel@tonic-gate 			break;
546*0Sstevel@tonic-gate 
547*0Sstevel@tonic-gate 		case '?':
548*0Sstevel@tonic-gate 			free(argv);
549*0Sstevel@tonic-gate 			return (-2);
550*0Sstevel@tonic-gate 
551*0Sstevel@tonic-gate 		default:
552*0Sstevel@tonic-gate 			bad_error("getopt", o);
553*0Sstevel@tonic-gate 		}
554*0Sstevel@tonic-gate 	}
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 	argc -= optind;
557*0Sstevel@tonic-gate 	if (argc != 1) {
558*0Sstevel@tonic-gate 		free(argv);
559*0Sstevel@tonic-gate 		return (-2);
560*0Sstevel@tonic-gate 	}
561*0Sstevel@tonic-gate 
562*0Sstevel@tonic-gate 	file = argv[optind];
563*0Sstevel@tonic-gate 	free(argv);
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate 	lscf_prep_hndl();
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 	if ((ret = mhash_test_file(g_hndl, file, 0, &pname, hash)) != 0)
568*0Sstevel@tonic-gate 		return (ret);
569*0Sstevel@tonic-gate 
570*0Sstevel@tonic-gate 	/* Load */
571*0Sstevel@tonic-gate 	b = internal_bundle_new();
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate 	if (lxml_get_bundle_file(b, file, 0) != 0) {
574*0Sstevel@tonic-gate 		internal_bundle_free(b);
575*0Sstevel@tonic-gate 		return (-1);
576*0Sstevel@tonic-gate 	}
577*0Sstevel@tonic-gate 
578*0Sstevel@tonic-gate 	/* Import */
579*0Sstevel@tonic-gate 	if (lscf_bundle_import(b, file, flags) != 0) {
580*0Sstevel@tonic-gate 		internal_bundle_free(b);
581*0Sstevel@tonic-gate 		return (-1);
582*0Sstevel@tonic-gate 	}
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate 	internal_bundle_free(b);
585*0Sstevel@tonic-gate 
586*0Sstevel@tonic-gate 	if (g_verbose)
587*0Sstevel@tonic-gate 		warn(gettext("Successful import.\n"));
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 	if (pname) {
590*0Sstevel@tonic-gate 		char *errstr;
591*0Sstevel@tonic-gate 
592*0Sstevel@tonic-gate 		if (mhash_store_entry(g_hndl, pname, hash, &errstr)) {
593*0Sstevel@tonic-gate 			if (errstr)
594*0Sstevel@tonic-gate 				semerr(errstr);
595*0Sstevel@tonic-gate 			else
596*0Sstevel@tonic-gate 				semerr(gettext("Unknown error from "
597*0Sstevel@tonic-gate 					"mhash_store_entry()\n"));
598*0Sstevel@tonic-gate 		}
599*0Sstevel@tonic-gate 
600*0Sstevel@tonic-gate 		free(pname);
601*0Sstevel@tonic-gate 	}
602*0Sstevel@tonic-gate 
603*0Sstevel@tonic-gate 	/* Verify */
604*0Sstevel@tonic-gate 	if (verify)
605*0Sstevel@tonic-gate 		warn(gettext("import -V not implemented.\n"));
606*0Sstevel@tonic-gate 
607*0Sstevel@tonic-gate 	return (0);
608*0Sstevel@tonic-gate }
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate int
611*0Sstevel@tonic-gate engine_apply(const char *file)
612*0Sstevel@tonic-gate {
613*0Sstevel@tonic-gate 	int ret;
614*0Sstevel@tonic-gate 	bundle_t *b;
615*0Sstevel@tonic-gate 	char *pname;
616*0Sstevel@tonic-gate 	uchar_t hash[16];
617*0Sstevel@tonic-gate 
618*0Sstevel@tonic-gate 	lscf_prep_hndl();
619*0Sstevel@tonic-gate 
620*0Sstevel@tonic-gate 	if ((ret = mhash_test_file(g_hndl, file, 1, &pname, hash)) != 0)
621*0Sstevel@tonic-gate 		return (ret);
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate 	b = internal_bundle_new();
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate 	if (lxml_get_bundle_file(b, file, 1) != 0) {
626*0Sstevel@tonic-gate 		internal_bundle_free(b);
627*0Sstevel@tonic-gate 		return (-1);
628*0Sstevel@tonic-gate 	}
629*0Sstevel@tonic-gate 
630*0Sstevel@tonic-gate 	if (lscf_bundle_apply(b) != 0) {
631*0Sstevel@tonic-gate 		internal_bundle_free(b);
632*0Sstevel@tonic-gate 		return (-1);
633*0Sstevel@tonic-gate 	}
634*0Sstevel@tonic-gate 
635*0Sstevel@tonic-gate 	internal_bundle_free(b);
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate 	if (pname) {
638*0Sstevel@tonic-gate 		char *errstr;
639*0Sstevel@tonic-gate 		if (mhash_store_entry(g_hndl, pname, hash, &errstr))
640*0Sstevel@tonic-gate 			semerr(errstr);
641*0Sstevel@tonic-gate 
642*0Sstevel@tonic-gate 		free(pname);
643*0Sstevel@tonic-gate 	}
644*0Sstevel@tonic-gate 
645*0Sstevel@tonic-gate 	return (0);
646*0Sstevel@tonic-gate }
647*0Sstevel@tonic-gate 
648*0Sstevel@tonic-gate int
649*0Sstevel@tonic-gate engine_set(uu_list_t *args)
650*0Sstevel@tonic-gate {
651*0Sstevel@tonic-gate 	uu_list_walk_t *walk;
652*0Sstevel@tonic-gate 	string_list_t *slp;
653*0Sstevel@tonic-gate 
654*0Sstevel@tonic-gate 	if (uu_list_first(args) == NULL) {
655*0Sstevel@tonic-gate 		/* Display current options. */
656*0Sstevel@tonic-gate 		if (!g_verbose)
657*0Sstevel@tonic-gate 			(void) fputs("no", stdout);
658*0Sstevel@tonic-gate 		(void) puts("verbose");
659*0Sstevel@tonic-gate 
660*0Sstevel@tonic-gate 		return (0);
661*0Sstevel@tonic-gate 	}
662*0Sstevel@tonic-gate 
663*0Sstevel@tonic-gate 	walk = uu_list_walk_start(args, UU_DEFAULT);
664*0Sstevel@tonic-gate 	if (walk == NULL)
665*0Sstevel@tonic-gate 		uu_die(gettext("Couldn't read arguments"));
666*0Sstevel@tonic-gate 
667*0Sstevel@tonic-gate 	/* Use getopt? */
668*0Sstevel@tonic-gate 	for (slp = uu_list_walk_next(walk);
669*0Sstevel@tonic-gate 	    slp != NULL;
670*0Sstevel@tonic-gate 	    slp = uu_list_walk_next(walk)) {
671*0Sstevel@tonic-gate 		if (slp->str[0] == '-') {
672*0Sstevel@tonic-gate 			char *op;
673*0Sstevel@tonic-gate 
674*0Sstevel@tonic-gate 			for (op = &slp->str[1]; *op != '\0'; ++op) {
675*0Sstevel@tonic-gate 				switch (*op) {
676*0Sstevel@tonic-gate 				case 'v':
677*0Sstevel@tonic-gate 					g_verbose = 1;
678*0Sstevel@tonic-gate 					break;
679*0Sstevel@tonic-gate 
680*0Sstevel@tonic-gate 				case 'V':
681*0Sstevel@tonic-gate 					g_verbose = 0;
682*0Sstevel@tonic-gate 					break;
683*0Sstevel@tonic-gate 
684*0Sstevel@tonic-gate 				default:
685*0Sstevel@tonic-gate 					warn(gettext("Unknown option -%c.\n"),
686*0Sstevel@tonic-gate 					    *op);
687*0Sstevel@tonic-gate 				}
688*0Sstevel@tonic-gate 			}
689*0Sstevel@tonic-gate 		} else {
690*0Sstevel@tonic-gate 			warn(gettext("No non-flag arguments defined.\n"));
691*0Sstevel@tonic-gate 		}
692*0Sstevel@tonic-gate 	}
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate 	return (0);
695*0Sstevel@tonic-gate }
696*0Sstevel@tonic-gate 
697*0Sstevel@tonic-gate void
698*0Sstevel@tonic-gate help(int com)
699*0Sstevel@tonic-gate {
700*0Sstevel@tonic-gate 	int i;
701*0Sstevel@tonic-gate 
702*0Sstevel@tonic-gate 	if (com == 0) {
703*0Sstevel@tonic-gate 		warn(gettext("General commands:	 help set repository end\n"
704*0Sstevel@tonic-gate 		    "Manifest commands:	 inventory validate import export "
705*0Sstevel@tonic-gate 		    "archive\n"
706*0Sstevel@tonic-gate 		    "Profile commands:	 apply extract\n"
707*0Sstevel@tonic-gate 		    "Entity commands:	 list select unselect add delete\n"
708*0Sstevel@tonic-gate 		    "Snapshot commands:	 listsnap selectsnap revert\n"
709*0Sstevel@tonic-gate 		    "Property group commands: listpg addpg delpg\n"
710*0Sstevel@tonic-gate 		    "Property commands:	 listprop setprop delprop editprop\n"
711*0Sstevel@tonic-gate 		    "Property value commands: addpropvalue delpropvalue "
712*0Sstevel@tonic-gate 		    "setenv unsetenv\n"));
713*0Sstevel@tonic-gate 		return;
714*0Sstevel@tonic-gate 	}
715*0Sstevel@tonic-gate 
716*0Sstevel@tonic-gate 	for (i = 0; help_messages[i].message != NULL; ++i) {
717*0Sstevel@tonic-gate 		if (help_messages[i].token == com) {
718*0Sstevel@tonic-gate 			warn(gettext("Usage: %s\n"),
719*0Sstevel@tonic-gate 			    gettext(help_messages[i].message));
720*0Sstevel@tonic-gate 			return;
721*0Sstevel@tonic-gate 		}
722*0Sstevel@tonic-gate 	}
723*0Sstevel@tonic-gate 
724*0Sstevel@tonic-gate 	warn(gettext("Unknown command.\n"));
725*0Sstevel@tonic-gate }
726