xref: /illumos-gate/usr/src/cmd/streams/strcmd/strchg.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
24*7c478bd9Sstevel@tonic-gate 
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate #ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.6	*/
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate /*
29*7c478bd9Sstevel@tonic-gate  * Streams Command strchg:	change the configuration of the
30*7c478bd9Sstevel@tonic-gate  *				stream associated with stdin.
31*7c478bd9Sstevel@tonic-gate  *
32*7c478bd9Sstevel@tonic-gate  * USAGE:	strchg -h module1[,module2,module3 ...]
33*7c478bd9Sstevel@tonic-gate  *    or:	strchg -p
34*7c478bd9Sstevel@tonic-gate  *    or:	strchg -p -a
35*7c478bd9Sstevel@tonic-gate  *    or:	strchg -p -u module
36*7c478bd9Sstevel@tonic-gate  *    or:	strchg -f file
37*7c478bd9Sstevel@tonic-gate  *
38*7c478bd9Sstevel@tonic-gate  * -h		pusHes the named module(s) onto the stdin stream
39*7c478bd9Sstevel@tonic-gate  * -p		poPs the topmost module from the stdin stream
40*7c478bd9Sstevel@tonic-gate  * -p -a	poPs All modules
41*7c478bd9Sstevel@tonic-gate  * -p -u module	poPs all modules Up to, but not including, the named module
42*7c478bd9Sstevel@tonic-gate  * -f file	reads a list of modules from the named File, pops all modules,
43*7c478bd9Sstevel@tonic-gate  *		then pushes the list of modules
44*7c478bd9Sstevel@tonic-gate  *
45*7c478bd9Sstevel@tonic-gate  * RETURNS:
46*7c478bd9Sstevel@tonic-gate  *	0	SUCCESS		it worked
47*7c478bd9Sstevel@tonic-gate  *	1	ERR_USAGE	bad invocation
48*7c478bd9Sstevel@tonic-gate  *	2	ERR_MODULE	bad module name(s)
49*7c478bd9Sstevel@tonic-gate  *	3	ERR_STDIN	an ioctl or stat on the stdin stream failed
50*7c478bd9Sstevel@tonic-gate  *	4	ERR_MEM		couldn't allocate memory
51*7c478bd9Sstevel@tonic-gate  *	5	ERR_OPEN	couldn't open file in -f opt
52*7c478bd9Sstevel@tonic-gate  *	6	ERR_PERM	not owner or superuser
53*7c478bd9Sstevel@tonic-gate  *
54*7c478bd9Sstevel@tonic-gate  */
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate #include	<stdio.h>
58*7c478bd9Sstevel@tonic-gate #include	<sys/stropts.h>
59*7c478bd9Sstevel@tonic-gate #include	<sys/termio.h>
60*7c478bd9Sstevel@tonic-gate #include	<sys/types.h>
61*7c478bd9Sstevel@tonic-gate #include	<sys/stat.h>
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate #define FALSE		0
64*7c478bd9Sstevel@tonic-gate #define	TRUE		1
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate #define SUCCESS		0
67*7c478bd9Sstevel@tonic-gate #define FAILURE		1
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate #define	NMODULES	16	/* "reasonable" # of modules to push	  */
70*7c478bd9Sstevel@tonic-gate 				/* 	(can push more if you like)	  */
71*7c478bd9Sstevel@tonic-gate #define	MAXMODULES	2048	/* max # of modules to push		  */
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate #define	OPTLIST		"af:h:pu:"
74*7c478bd9Sstevel@tonic-gate #define	USAGE		"Usage:\t%s -h module1[,module2 ... ]\n\t%s -f file\n\t%s -p [-a | -u module ]\n"
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate #define	ERR_USAGE	1	/* bad invocation			  */
77*7c478bd9Sstevel@tonic-gate #define	ERR_MODULE	2	/* bad module name(s) or too many modules */
78*7c478bd9Sstevel@tonic-gate #define	ERR_STDIN	3	/* an ioctl or stat on stdin failed	  */
79*7c478bd9Sstevel@tonic-gate #define	ERR_MEM		4	/* couldn't allocate memory		  */
80*7c478bd9Sstevel@tonic-gate #define	ERR_OPEN	5	/* couldn't open file in -f opt		  */
81*7c478bd9Sstevel@tonic-gate #define	ERR_PERM	6	/* not owner or superuser		  */
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate #define	STDIN		0
84*7c478bd9Sstevel@tonic-gate #define	CNULL		(char *)NULL
85*7c478bd9Sstevel@tonic-gate #define	SAME		0	/* return from str[n]cmp if match	*/
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate static char		 *Cmd_namep;		/* how was it invoked?	*/
88*7c478bd9Sstevel@tonic-gate static struct str_mlist	Oldmods[NMODULES];	/* modlist for Oldlist	*/
89*7c478bd9Sstevel@tonic-gate static struct str_list	Oldlist;		/* original modules	*/
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate extern char		*strncpy();
92*7c478bd9Sstevel@tonic-gate extern char		*strtok();
93*7c478bd9Sstevel@tonic-gate extern int		getopt();
94*7c478bd9Sstevel@tonic-gate extern unsigned short	geteuid();
95*7c478bd9Sstevel@tonic-gate extern int		ioctl();
96*7c478bd9Sstevel@tonic-gate extern int		strncmp();
97*7c478bd9Sstevel@tonic-gate extern void		perror();
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate static int	pop_modules();	/* pop 'n' modules		*/
100*7c478bd9Sstevel@tonic-gate static int	push_module();	/* push a module		*/
101*7c478bd9Sstevel@tonic-gate static int	more_modules();	/* increase size of mod lists	*/
102*7c478bd9Sstevel@tonic-gate static void	restore();	/* restore state of stdin	*/
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate main( argc, argv)
105*7c478bd9Sstevel@tonic-gate int	argc;
106*7c478bd9Sstevel@tonic-gate char	*argv[];
107*7c478bd9Sstevel@tonic-gate {
108*7c478bd9Sstevel@tonic-gate 	char		buf[BUFSIZ];	/* input buffer			*/
109*7c478bd9Sstevel@tonic-gate 	char 		*file_namep;	/* file from -f opt		*/
110*7c478bd9Sstevel@tonic-gate 	char		*modnamep;	/* mods from -h or -u opt	*/
111*7c478bd9Sstevel@tonic-gate 	char		*modp;		/* for walking thru modnamep	*/
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 	FILE		*fp;		/* file pointer for -f file	*/
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate 	register int	i;		/* loop index and junk var	*/
116*7c478bd9Sstevel@tonic-gate 	register int	j;		/* loop index and junk var	*/
117*7c478bd9Sstevel@tonic-gate 	int		euid;		/* effective uid		*/
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate 	short		error;		/* TRUE if usage error		*/
120*7c478bd9Sstevel@tonic-gate 	short		fromfile;	/* TRUE if -f file		*/
121*7c478bd9Sstevel@tonic-gate 	short		is_a_tty;	/* TRUE if TCGETA succeeds	*/
122*7c478bd9Sstevel@tonic-gate 	short		pop;		/* TRUE if -p			*/
123*7c478bd9Sstevel@tonic-gate 	short		popall;		/* TRUE if -p -a		*/
124*7c478bd9Sstevel@tonic-gate 	short		popupto;	/* TRUE if -p -u module		*/
125*7c478bd9Sstevel@tonic-gate 	short		push;		/* TRUE if -h mod1[,mod2 ...]	*/
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate 	struct str_mlist
128*7c478bd9Sstevel@tonic-gate 			newmods[NMODULES];/* mod list for new list	*/
129*7c478bd9Sstevel@tonic-gate 	struct stat	stats;		/* stream stats			*/
130*7c478bd9Sstevel@tonic-gate 	struct str_list	newlist;	/* modules to be pushed		*/
131*7c478bd9Sstevel@tonic-gate 	struct termio	termio;		/* save state of tty		*/
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	extern char	*optarg;	/* for getopt()			*/
134*7c478bd9Sstevel@tonic-gate 	extern int	optind;		/* for getopt()			*/
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate 	/*
137*7c478bd9Sstevel@tonic-gate 	 *	init
138*7c478bd9Sstevel@tonic-gate 	 */
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 	Cmd_namep = argv[0];
141*7c478bd9Sstevel@tonic-gate 	error = fromfile = is_a_tty = pop = popall = popupto = push = FALSE;
142*7c478bd9Sstevel@tonic-gate 	Oldlist.sl_modlist = Oldmods;
143*7c478bd9Sstevel@tonic-gate 	Oldlist.sl_nmods = NMODULES;
144*7c478bd9Sstevel@tonic-gate 	newlist.sl_modlist = newmods;
145*7c478bd9Sstevel@tonic-gate 	newlist.sl_nmods = NMODULES;
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	/*
148*7c478bd9Sstevel@tonic-gate 	 *	only owner and root can change stream configuration
149*7c478bd9Sstevel@tonic-gate 	 */
150*7c478bd9Sstevel@tonic-gate 	if ( (euid = geteuid()) != 0 ) {
151*7c478bd9Sstevel@tonic-gate 		if ( fstat(0, &stats) < 0 ) {
152*7c478bd9Sstevel@tonic-gate 			perror("fstat");
153*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: fstat of stdin failed\n",
154*7c478bd9Sstevel@tonic-gate 				Cmd_namep);
155*7c478bd9Sstevel@tonic-gate 			return(ERR_STDIN);
156*7c478bd9Sstevel@tonic-gate 		}
157*7c478bd9Sstevel@tonic-gate 		if ( euid != stats.st_uid ) {
158*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
159*7c478bd9Sstevel@tonic-gate 				"%s: not owner of stdin\n", Cmd_namep);
160*7c478bd9Sstevel@tonic-gate 			return(ERR_PERM);
161*7c478bd9Sstevel@tonic-gate 		}
162*7c478bd9Sstevel@tonic-gate 	}
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	/*
166*7c478bd9Sstevel@tonic-gate 	 *	parse args
167*7c478bd9Sstevel@tonic-gate 	 */
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 	if ( argc == 1 ) {
170*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, USAGE, Cmd_namep, Cmd_namep, Cmd_namep);
171*7c478bd9Sstevel@tonic-gate 		return(ERR_USAGE);
172*7c478bd9Sstevel@tonic-gate 	}
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 	while ( !error && (i = getopt( argc, argv, OPTLIST)) != -1 ) {
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 		switch (i) {
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 		case 'a':				/* pop All	*/
179*7c478bd9Sstevel@tonic-gate 			if ( fromfile || popupto || push )
180*7c478bd9Sstevel@tonic-gate 				error = TRUE;
181*7c478bd9Sstevel@tonic-gate 			else
182*7c478bd9Sstevel@tonic-gate 				popall = TRUE;
183*7c478bd9Sstevel@tonic-gate 			break;
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate 		case 'f':				/* read from File*/
186*7c478bd9Sstevel@tonic-gate 			if ( pop || push )
187*7c478bd9Sstevel@tonic-gate 				error = TRUE;
188*7c478bd9Sstevel@tonic-gate 			else {
189*7c478bd9Sstevel@tonic-gate 				fromfile = TRUE;
190*7c478bd9Sstevel@tonic-gate 				file_namep = optarg;
191*7c478bd9Sstevel@tonic-gate 			}
192*7c478bd9Sstevel@tonic-gate 			break;
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 		case 'h':				/* pusH		*/
195*7c478bd9Sstevel@tonic-gate 			if ( fromfile || pop )
196*7c478bd9Sstevel@tonic-gate 				error = TRUE;
197*7c478bd9Sstevel@tonic-gate 			else {
198*7c478bd9Sstevel@tonic-gate 				push = TRUE;
199*7c478bd9Sstevel@tonic-gate 				modnamep = optarg;
200*7c478bd9Sstevel@tonic-gate 			}
201*7c478bd9Sstevel@tonic-gate 			break;
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 		case 'p':				/* poP		*/
204*7c478bd9Sstevel@tonic-gate 			if ( fromfile || push )
205*7c478bd9Sstevel@tonic-gate 				error = TRUE;
206*7c478bd9Sstevel@tonic-gate 			else
207*7c478bd9Sstevel@tonic-gate 				pop = TRUE;
208*7c478bd9Sstevel@tonic-gate 			break;
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate 		case 'u':				/* pop Upto	*/
211*7c478bd9Sstevel@tonic-gate 			if ( fromfile || popall || push )
212*7c478bd9Sstevel@tonic-gate 				error = TRUE;
213*7c478bd9Sstevel@tonic-gate 			else {
214*7c478bd9Sstevel@tonic-gate 				popupto = TRUE;
215*7c478bd9Sstevel@tonic-gate 				modnamep = optarg;
216*7c478bd9Sstevel@tonic-gate 			}
217*7c478bd9Sstevel@tonic-gate 			break;
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 		default:
220*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
221*7c478bd9Sstevel@tonic-gate 				USAGE, Cmd_namep, Cmd_namep, Cmd_namep);
222*7c478bd9Sstevel@tonic-gate 			return(ERR_USAGE);
223*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
224*7c478bd9Sstevel@tonic-gate 		}
225*7c478bd9Sstevel@tonic-gate 	}
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 	if ( error || optind < argc )  {
228*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, USAGE, Cmd_namep, Cmd_namep, Cmd_namep);
229*7c478bd9Sstevel@tonic-gate 		return(ERR_USAGE);
230*7c478bd9Sstevel@tonic-gate 	}
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	if ( !pop && ( popall || popupto ) ) {
233*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
234*7c478bd9Sstevel@tonic-gate 			"%s: -p option must be used with -a or -u to pop modules\n",
235*7c478bd9Sstevel@tonic-gate 			Cmd_namep);
236*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, USAGE, Cmd_namep, Cmd_namep, Cmd_namep);
237*7c478bd9Sstevel@tonic-gate 		return(ERR_USAGE);
238*7c478bd9Sstevel@tonic-gate 	}
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 	/*
242*7c478bd9Sstevel@tonic-gate 	 * Save state so can restore if something goes wrong
243*7c478bd9Sstevel@tonic-gate 	 * (If are only going to push modules, don't need to
244*7c478bd9Sstevel@tonic-gate 	 * save original module list for restore.)
245*7c478bd9Sstevel@tonic-gate 	 */
246*7c478bd9Sstevel@tonic-gate 	if ( fromfile || pop ) {
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate 		/*
249*7c478bd9Sstevel@tonic-gate 		 * get number of modules on stream
250*7c478bd9Sstevel@tonic-gate 		 * allocate more room if needed
251*7c478bd9Sstevel@tonic-gate 		 */
252*7c478bd9Sstevel@tonic-gate 		if ( (i =  ioctl(STDIN, I_LIST, (struct str_list *)NULL))
253*7c478bd9Sstevel@tonic-gate 		 < 0 ) {
254*7c478bd9Sstevel@tonic-gate 			perror("I_LIST");
255*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
256*7c478bd9Sstevel@tonic-gate 				"%s: I_LIST ioctl failed\n", Cmd_namep);
257*7c478bd9Sstevel@tonic-gate 			return(ERR_STDIN);
258*7c478bd9Sstevel@tonic-gate 		}
259*7c478bd9Sstevel@tonic-gate 		if ( i > Oldlist.sl_nmods )
260*7c478bd9Sstevel@tonic-gate 			if ( more_modules(&Oldlist, i) != SUCCESS )
261*7c478bd9Sstevel@tonic-gate 				return(ERR_MEM);
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 		/*
264*7c478bd9Sstevel@tonic-gate 		 * get list of modules on stream
265*7c478bd9Sstevel@tonic-gate 		 */
266*7c478bd9Sstevel@tonic-gate 		Oldlist.sl_nmods = i;
267*7c478bd9Sstevel@tonic-gate 		if ( ioctl(STDIN, I_LIST, &Oldlist) < 0 ) {
268*7c478bd9Sstevel@tonic-gate 			perror("I_LIST");
269*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
270*7c478bd9Sstevel@tonic-gate 				"%s: I_LIST ioctl failed\n", Cmd_namep);
271*7c478bd9Sstevel@tonic-gate 			return(ERR_STDIN);
272*7c478bd9Sstevel@tonic-gate 		}
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 		/*
275*7c478bd9Sstevel@tonic-gate 		 * The following attempts to avoid leaving a
276*7c478bd9Sstevel@tonic-gate 		 * terminal line that does not respond to anything
277*7c478bd9Sstevel@tonic-gate 		 * if the strchg -h or -f options failed due to
278*7c478bd9Sstevel@tonic-gate 		 * specifying invalid module names for pushing
279*7c478bd9Sstevel@tonic-gate 		 */
280*7c478bd9Sstevel@tonic-gate 		if (ioctl(STDIN, TCGETA, &termio) >= 0 )
281*7c478bd9Sstevel@tonic-gate 			is_a_tty = TRUE;
282*7c478bd9Sstevel@tonic-gate 	}
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 	/*
286*7c478bd9Sstevel@tonic-gate 	 *	push modules on stream
287*7c478bd9Sstevel@tonic-gate 	 */
288*7c478bd9Sstevel@tonic-gate 	if ( push ) {
289*7c478bd9Sstevel@tonic-gate 		/*
290*7c478bd9Sstevel@tonic-gate 		 * pull mod names out of comma-separated list
291*7c478bd9Sstevel@tonic-gate 		 */
292*7c478bd9Sstevel@tonic-gate 		for ( i = 0, modp = strtok(modnamep, ",");
293*7c478bd9Sstevel@tonic-gate 		modp != CNULL; ++i, modp = strtok(CNULL, ",") ) {
294*7c478bd9Sstevel@tonic-gate 			if ( push_module(modp) == FAILURE) {
295*7c478bd9Sstevel@tonic-gate 				/* pop the 'i' modules we just added */
296*7c478bd9Sstevel@tonic-gate 				restore(i, 0);
297*7c478bd9Sstevel@tonic-gate 				return(ERR_STDIN);
298*7c478bd9Sstevel@tonic-gate 			}
299*7c478bd9Sstevel@tonic-gate 		}
300*7c478bd9Sstevel@tonic-gate 		return(SUCCESS);
301*7c478bd9Sstevel@tonic-gate 	}
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	/*
304*7c478bd9Sstevel@tonic-gate 	 *	read configuration from a file
305*7c478bd9Sstevel@tonic-gate 	 */
306*7c478bd9Sstevel@tonic-gate 	if ( fromfile ) {
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 		if ( (fp = fopen(file_namep, "r")) == (FILE *)NULL ) {
309*7c478bd9Sstevel@tonic-gate 			perror("fopen");
310*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
311*7c478bd9Sstevel@tonic-gate 				"%s: could not open file '%s'\n",
312*7c478bd9Sstevel@tonic-gate 				Cmd_namep, file_namep);
313*7c478bd9Sstevel@tonic-gate 			return(ERR_OPEN);
314*7c478bd9Sstevel@tonic-gate 		}
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 		/*
317*7c478bd9Sstevel@tonic-gate 		 * read file and construct a new strlist
318*7c478bd9Sstevel@tonic-gate 		 */
319*7c478bd9Sstevel@tonic-gate 		i = 0;
320*7c478bd9Sstevel@tonic-gate 		while ( fgets(buf, BUFSIZ, fp) != CNULL ) {
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 			if ( buf[0] == '#' )
323*7c478bd9Sstevel@tonic-gate 				continue;	/* skip comments */
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 			/*
326*7c478bd9Sstevel@tonic-gate 			 * skip trailing newline, trailing and leading
327*7c478bd9Sstevel@tonic-gate 			 * whitespace
328*7c478bd9Sstevel@tonic-gate 			 */
329*7c478bd9Sstevel@tonic-gate 			if ( (modp = strtok(buf, " \t\n")) == CNULL )
330*7c478bd9Sstevel@tonic-gate 				continue;	/* blank line */
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 			(void)strncpy(newlist.sl_modlist[i].l_name,
333*7c478bd9Sstevel@tonic-gate 							modp, FMNAMESZ);
334*7c478bd9Sstevel@tonic-gate 			++i;
335*7c478bd9Sstevel@tonic-gate 			if ( (modp = strtok(CNULL, " \t\n")) != CNULL ) {
336*7c478bd9Sstevel@tonic-gate 				/*
337*7c478bd9Sstevel@tonic-gate 				 * bad format
338*7c478bd9Sstevel@tonic-gate 				 * should only be one name per line
339*7c478bd9Sstevel@tonic-gate 				 */
340*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
341*7c478bd9Sstevel@tonic-gate 				"%s: error on line %d in file %s: multiple module names??\n",
342*7c478bd9Sstevel@tonic-gate 				Cmd_namep, i, file_namep);
343*7c478bd9Sstevel@tonic-gate 				return(ERR_MODULE);
344*7c478bd9Sstevel@tonic-gate 			}
345*7c478bd9Sstevel@tonic-gate 			if ( i > newlist.sl_nmods )
346*7c478bd9Sstevel@tonic-gate 				if ( more_modules(&newlist, i) != SUCCESS )
347*7c478bd9Sstevel@tonic-gate 					return(ERR_MEM);
348*7c478bd9Sstevel@tonic-gate 		}
349*7c478bd9Sstevel@tonic-gate 		newlist.sl_nmods = i;
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 		/*
352*7c478bd9Sstevel@tonic-gate 		 * If an empty file, exit silently
353*7c478bd9Sstevel@tonic-gate 		 */
354*7c478bd9Sstevel@tonic-gate 		if ( i == 0 )
355*7c478bd9Sstevel@tonic-gate 			return(SUCCESS);
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 		/*
358*7c478bd9Sstevel@tonic-gate 		 * Pop all modules currently on the stream.
359*7c478bd9Sstevel@tonic-gate 		 */
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 		if ( (i = pop_modules(Oldlist.sl_nmods - 1))
362*7c478bd9Sstevel@tonic-gate 		!= (Oldlist.sl_nmods - 1) ) {
363*7c478bd9Sstevel@tonic-gate 			/* put back whatever we've popped */
364*7c478bd9Sstevel@tonic-gate 			restore(0, i);
365*7c478bd9Sstevel@tonic-gate 			return(ERR_STDIN);
366*7c478bd9Sstevel@tonic-gate 		}
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 		/*
369*7c478bd9Sstevel@tonic-gate 		 * Push new modules
370*7c478bd9Sstevel@tonic-gate 		 */
371*7c478bd9Sstevel@tonic-gate 		for ( i = newlist.sl_nmods - 1; i >= 0; --i ) {
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 			if ( push_module(newlist.sl_modlist[i].l_name)
374*7c478bd9Sstevel@tonic-gate 			== FAILURE ) {
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate 				/*
377*7c478bd9Sstevel@tonic-gate 				 * pop whatever new modules we've pushed
378*7c478bd9Sstevel@tonic-gate 				 * then push old module list back on
379*7c478bd9Sstevel@tonic-gate 				 */
380*7c478bd9Sstevel@tonic-gate 				restore((newlist.sl_nmods - 1 - i),
381*7c478bd9Sstevel@tonic-gate 						(Oldlist.sl_nmods - 1));
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 				/*
384*7c478bd9Sstevel@tonic-gate 				 * If the stream is a tty line, at least try
385*7c478bd9Sstevel@tonic-gate 				 * to set the state to what it was before.
386*7c478bd9Sstevel@tonic-gate 				 */
387*7c478bd9Sstevel@tonic-gate 				if ( is_a_tty ) {
388*7c478bd9Sstevel@tonic-gate 					if ( ioctl(STDIN, TCSETA, &termio) < 0 ) {
389*7c478bd9Sstevel@tonic-gate 						perror("TCSETA");
390*7c478bd9Sstevel@tonic-gate 						(void) fprintf(stderr,
391*7c478bd9Sstevel@tonic-gate 						"%s: WARNING: Could not restore the states of the terminal line discipline\n",
392*7c478bd9Sstevel@tonic-gate 						Cmd_namep);
393*7c478bd9Sstevel@tonic-gate 					}
394*7c478bd9Sstevel@tonic-gate 				}
395*7c478bd9Sstevel@tonic-gate 				return(ERR_STDIN);
396*7c478bd9Sstevel@tonic-gate 			}
397*7c478bd9Sstevel@tonic-gate 		}
398*7c478bd9Sstevel@tonic-gate 		return(SUCCESS);
399*7c478bd9Sstevel@tonic-gate 	}	/* end if-fromfile */
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate 	/*
403*7c478bd9Sstevel@tonic-gate 	 *	pop all modules (except driver)
404*7c478bd9Sstevel@tonic-gate 	 */
405*7c478bd9Sstevel@tonic-gate 	if ( popall ) {
406*7c478bd9Sstevel@tonic-gate 		if ( Oldlist.sl_nmods > 1 ) {
407*7c478bd9Sstevel@tonic-gate 			if ( (i = pop_modules(Oldlist.sl_nmods - 1))
408*7c478bd9Sstevel@tonic-gate 			!= (Oldlist.sl_nmods - 1) ) {
409*7c478bd9Sstevel@tonic-gate 				restore(0, i);
410*7c478bd9Sstevel@tonic-gate 				return(ERR_STDIN);
411*7c478bd9Sstevel@tonic-gate 			}
412*7c478bd9Sstevel@tonic-gate 		}
413*7c478bd9Sstevel@tonic-gate 		return(SUCCESS);
414*7c478bd9Sstevel@tonic-gate 	}
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate 	/*
417*7c478bd9Sstevel@tonic-gate 	 *	pop up to (but not including) a module
418*7c478bd9Sstevel@tonic-gate 	 */
419*7c478bd9Sstevel@tonic-gate 	if ( popupto ) {
420*7c478bd9Sstevel@tonic-gate 		/*
421*7c478bd9Sstevel@tonic-gate 		 * check that the module is in fact on the stream
422*7c478bd9Sstevel@tonic-gate 		 */
423*7c478bd9Sstevel@tonic-gate 		for ( i = 0; i < Oldlist.sl_nmods; ++i )
424*7c478bd9Sstevel@tonic-gate 			if ( strncmp(Oldlist.sl_modlist[i].l_name, modnamep,
425*7c478bd9Sstevel@tonic-gate 							FMNAMESZ) == SAME )
426*7c478bd9Sstevel@tonic-gate 				break;
427*7c478bd9Sstevel@tonic-gate 		if ( i == Oldlist.sl_nmods ) {
428*7c478bd9Sstevel@tonic-gate 			/* no match found */
429*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: %s not found on stream\n",
430*7c478bd9Sstevel@tonic-gate 							Cmd_namep, modnamep);
431*7c478bd9Sstevel@tonic-gate 			return(ERR_MODULE);
432*7c478bd9Sstevel@tonic-gate 		}
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 		if ( (j = pop_modules(i)) != i ) {
435*7c478bd9Sstevel@tonic-gate 			/* put back whatever we've popped */
436*7c478bd9Sstevel@tonic-gate 			restore(0, j);
437*7c478bd9Sstevel@tonic-gate 			return(ERR_STDIN);
438*7c478bd9Sstevel@tonic-gate 		}
439*7c478bd9Sstevel@tonic-gate 		return(SUCCESS);
440*7c478bd9Sstevel@tonic-gate 	}
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 	/*
443*7c478bd9Sstevel@tonic-gate 	 *	pop the topmost module
444*7c478bd9Sstevel@tonic-gate 	 */
445*7c478bd9Sstevel@tonic-gate 	if ( pop ) {
446*7c478bd9Sstevel@tonic-gate 		if ( Oldlist.sl_nmods > 1 )
447*7c478bd9Sstevel@tonic-gate 			if ( pop_modules(1) != 1 )
448*7c478bd9Sstevel@tonic-gate 				/* no need to restore */
449*7c478bd9Sstevel@tonic-gate 				return(ERR_STDIN);
450*7c478bd9Sstevel@tonic-gate 		return(SUCCESS);
451*7c478bd9Sstevel@tonic-gate 	}
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
454*7c478bd9Sstevel@tonic-gate }
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate /*
457*7c478bd9Sstevel@tonic-gate  * pop_module(n)		pop 'n' modules from stream
458*7c478bd9Sstevel@tonic-gate  *
459*7c478bd9Sstevel@tonic-gate  * returns # of modules popped
460*7c478bd9Sstevel@tonic-gate  */
461*7c478bd9Sstevel@tonic-gate static int
462*7c478bd9Sstevel@tonic-gate pop_modules(num_modules)
463*7c478bd9Sstevel@tonic-gate int num_modules;
464*7c478bd9Sstevel@tonic-gate {
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate 	register short i;	/* the ubiquitous loop variable */
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 	for ( i = 0; i < num_modules; i++ ) {
469*7c478bd9Sstevel@tonic-gate 		if ( ioctl(STDIN, I_POP, 0) < 0 ) {
470*7c478bd9Sstevel@tonic-gate 			perror("I_POP");
471*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
472*7c478bd9Sstevel@tonic-gate 				"%s: I_POP ioctl failed\n", Cmd_namep);
473*7c478bd9Sstevel@tonic-gate 			return(i);
474*7c478bd9Sstevel@tonic-gate 		}
475*7c478bd9Sstevel@tonic-gate 	}
476*7c478bd9Sstevel@tonic-gate 	return(i);
477*7c478bd9Sstevel@tonic-gate }
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate /*
480*7c478bd9Sstevel@tonic-gate  * push_module(modnamep)	pushes 'modnamep' module on stream
481*7c478bd9Sstevel@tonic-gate  *
482*7c478bd9Sstevel@tonic-gate  * returns SUCCESS or FAILURE
483*7c478bd9Sstevel@tonic-gate  */
484*7c478bd9Sstevel@tonic-gate static int
485*7c478bd9Sstevel@tonic-gate push_module(modnamep)
486*7c478bd9Sstevel@tonic-gate char *modnamep;
487*7c478bd9Sstevel@tonic-gate {
488*7c478bd9Sstevel@tonic-gate 	if ( ioctl(STDIN, I_PUSH, modnamep) < 0 ) {
489*7c478bd9Sstevel@tonic-gate 		perror("I_PUSH");
490*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
491*7c478bd9Sstevel@tonic-gate 			"%s: I_PUSH ioctl of %s failed\n", Cmd_namep, modnamep);
492*7c478bd9Sstevel@tonic-gate 		return(FAILURE);
493*7c478bd9Sstevel@tonic-gate 	}
494*7c478bd9Sstevel@tonic-gate 	return (SUCCESS);
495*7c478bd9Sstevel@tonic-gate }
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate /*
499*7c478bd9Sstevel@tonic-gate  * restore(npop, npush)		restore original state of stream
500*7c478bd9Sstevel@tonic-gate  *
501*7c478bd9Sstevel@tonic-gate  * pops 'npop' modules, then pushes the topmost 'npush' modules from
502*7c478bd9Sstevel@tonic-gate  * Oldlist
503*7c478bd9Sstevel@tonic-gate  *
504*7c478bd9Sstevel@tonic-gate  */
505*7c478bd9Sstevel@tonic-gate static void
506*7c478bd9Sstevel@tonic-gate restore(npop, npush)
507*7c478bd9Sstevel@tonic-gate int	npop;
508*7c478bd9Sstevel@tonic-gate int	npush;
509*7c478bd9Sstevel@tonic-gate {
510*7c478bd9Sstevel@tonic-gate 	register int	i;
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 	if ( (i = pop_modules(npop)) != npop ) {
513*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
514*7c478bd9Sstevel@tonic-gate 		"%s: WARNING: could not restore state of stream\n", Cmd_namep);
515*7c478bd9Sstevel@tonic-gate 		return;
516*7c478bd9Sstevel@tonic-gate 	}
517*7c478bd9Sstevel@tonic-gate 	if ( npush >= Oldlist.sl_nmods ) {	/* "cannot" happen */
518*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
519*7c478bd9Sstevel@tonic-gate 		"%s: internal logic error in restore\n", Cmd_namep);
520*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
521*7c478bd9Sstevel@tonic-gate 		"%s: WARNING: could not restore state of stream\n", Cmd_namep);
522*7c478bd9Sstevel@tonic-gate 		return;
523*7c478bd9Sstevel@tonic-gate 	}
524*7c478bd9Sstevel@tonic-gate 	for ( i = npush - 1; i >= 0; --i ) {
525*7c478bd9Sstevel@tonic-gate 		if ( push_module(Oldlist.sl_modlist[i].l_name) == FAILURE ) {
526*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
527*7c478bd9Sstevel@tonic-gate 			"%s: WARNING: could not restore state of stream\n",
528*7c478bd9Sstevel@tonic-gate 			Cmd_namep);
529*7c478bd9Sstevel@tonic-gate 			return;
530*7c478bd9Sstevel@tonic-gate 		}
531*7c478bd9Sstevel@tonic-gate 	}
532*7c478bd9Sstevel@tonic-gate 	return;
533*7c478bd9Sstevel@tonic-gate }
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate /*
536*7c478bd9Sstevel@tonic-gate  * more_modules(listp, n)	allocate space for 'n' modules in 'listp'
537*7c478bd9Sstevel@tonic-gate  *
538*7c478bd9Sstevel@tonic-gate  * returns:	SUCCESS or FAILURE
539*7c478bd9Sstevel@tonic-gate  */
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate static int
542*7c478bd9Sstevel@tonic-gate more_modules(listp, n)
543*7c478bd9Sstevel@tonic-gate struct str_list	*listp;		/* streams module list	*/
544*7c478bd9Sstevel@tonic-gate int		n;		/* # of modules		*/
545*7c478bd9Sstevel@tonic-gate {
546*7c478bd9Sstevel@tonic-gate 	register int			i;
547*7c478bd9Sstevel@tonic-gate 	register struct str_mlist	*modp;
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate 	extern char	*calloc();
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 	if ( n > MAXMODULES ) {
552*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
553*7c478bd9Sstevel@tonic-gate 			"%s: too many modules (%d) -- max is %d\n",
554*7c478bd9Sstevel@tonic-gate 			Cmd_namep, n, MAXMODULES);
555*7c478bd9Sstevel@tonic-gate 		return(FAILURE);
556*7c478bd9Sstevel@tonic-gate 	}
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate 	if ( (modp = (struct str_mlist *)calloc((unsigned)n,
559*7c478bd9Sstevel@tonic-gate 	(unsigned)sizeof(struct str_mlist))) == (struct str_mlist *)NULL ) {
560*7c478bd9Sstevel@tonic-gate 		perror("calloc");
561*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
562*7c478bd9Sstevel@tonic-gate 			"%s: failed to allocate space for module list\n",
563*7c478bd9Sstevel@tonic-gate 			Cmd_namep);
564*7c478bd9Sstevel@tonic-gate 		return(FAILURE);
565*7c478bd9Sstevel@tonic-gate 	}
566*7c478bd9Sstevel@tonic-gate 
567*7c478bd9Sstevel@tonic-gate 	for ( i = 0; i < listp->sl_nmods; ++i )
568*7c478bd9Sstevel@tonic-gate 		(void) strncpy(modp[i].l_name, listp->sl_modlist[i].l_name,
569*7c478bd9Sstevel@tonic-gate 			FMNAMESZ);
570*7c478bd9Sstevel@tonic-gate 	listp->sl_nmods = n;
571*7c478bd9Sstevel@tonic-gate 	listp->sl_modlist = modp;
572*7c478bd9Sstevel@tonic-gate 	return(SUCCESS);
573*7c478bd9Sstevel@tonic-gate }
574