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