xref: /onnv-gate/usr/src/cmd/streams/strcmd/strchg.c (revision 515:484fe491001b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
22*515Smeem 
23*515Smeem /*
24*515Smeem  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25*515Smeem  * Use is subject to license terms.
26*515Smeem  */
27*515Smeem 
280Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
290Sstevel@tonic-gate /*	  All Rights Reserved  	*/
300Sstevel@tonic-gate 
31*515Smeem #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.6	*/
320Sstevel@tonic-gate 
33*515Smeem /*
340Sstevel@tonic-gate  * Streams Command strchg:	change the configuration of the
350Sstevel@tonic-gate  *				stream associated with stdin.
360Sstevel@tonic-gate  *
370Sstevel@tonic-gate  * USAGE:	strchg -h module1[,module2,module3 ...]
380Sstevel@tonic-gate  *    or:	strchg -p
390Sstevel@tonic-gate  *    or:	strchg -p -a
400Sstevel@tonic-gate  *    or:	strchg -p -u module
410Sstevel@tonic-gate  *    or:	strchg -f file
420Sstevel@tonic-gate  *
430Sstevel@tonic-gate  * -h		pusHes the named module(s) onto the stdin stream
440Sstevel@tonic-gate  * -p		poPs the topmost module from the stdin stream
450Sstevel@tonic-gate  * -p -a	poPs All modules
460Sstevel@tonic-gate  * -p -u module	poPs all modules Up to, but not including, the named module
470Sstevel@tonic-gate  * -f file	reads a list of modules from the named File, pops all modules,
480Sstevel@tonic-gate  *		then pushes the list of modules
490Sstevel@tonic-gate  *
500Sstevel@tonic-gate  * RETURNS:
510Sstevel@tonic-gate  *	0	SUCCESS		it worked
520Sstevel@tonic-gate  *	1	ERR_USAGE	bad invocation
530Sstevel@tonic-gate  *	2	ERR_MODULE	bad module name(s)
540Sstevel@tonic-gate  *	3	ERR_STDIN	an ioctl or stat on the stdin stream failed
550Sstevel@tonic-gate  *	4	ERR_MEM		couldn't allocate memory
560Sstevel@tonic-gate  *	5	ERR_OPEN	couldn't open file in -f opt
570Sstevel@tonic-gate  *	6	ERR_PERM	not owner or superuser
580Sstevel@tonic-gate  *
590Sstevel@tonic-gate  */
600Sstevel@tonic-gate 
610Sstevel@tonic-gate 
62*515Smeem #include <stdio.h>
63*515Smeem #include <sys/stropts.h>
64*515Smeem #include <sys/termio.h>
65*515Smeem #include <sys/types.h>
66*515Smeem #include <sys/stat.h>
67*515Smeem #include <string.h>
68*515Smeem #include <stdlib.h>
69*515Smeem #include <unistd.h>
700Sstevel@tonic-gate 
71*515Smeem #define	FALSE		0
720Sstevel@tonic-gate #define	TRUE		1
730Sstevel@tonic-gate 
74*515Smeem #define	SUCCESS		0
75*515Smeem #define	FAILURE		1
760Sstevel@tonic-gate 
770Sstevel@tonic-gate #define	NMODULES	16	/* "reasonable" # of modules to push	  */
780Sstevel@tonic-gate 				/* 	(can push more if you like)	  */
790Sstevel@tonic-gate #define	MAXMODULES	2048	/* max # of modules to push		  */
800Sstevel@tonic-gate 
810Sstevel@tonic-gate #define	OPTLIST		"af:h:pu:"
82*515Smeem #define	USAGE		"Usage:\t%s -h module1[,module2 ... ]\n\t%s -f file"\
83*515Smeem 			"\n\t%s -p [-a | -u module ]\n"
840Sstevel@tonic-gate 
850Sstevel@tonic-gate #define	ERR_USAGE	1	/* bad invocation			  */
860Sstevel@tonic-gate #define	ERR_MODULE	2	/* bad module name(s) or too many modules */
870Sstevel@tonic-gate #define	ERR_STDIN	3	/* an ioctl or stat on stdin failed	  */
880Sstevel@tonic-gate #define	ERR_MEM		4	/* couldn't allocate memory		  */
890Sstevel@tonic-gate #define	ERR_OPEN	5	/* couldn't open file in -f opt		  */
900Sstevel@tonic-gate #define	ERR_PERM	6	/* not owner or superuser		  */
910Sstevel@tonic-gate 
920Sstevel@tonic-gate #define	STDIN		0
930Sstevel@tonic-gate 
94*515Smeem static char		*Cmd_namep;		/* how was it invoked?	*/
950Sstevel@tonic-gate static struct str_mlist	Oldmods[NMODULES];	/* modlist for Oldlist	*/
960Sstevel@tonic-gate static struct str_list	Oldlist;		/* original modules	*/
970Sstevel@tonic-gate 
98*515Smeem static int	pop_modules(int);
99*515Smeem static int	push_module(const char *);
100*515Smeem static int	more_modules(struct str_list *, int);
101*515Smeem static void	restore(int, int);
1020Sstevel@tonic-gate 
103*515Smeem int
main(int argc,char ** argv)104*515Smeem main(int argc, char **argv)
1050Sstevel@tonic-gate {
1060Sstevel@tonic-gate 	char		buf[BUFSIZ];	/* input buffer			*/
1070Sstevel@tonic-gate 	char 		*file_namep;	/* file from -f opt		*/
1080Sstevel@tonic-gate 	char		*modnamep;	/* mods from -h or -u opt	*/
1090Sstevel@tonic-gate 	char		*modp;		/* for walking thru modnamep	*/
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate 	FILE		*fp;		/* file pointer for -f file	*/
1120Sstevel@tonic-gate 
113*515Smeem 	int		i;		/* loop index and junk var	*/
114*515Smeem 	int		j;		/* loop index and junk var	*/
1150Sstevel@tonic-gate 	int		euid;		/* effective uid		*/
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	short		error;		/* TRUE if usage error		*/
1180Sstevel@tonic-gate 	short		fromfile;	/* TRUE if -f file		*/
1190Sstevel@tonic-gate 	short		is_a_tty;	/* TRUE if TCGETA succeeds	*/
1200Sstevel@tonic-gate 	short		pop;		/* TRUE if -p			*/
1210Sstevel@tonic-gate 	short		popall;		/* TRUE if -p -a		*/
1220Sstevel@tonic-gate 	short		popupto;	/* TRUE if -p -u module		*/
1230Sstevel@tonic-gate 	short		push;		/* TRUE if -h mod1[,mod2 ...]	*/
1240Sstevel@tonic-gate 
125*515Smeem 	struct str_mlist newmods[NMODULES]; /* mod list for new list	*/
1260Sstevel@tonic-gate 	struct stat	stats;		/* stream stats			*/
1270Sstevel@tonic-gate 	struct str_list	newlist;	/* modules to be pushed		*/
1280Sstevel@tonic-gate 	struct termio	termio;		/* save state of tty		*/
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	/*
1310Sstevel@tonic-gate 	 *	init
1320Sstevel@tonic-gate 	 */
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	Cmd_namep = argv[0];
1350Sstevel@tonic-gate 	error = fromfile = is_a_tty = pop = popall = popupto = push = FALSE;
1360Sstevel@tonic-gate 	Oldlist.sl_modlist = Oldmods;
1370Sstevel@tonic-gate 	Oldlist.sl_nmods = NMODULES;
1380Sstevel@tonic-gate 	newlist.sl_modlist = newmods;
1390Sstevel@tonic-gate 	newlist.sl_nmods = NMODULES;
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	/*
1420Sstevel@tonic-gate 	 *	only owner and root can change stream configuration
1430Sstevel@tonic-gate 	 */
144*515Smeem 	if ((euid = geteuid()) != 0) {
145*515Smeem 		if (fstat(0, &stats) < 0) {
1460Sstevel@tonic-gate 			perror("fstat");
1470Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: fstat of stdin failed\n",
1480Sstevel@tonic-gate 				Cmd_namep);
149*515Smeem 			return (ERR_STDIN);
1500Sstevel@tonic-gate 		}
151*515Smeem 		if (euid != stats.st_uid) {
1520Sstevel@tonic-gate 			(void) fprintf(stderr,
1530Sstevel@tonic-gate 				"%s: not owner of stdin\n", Cmd_namep);
154*515Smeem 			return (ERR_PERM);
1550Sstevel@tonic-gate 		}
1560Sstevel@tonic-gate 	}
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 	/*
1600Sstevel@tonic-gate 	 *	parse args
1610Sstevel@tonic-gate 	 */
1620Sstevel@tonic-gate 
163*515Smeem 	if (argc == 1) {
1640Sstevel@tonic-gate 		(void) fprintf(stderr, USAGE, Cmd_namep, Cmd_namep, Cmd_namep);
165*515Smeem 		return (ERR_USAGE);
1660Sstevel@tonic-gate 	}
1670Sstevel@tonic-gate 
168*515Smeem 	while (!error && (i = getopt(argc, argv, OPTLIST)) != -1) {
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 		switch (i) {
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 		case 'a':				/* pop All	*/
173*515Smeem 			if (fromfile || popupto || push)
1740Sstevel@tonic-gate 				error = TRUE;
1750Sstevel@tonic-gate 			else
1760Sstevel@tonic-gate 				popall = TRUE;
1770Sstevel@tonic-gate 			break;
1780Sstevel@tonic-gate 
179*515Smeem 		case 'f':				/* read from File */
180*515Smeem 			if (pop || push)
1810Sstevel@tonic-gate 				error = TRUE;
1820Sstevel@tonic-gate 			else {
1830Sstevel@tonic-gate 				fromfile = TRUE;
1840Sstevel@tonic-gate 				file_namep = optarg;
1850Sstevel@tonic-gate 			}
1860Sstevel@tonic-gate 			break;
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 		case 'h':				/* pusH		*/
189*515Smeem 			if (fromfile || pop)
1900Sstevel@tonic-gate 				error = TRUE;
1910Sstevel@tonic-gate 			else {
1920Sstevel@tonic-gate 				push = TRUE;
1930Sstevel@tonic-gate 				modnamep = optarg;
1940Sstevel@tonic-gate 			}
1950Sstevel@tonic-gate 			break;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 		case 'p':				/* poP		*/
198*515Smeem 			if (fromfile || push)
1990Sstevel@tonic-gate 				error = TRUE;
2000Sstevel@tonic-gate 			else
2010Sstevel@tonic-gate 				pop = TRUE;
2020Sstevel@tonic-gate 			break;
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 		case 'u':				/* pop Upto	*/
205*515Smeem 			if (fromfile || popall || push)
2060Sstevel@tonic-gate 				error = TRUE;
2070Sstevel@tonic-gate 			else {
2080Sstevel@tonic-gate 				popupto = TRUE;
2090Sstevel@tonic-gate 				modnamep = optarg;
2100Sstevel@tonic-gate 			}
2110Sstevel@tonic-gate 			break;
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 		default:
2140Sstevel@tonic-gate 			(void) fprintf(stderr,
2150Sstevel@tonic-gate 				USAGE, Cmd_namep, Cmd_namep, Cmd_namep);
216*515Smeem 			return (ERR_USAGE);
2170Sstevel@tonic-gate 			/*NOTREACHED*/
2180Sstevel@tonic-gate 		}
2190Sstevel@tonic-gate 	}
2200Sstevel@tonic-gate 
221*515Smeem 	if (error || optind < argc)  {
2220Sstevel@tonic-gate 		(void) fprintf(stderr, USAGE, Cmd_namep, Cmd_namep, Cmd_namep);
223*515Smeem 		return (ERR_USAGE);
2240Sstevel@tonic-gate 	}
2250Sstevel@tonic-gate 
226*515Smeem 	if (!pop && (popall || popupto)) {
2270Sstevel@tonic-gate 		(void) fprintf(stderr,
228*515Smeem 		    "%s: -p option must be used with -a or -u to pop modules\n",
229*515Smeem 		    Cmd_namep);
2300Sstevel@tonic-gate 		(void) fprintf(stderr, USAGE, Cmd_namep, Cmd_namep, Cmd_namep);
231*515Smeem 		return (ERR_USAGE);
2320Sstevel@tonic-gate 	}
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	/*
2360Sstevel@tonic-gate 	 * Save state so can restore if something goes wrong
237*515Smeem 	 * (If are only going to push modules, don't need to
2380Sstevel@tonic-gate 	 * save original module list for restore.)
2390Sstevel@tonic-gate 	 */
240*515Smeem 	if (fromfile || pop) {
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 		/*
2430Sstevel@tonic-gate 		 * get number of modules on stream
2440Sstevel@tonic-gate 		 * allocate more room if needed
2450Sstevel@tonic-gate 		 */
246*515Smeem 		if ((i =  ioctl(STDIN, I_LIST, NULL)) < 0) {
2470Sstevel@tonic-gate 			perror("I_LIST");
2480Sstevel@tonic-gate 			(void) fprintf(stderr,
2490Sstevel@tonic-gate 				"%s: I_LIST ioctl failed\n", Cmd_namep);
250*515Smeem 			return (ERR_STDIN);
2510Sstevel@tonic-gate 		}
252*515Smeem 		if (i > Oldlist.sl_nmods &&
253*515Smeem 		    more_modules(&Oldlist, i) != SUCCESS)
254*515Smeem 				return (ERR_MEM);
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 		/*
2570Sstevel@tonic-gate 		 * get list of modules on stream
2580Sstevel@tonic-gate 		 */
2590Sstevel@tonic-gate 		Oldlist.sl_nmods = i;
260*515Smeem 		if (ioctl(STDIN, I_LIST, &Oldlist) < 0) {
2610Sstevel@tonic-gate 			perror("I_LIST");
2620Sstevel@tonic-gate 			(void) fprintf(stderr,
2630Sstevel@tonic-gate 				"%s: I_LIST ioctl failed\n", Cmd_namep);
264*515Smeem 			return (ERR_STDIN);
2650Sstevel@tonic-gate 		}
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 		/*
2680Sstevel@tonic-gate 		 * The following attempts to avoid leaving a
2690Sstevel@tonic-gate 		 * terminal line that does not respond to anything
2700Sstevel@tonic-gate 		 * if the strchg -h or -f options failed due to
2710Sstevel@tonic-gate 		 * specifying invalid module names for pushing
2720Sstevel@tonic-gate 		 */
273*515Smeem 		if (ioctl(STDIN, TCGETA, &termio) >= 0)
2740Sstevel@tonic-gate 			is_a_tty = TRUE;
2750Sstevel@tonic-gate 	}
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	/*
2790Sstevel@tonic-gate 	 *	push modules on stream
2800Sstevel@tonic-gate 	 */
281*515Smeem 	if (push) {
2820Sstevel@tonic-gate 		/*
2830Sstevel@tonic-gate 		 * pull mod names out of comma-separated list
2840Sstevel@tonic-gate 		 */
285*515Smeem 		for (i = 0, modp = strtok(modnamep, ",");
286*515Smeem 		    modp != NULL; ++i, modp = strtok(NULL, ",")) {
287*515Smeem 			if (push_module(modp) == FAILURE) {
2880Sstevel@tonic-gate 				/* pop the 'i' modules we just added */
2890Sstevel@tonic-gate 				restore(i, 0);
290*515Smeem 				return (ERR_STDIN);
2910Sstevel@tonic-gate 			}
2920Sstevel@tonic-gate 		}
293*515Smeem 		return (SUCCESS);
2940Sstevel@tonic-gate 	}
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	/*
2970Sstevel@tonic-gate 	 *	read configuration from a file
2980Sstevel@tonic-gate 	 */
299*515Smeem 	if (fromfile) {
3000Sstevel@tonic-gate 
301*515Smeem 		if ((fp = fopen(file_namep, "r")) == NULL) {
3020Sstevel@tonic-gate 			perror("fopen");
3030Sstevel@tonic-gate 			(void) fprintf(stderr,
3040Sstevel@tonic-gate 				"%s: could not open file '%s'\n",
3050Sstevel@tonic-gate 				Cmd_namep, file_namep);
306*515Smeem 			return (ERR_OPEN);
3070Sstevel@tonic-gate 		}
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 		/*
3100Sstevel@tonic-gate 		 * read file and construct a new strlist
3110Sstevel@tonic-gate 		 */
3120Sstevel@tonic-gate 		i = 0;
313*515Smeem 		while (fgets(buf, BUFSIZ, fp) != NULL) {
3140Sstevel@tonic-gate 
315*515Smeem 			if (buf[0] == '#')
3160Sstevel@tonic-gate 				continue;	/* skip comments */
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 			/*
3190Sstevel@tonic-gate 			 * skip trailing newline, trailing and leading
3200Sstevel@tonic-gate 			 * whitespace
3210Sstevel@tonic-gate 			 */
322*515Smeem 			if ((modp = strtok(buf, " \t\n")) == NULL)
3230Sstevel@tonic-gate 				continue;	/* blank line */
3240Sstevel@tonic-gate 
325*515Smeem 			(void) strncpy(newlist.sl_modlist[i].l_name,
326*515Smeem 			    modp, FMNAMESZ);
3270Sstevel@tonic-gate 			++i;
328*515Smeem 			if ((modp = strtok(NULL, " \t\n")) != NULL) {
3290Sstevel@tonic-gate 				/*
330*515Smeem 				 * bad format
3310Sstevel@tonic-gate 				 * should only be one name per line
3320Sstevel@tonic-gate 				 */
3330Sstevel@tonic-gate 				(void) fprintf(stderr,
334*515Smeem 				    "%s: error on line %d in file %s: "
335*515Smeem 				    "multiple module names??\n",
336*515Smeem 				    Cmd_namep, i, file_namep);
337*515Smeem 				return (ERR_MODULE);
3380Sstevel@tonic-gate 			}
339*515Smeem 			if (i > newlist.sl_nmods)
340*515Smeem 				if (more_modules(&newlist, i) != SUCCESS)
341*515Smeem 					return (ERR_MEM);
3420Sstevel@tonic-gate 		}
3430Sstevel@tonic-gate 		newlist.sl_nmods = i;
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 		/*
3460Sstevel@tonic-gate 		 * If an empty file, exit silently
3470Sstevel@tonic-gate 		 */
348*515Smeem 		if (i == 0)
349*515Smeem 			return (SUCCESS);
3500Sstevel@tonic-gate 
351*515Smeem 		/*
3520Sstevel@tonic-gate 		 * Pop all modules currently on the stream.
3530Sstevel@tonic-gate 		 */
354*515Smeem 		if ((i = pop_modules(Oldlist.sl_nmods - 1))
355*515Smeem 		    != (Oldlist.sl_nmods - 1)) {
3560Sstevel@tonic-gate 			/* put back whatever we've popped */
3570Sstevel@tonic-gate 			restore(0, i);
358*515Smeem 			return (ERR_STDIN);
3590Sstevel@tonic-gate 		}
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 		/*
3620Sstevel@tonic-gate 		 * Push new modules
3630Sstevel@tonic-gate 		 */
364*515Smeem 		for (i = newlist.sl_nmods - 1; i >= 0; --i) {
365*515Smeem 			if (push_module(newlist.sl_modlist[i].l_name) ==
366*515Smeem 			    FAILURE) {
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 				/*
3690Sstevel@tonic-gate 				 * pop whatever new modules we've pushed
3700Sstevel@tonic-gate 				 * then push old module list back on
3710Sstevel@tonic-gate 				 */
3720Sstevel@tonic-gate 				restore((newlist.sl_nmods - 1 - i),
373*515Smeem 				    (Oldlist.sl_nmods - 1));
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 				/*
3760Sstevel@tonic-gate 				 * If the stream is a tty line, at least try
3770Sstevel@tonic-gate 				 * to set the state to what it was before.
3780Sstevel@tonic-gate 				 */
379*515Smeem 				if (is_a_tty &&
380*515Smeem 				    ioctl(STDIN, TCSETA, &termio) < 0) {
381*515Smeem 					perror("TCSETA");
382*515Smeem 					(void) fprintf(stderr,
383*515Smeem 					    "%s: WARNING: Could not restore "
384*515Smeem 					    "the states of the terminal line "
385*515Smeem 					    "discipline\n", Cmd_namep);
3860Sstevel@tonic-gate 				}
387*515Smeem 				return (ERR_STDIN);
3880Sstevel@tonic-gate 			}
389*515Smeem 		}
390*515Smeem 		return (SUCCESS);
3910Sstevel@tonic-gate 	}	/* end if-fromfile */
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	/*
3950Sstevel@tonic-gate 	 *	pop all modules (except driver)
3960Sstevel@tonic-gate 	 */
397*515Smeem 	if (popall) {
398*515Smeem 		if (Oldlist.sl_nmods > 1) {
399*515Smeem 			if ((i = pop_modules(Oldlist.sl_nmods - 1)) !=
400*515Smeem 			    (Oldlist.sl_nmods - 1)) {
4010Sstevel@tonic-gate 				restore(0, i);
402*515Smeem 				return (ERR_STDIN);
4030Sstevel@tonic-gate 			}
4040Sstevel@tonic-gate 		}
405*515Smeem 		return (SUCCESS);
4060Sstevel@tonic-gate 	}
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	/*
4090Sstevel@tonic-gate 	 *	pop up to (but not including) a module
4100Sstevel@tonic-gate 	 */
411*515Smeem 	if (popupto) {
4120Sstevel@tonic-gate 		/*
4130Sstevel@tonic-gate 		 * check that the module is in fact on the stream
4140Sstevel@tonic-gate 		 */
415*515Smeem 		for (i = 0; i < Oldlist.sl_nmods; ++i)
416*515Smeem 			if (strncmp(Oldlist.sl_modlist[i].l_name, modnamep,
417*515Smeem 			    FMNAMESZ) == 0)
4180Sstevel@tonic-gate 				break;
419*515Smeem 		if (i == Oldlist.sl_nmods) {
4200Sstevel@tonic-gate 			/* no match found */
4210Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: %s not found on stream\n",
4220Sstevel@tonic-gate 							Cmd_namep, modnamep);
423*515Smeem 			return (ERR_MODULE);
4240Sstevel@tonic-gate 		}
4250Sstevel@tonic-gate 
426*515Smeem 		if ((j = pop_modules(i)) != i) {
4270Sstevel@tonic-gate 			/* put back whatever we've popped */
4280Sstevel@tonic-gate 			restore(0, j);
429*515Smeem 			return (ERR_STDIN);
4300Sstevel@tonic-gate 		}
431*515Smeem 		return (SUCCESS);
4320Sstevel@tonic-gate 	}
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	/*
4350Sstevel@tonic-gate 	 *	pop the topmost module
4360Sstevel@tonic-gate 	 */
437*515Smeem 	if (pop) {
438*515Smeem 		if (Oldlist.sl_nmods > 1)
439*515Smeem 			if (pop_modules(1) != 1)
4400Sstevel@tonic-gate 				/* no need to restore */
441*515Smeem 				return (ERR_STDIN);
442*515Smeem 		return (SUCCESS);
4430Sstevel@tonic-gate 	}
4440Sstevel@tonic-gate 
445*515Smeem 	return (SUCCESS);
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate 
448*515Smeem /*
4490Sstevel@tonic-gate  * pop_module(n)		pop 'n' modules from stream
4500Sstevel@tonic-gate  *
4510Sstevel@tonic-gate  * returns # of modules popped
4520Sstevel@tonic-gate  */
4530Sstevel@tonic-gate static int
pop_modules(int num_modules)454*515Smeem pop_modules(int num_modules)
4550Sstevel@tonic-gate {
456*515Smeem 	int i;
4570Sstevel@tonic-gate 
458*515Smeem 	for (i = 0; i < num_modules; i++) {
459*515Smeem 		if (ioctl(STDIN, I_POP, 0) < 0) {
4600Sstevel@tonic-gate 			perror("I_POP");
4610Sstevel@tonic-gate 			(void) fprintf(stderr,
462*515Smeem 			    "%s: I_POP ioctl failed\n", Cmd_namep);
463*515Smeem 			return (i);
4640Sstevel@tonic-gate 		}
4650Sstevel@tonic-gate 	}
466*515Smeem 	return (i);
4670Sstevel@tonic-gate }
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate /*
4700Sstevel@tonic-gate  * push_module(modnamep)	pushes 'modnamep' module on stream
4710Sstevel@tonic-gate  *
4720Sstevel@tonic-gate  * returns SUCCESS or FAILURE
4730Sstevel@tonic-gate  */
4740Sstevel@tonic-gate static int
push_module(const char * modnamep)475*515Smeem push_module(const char *modnamep)
4760Sstevel@tonic-gate {
477*515Smeem 	if (ioctl(STDIN, I_PUSH, modnamep) < 0) {
4780Sstevel@tonic-gate 		perror("I_PUSH");
4790Sstevel@tonic-gate 		(void) fprintf(stderr,
480*515Smeem 		    "%s: I_PUSH ioctl of %s failed\n", Cmd_namep, modnamep);
481*515Smeem 		return (FAILURE);
4820Sstevel@tonic-gate 	}
4830Sstevel@tonic-gate 	return (SUCCESS);
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate /*
4880Sstevel@tonic-gate  * restore(npop, npush)		restore original state of stream
4890Sstevel@tonic-gate  *
4900Sstevel@tonic-gate  * pops 'npop' modules, then pushes the topmost 'npush' modules from
4910Sstevel@tonic-gate  * Oldlist
4920Sstevel@tonic-gate  *
4930Sstevel@tonic-gate  */
4940Sstevel@tonic-gate static void
restore(int npop,int npush)495*515Smeem restore(int npop, int npush)
4960Sstevel@tonic-gate {
497*515Smeem 	int	i;
4980Sstevel@tonic-gate 
499*515Smeem 	if ((i = pop_modules(npop)) != npop) {
5000Sstevel@tonic-gate 		(void) fprintf(stderr,
501*515Smeem 		    "%s: WARNING: could not restore state of stream\n",
502*515Smeem 		    Cmd_namep);
5030Sstevel@tonic-gate 		return;
5040Sstevel@tonic-gate 	}
505*515Smeem 
506*515Smeem 	if (npush >= Oldlist.sl_nmods) {	/* "cannot" happen */
5070Sstevel@tonic-gate 		(void) fprintf(stderr,
508*515Smeem 		    "%s: internal logic error in restore\n", Cmd_namep);
5090Sstevel@tonic-gate 		(void) fprintf(stderr,
510*515Smeem 		    "%s: WARNING: could not restore state of stream\n",
511*515Smeem 		    Cmd_namep);
5120Sstevel@tonic-gate 		return;
5130Sstevel@tonic-gate 	}
514*515Smeem 
515*515Smeem 	for (i = npush - 1; i >= 0; --i) {
516*515Smeem 		if (push_module(Oldlist.sl_modlist[i].l_name) == FAILURE) {
5170Sstevel@tonic-gate 			(void) fprintf(stderr,
518*515Smeem 			    "%s: WARNING: could not restore state of stream\n",
519*515Smeem 			    Cmd_namep);
5200Sstevel@tonic-gate 			return;
5210Sstevel@tonic-gate 		}
5220Sstevel@tonic-gate 	}
5230Sstevel@tonic-gate }
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate /*
5260Sstevel@tonic-gate  * more_modules(listp, n)	allocate space for 'n' modules in 'listp'
5270Sstevel@tonic-gate  *
5280Sstevel@tonic-gate  * returns:	SUCCESS or FAILURE
5290Sstevel@tonic-gate  */
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate static int
more_modules(struct str_list * listp,int n)532*515Smeem more_modules(struct str_list *listp, int n)
5330Sstevel@tonic-gate {
534*515Smeem 	int			i;
535*515Smeem 	struct str_mlist	*modp;
5360Sstevel@tonic-gate 
537*515Smeem 	if (n > MAXMODULES) {
5380Sstevel@tonic-gate 		(void) fprintf(stderr,
539*515Smeem 		    "%s: too many modules (%d) -- max is %d\n",
540*515Smeem 		    Cmd_namep, n, MAXMODULES);
541*515Smeem 		return (FAILURE);
5420Sstevel@tonic-gate 	}
5430Sstevel@tonic-gate 
544*515Smeem 	if ((modp = calloc(n, sizeof (struct str_mlist))) == NULL) {
5450Sstevel@tonic-gate 		perror("calloc");
5460Sstevel@tonic-gate 		(void) fprintf(stderr,
547*515Smeem 		    "%s: failed to allocate space for module list\n",
548*515Smeem 		    Cmd_namep);
549*515Smeem 		return (FAILURE);
5500Sstevel@tonic-gate 	}
5510Sstevel@tonic-gate 
552*515Smeem 	for (i = 0; i < listp->sl_nmods; ++i)
5530Sstevel@tonic-gate 		(void) strncpy(modp[i].l_name, listp->sl_modlist[i].l_name,
554*515Smeem 		    FMNAMESZ);
5550Sstevel@tonic-gate 	listp->sl_nmods = n;
5560Sstevel@tonic-gate 	listp->sl_modlist = modp;
557*515Smeem 	return (SUCCESS);
5580Sstevel@tonic-gate }
559