17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate * with the License.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate * and limitations under the License.
137c478bd9Sstevel@tonic-gate *
147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate *
207c478bd9Sstevel@tonic-gate * CDDL HEADER END
217c478bd9Sstevel@tonic-gate */
22*4b908718Smeem
23*4b908718Smeem /*
24*4b908718Smeem * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
25*4b908718Smeem * Use is subject to license terms.
26*4b908718Smeem */
27*4b908718Smeem
287c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
297c478bd9Sstevel@tonic-gate /* All Rights Reserved */
307c478bd9Sstevel@tonic-gate
31*4b908718Smeem #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6 */
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate /*
347c478bd9Sstevel@tonic-gate * Streams Command strchg: change the configuration of the
357c478bd9Sstevel@tonic-gate * stream associated with stdin.
367c478bd9Sstevel@tonic-gate *
377c478bd9Sstevel@tonic-gate * USAGE: strchg -h module1[,module2,module3 ...]
387c478bd9Sstevel@tonic-gate * or: strchg -p
397c478bd9Sstevel@tonic-gate * or: strchg -p -a
407c478bd9Sstevel@tonic-gate * or: strchg -p -u module
417c478bd9Sstevel@tonic-gate * or: strchg -f file
427c478bd9Sstevel@tonic-gate *
437c478bd9Sstevel@tonic-gate * -h pusHes the named module(s) onto the stdin stream
447c478bd9Sstevel@tonic-gate * -p poPs the topmost module from the stdin stream
457c478bd9Sstevel@tonic-gate * -p -a poPs All modules
467c478bd9Sstevel@tonic-gate * -p -u module poPs all modules Up to, but not including, the named module
477c478bd9Sstevel@tonic-gate * -f file reads a list of modules from the named File, pops all modules,
487c478bd9Sstevel@tonic-gate * then pushes the list of modules
497c478bd9Sstevel@tonic-gate *
507c478bd9Sstevel@tonic-gate * RETURNS:
517c478bd9Sstevel@tonic-gate * 0 SUCCESS it worked
527c478bd9Sstevel@tonic-gate * 1 ERR_USAGE bad invocation
537c478bd9Sstevel@tonic-gate * 2 ERR_MODULE bad module name(s)
547c478bd9Sstevel@tonic-gate * 3 ERR_STDIN an ioctl or stat on the stdin stream failed
557c478bd9Sstevel@tonic-gate * 4 ERR_MEM couldn't allocate memory
567c478bd9Sstevel@tonic-gate * 5 ERR_OPEN couldn't open file in -f opt
577c478bd9Sstevel@tonic-gate * 6 ERR_PERM not owner or superuser
587c478bd9Sstevel@tonic-gate *
597c478bd9Sstevel@tonic-gate */
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate #include <stdio.h>
637c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
647c478bd9Sstevel@tonic-gate #include <sys/termio.h>
657c478bd9Sstevel@tonic-gate #include <sys/types.h>
667c478bd9Sstevel@tonic-gate #include <sys/stat.h>
67*4b908718Smeem #include <string.h>
68*4b908718Smeem #include <stdlib.h>
69*4b908718Smeem #include <unistd.h>
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate #define FALSE 0
727c478bd9Sstevel@tonic-gate #define TRUE 1
737c478bd9Sstevel@tonic-gate
747c478bd9Sstevel@tonic-gate #define SUCCESS 0
757c478bd9Sstevel@tonic-gate #define FAILURE 1
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate #define NMODULES 16 /* "reasonable" # of modules to push */
787c478bd9Sstevel@tonic-gate /* (can push more if you like) */
797c478bd9Sstevel@tonic-gate #define MAXMODULES 2048 /* max # of modules to push */
807c478bd9Sstevel@tonic-gate
817c478bd9Sstevel@tonic-gate #define OPTLIST "af:h:pu:"
82*4b908718Smeem #define USAGE "Usage:\t%s -h module1[,module2 ... ]\n\t%s -f file"\
83*4b908718Smeem "\n\t%s -p [-a | -u module ]\n"
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate #define ERR_USAGE 1 /* bad invocation */
867c478bd9Sstevel@tonic-gate #define ERR_MODULE 2 /* bad module name(s) or too many modules */
877c478bd9Sstevel@tonic-gate #define ERR_STDIN 3 /* an ioctl or stat on stdin failed */
887c478bd9Sstevel@tonic-gate #define ERR_MEM 4 /* couldn't allocate memory */
897c478bd9Sstevel@tonic-gate #define ERR_OPEN 5 /* couldn't open file in -f opt */
907c478bd9Sstevel@tonic-gate #define ERR_PERM 6 /* not owner or superuser */
917c478bd9Sstevel@tonic-gate
927c478bd9Sstevel@tonic-gate #define STDIN 0
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate static char *Cmd_namep; /* how was it invoked? */
957c478bd9Sstevel@tonic-gate static struct str_mlist Oldmods[NMODULES]; /* modlist for Oldlist */
967c478bd9Sstevel@tonic-gate static struct str_list Oldlist; /* original modules */
977c478bd9Sstevel@tonic-gate
98*4b908718Smeem static int pop_modules(int);
99*4b908718Smeem static int push_module(const char *);
100*4b908718Smeem static int more_modules(struct str_list *, int);
101*4b908718Smeem static void restore(int, int);
1027c478bd9Sstevel@tonic-gate
103*4b908718Smeem int
main(int argc,char ** argv)104*4b908718Smeem main(int argc, char **argv)
1057c478bd9Sstevel@tonic-gate {
1067c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; /* input buffer */
1077c478bd9Sstevel@tonic-gate char *file_namep; /* file from -f opt */
1087c478bd9Sstevel@tonic-gate char *modnamep; /* mods from -h or -u opt */
1097c478bd9Sstevel@tonic-gate char *modp; /* for walking thru modnamep */
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate FILE *fp; /* file pointer for -f file */
1127c478bd9Sstevel@tonic-gate
113*4b908718Smeem int i; /* loop index and junk var */
114*4b908718Smeem int j; /* loop index and junk var */
1157c478bd9Sstevel@tonic-gate int euid; /* effective uid */
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate short error; /* TRUE if usage error */
1187c478bd9Sstevel@tonic-gate short fromfile; /* TRUE if -f file */
1197c478bd9Sstevel@tonic-gate short is_a_tty; /* TRUE if TCGETA succeeds */
1207c478bd9Sstevel@tonic-gate short pop; /* TRUE if -p */
1217c478bd9Sstevel@tonic-gate short popall; /* TRUE if -p -a */
1227c478bd9Sstevel@tonic-gate short popupto; /* TRUE if -p -u module */
1237c478bd9Sstevel@tonic-gate short push; /* TRUE if -h mod1[,mod2 ...] */
1247c478bd9Sstevel@tonic-gate
125*4b908718Smeem struct str_mlist newmods[NMODULES]; /* mod list for new list */
1267c478bd9Sstevel@tonic-gate struct stat stats; /* stream stats */
1277c478bd9Sstevel@tonic-gate struct str_list newlist; /* modules to be pushed */
1287c478bd9Sstevel@tonic-gate struct termio termio; /* save state of tty */
1297c478bd9Sstevel@tonic-gate
1307c478bd9Sstevel@tonic-gate /*
1317c478bd9Sstevel@tonic-gate * init
1327c478bd9Sstevel@tonic-gate */
1337c478bd9Sstevel@tonic-gate
1347c478bd9Sstevel@tonic-gate Cmd_namep = argv[0];
1357c478bd9Sstevel@tonic-gate error = fromfile = is_a_tty = pop = popall = popupto = push = FALSE;
1367c478bd9Sstevel@tonic-gate Oldlist.sl_modlist = Oldmods;
1377c478bd9Sstevel@tonic-gate Oldlist.sl_nmods = NMODULES;
1387c478bd9Sstevel@tonic-gate newlist.sl_modlist = newmods;
1397c478bd9Sstevel@tonic-gate newlist.sl_nmods = NMODULES;
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate /*
1427c478bd9Sstevel@tonic-gate * only owner and root can change stream configuration
1437c478bd9Sstevel@tonic-gate */
1447c478bd9Sstevel@tonic-gate if ((euid = geteuid()) != 0) {
1457c478bd9Sstevel@tonic-gate if (fstat(0, &stats) < 0) {
1467c478bd9Sstevel@tonic-gate perror("fstat");
1477c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: fstat of stdin failed\n",
1487c478bd9Sstevel@tonic-gate Cmd_namep);
1497c478bd9Sstevel@tonic-gate return (ERR_STDIN);
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate if (euid != stats.st_uid) {
1527c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
1537c478bd9Sstevel@tonic-gate "%s: not owner of stdin\n", Cmd_namep);
1547c478bd9Sstevel@tonic-gate return (ERR_PERM);
1557c478bd9Sstevel@tonic-gate }
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gate /*
1607c478bd9Sstevel@tonic-gate * parse args
1617c478bd9Sstevel@tonic-gate */
1627c478bd9Sstevel@tonic-gate
1637c478bd9Sstevel@tonic-gate if (argc == 1) {
1647c478bd9Sstevel@tonic-gate (void) fprintf(stderr, USAGE, Cmd_namep, Cmd_namep, Cmd_namep);
1657c478bd9Sstevel@tonic-gate return (ERR_USAGE);
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate while (!error && (i = getopt(argc, argv, OPTLIST)) != -1) {
1697c478bd9Sstevel@tonic-gate
1707c478bd9Sstevel@tonic-gate switch (i) {
1717c478bd9Sstevel@tonic-gate
1727c478bd9Sstevel@tonic-gate case 'a': /* pop All */
1737c478bd9Sstevel@tonic-gate if (fromfile || popupto || push)
1747c478bd9Sstevel@tonic-gate error = TRUE;
1757c478bd9Sstevel@tonic-gate else
1767c478bd9Sstevel@tonic-gate popall = TRUE;
1777c478bd9Sstevel@tonic-gate break;
1787c478bd9Sstevel@tonic-gate
1797c478bd9Sstevel@tonic-gate case 'f': /* read from File */
1807c478bd9Sstevel@tonic-gate if (pop || push)
1817c478bd9Sstevel@tonic-gate error = TRUE;
1827c478bd9Sstevel@tonic-gate else {
1837c478bd9Sstevel@tonic-gate fromfile = TRUE;
1847c478bd9Sstevel@tonic-gate file_namep = optarg;
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate break;
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate case 'h': /* pusH */
1897c478bd9Sstevel@tonic-gate if (fromfile || pop)
1907c478bd9Sstevel@tonic-gate error = TRUE;
1917c478bd9Sstevel@tonic-gate else {
1927c478bd9Sstevel@tonic-gate push = TRUE;
1937c478bd9Sstevel@tonic-gate modnamep = optarg;
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate break;
1967c478bd9Sstevel@tonic-gate
1977c478bd9Sstevel@tonic-gate case 'p': /* poP */
1987c478bd9Sstevel@tonic-gate if (fromfile || push)
1997c478bd9Sstevel@tonic-gate error = TRUE;
2007c478bd9Sstevel@tonic-gate else
2017c478bd9Sstevel@tonic-gate pop = TRUE;
2027c478bd9Sstevel@tonic-gate break;
2037c478bd9Sstevel@tonic-gate
2047c478bd9Sstevel@tonic-gate case 'u': /* pop Upto */
2057c478bd9Sstevel@tonic-gate if (fromfile || popall || push)
2067c478bd9Sstevel@tonic-gate error = TRUE;
2077c478bd9Sstevel@tonic-gate else {
2087c478bd9Sstevel@tonic-gate popupto = TRUE;
2097c478bd9Sstevel@tonic-gate modnamep = optarg;
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate break;
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate default:
2147c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
2157c478bd9Sstevel@tonic-gate USAGE, Cmd_namep, Cmd_namep, Cmd_namep);
2167c478bd9Sstevel@tonic-gate return (ERR_USAGE);
2177c478bd9Sstevel@tonic-gate /*NOTREACHED*/
2187c478bd9Sstevel@tonic-gate }
2197c478bd9Sstevel@tonic-gate }
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate if (error || optind < argc) {
2227c478bd9Sstevel@tonic-gate (void) fprintf(stderr, USAGE, Cmd_namep, Cmd_namep, Cmd_namep);
2237c478bd9Sstevel@tonic-gate return (ERR_USAGE);
2247c478bd9Sstevel@tonic-gate }
2257c478bd9Sstevel@tonic-gate
2267c478bd9Sstevel@tonic-gate if (!pop && (popall || popupto)) {
2277c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
2287c478bd9Sstevel@tonic-gate "%s: -p option must be used with -a or -u to pop modules\n",
2297c478bd9Sstevel@tonic-gate Cmd_namep);
2307c478bd9Sstevel@tonic-gate (void) fprintf(stderr, USAGE, Cmd_namep, Cmd_namep, Cmd_namep);
2317c478bd9Sstevel@tonic-gate return (ERR_USAGE);
2327c478bd9Sstevel@tonic-gate }
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate
2357c478bd9Sstevel@tonic-gate /*
2367c478bd9Sstevel@tonic-gate * Save state so can restore if something goes wrong
2377c478bd9Sstevel@tonic-gate * (If are only going to push modules, don't need to
2387c478bd9Sstevel@tonic-gate * save original module list for restore.)
2397c478bd9Sstevel@tonic-gate */
2407c478bd9Sstevel@tonic-gate if (fromfile || pop) {
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate /*
2437c478bd9Sstevel@tonic-gate * get number of modules on stream
2447c478bd9Sstevel@tonic-gate * allocate more room if needed
2457c478bd9Sstevel@tonic-gate */
246*4b908718Smeem if ((i = ioctl(STDIN, I_LIST, NULL)) < 0) {
2477c478bd9Sstevel@tonic-gate perror("I_LIST");
2487c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
2497c478bd9Sstevel@tonic-gate "%s: I_LIST ioctl failed\n", Cmd_namep);
2507c478bd9Sstevel@tonic-gate return (ERR_STDIN);
2517c478bd9Sstevel@tonic-gate }
252*4b908718Smeem if (i > Oldlist.sl_nmods &&
253*4b908718Smeem more_modules(&Oldlist, i) != SUCCESS)
2547c478bd9Sstevel@tonic-gate return (ERR_MEM);
2557c478bd9Sstevel@tonic-gate
2567c478bd9Sstevel@tonic-gate /*
2577c478bd9Sstevel@tonic-gate * get list of modules on stream
2587c478bd9Sstevel@tonic-gate */
2597c478bd9Sstevel@tonic-gate Oldlist.sl_nmods = i;
2607c478bd9Sstevel@tonic-gate if (ioctl(STDIN, I_LIST, &Oldlist) < 0) {
2617c478bd9Sstevel@tonic-gate perror("I_LIST");
2627c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
2637c478bd9Sstevel@tonic-gate "%s: I_LIST ioctl failed\n", Cmd_namep);
2647c478bd9Sstevel@tonic-gate return (ERR_STDIN);
2657c478bd9Sstevel@tonic-gate }
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gate /*
2687c478bd9Sstevel@tonic-gate * The following attempts to avoid leaving a
2697c478bd9Sstevel@tonic-gate * terminal line that does not respond to anything
2707c478bd9Sstevel@tonic-gate * if the strchg -h or -f options failed due to
2717c478bd9Sstevel@tonic-gate * specifying invalid module names for pushing
2727c478bd9Sstevel@tonic-gate */
2737c478bd9Sstevel@tonic-gate if (ioctl(STDIN, TCGETA, &termio) >= 0)
2747c478bd9Sstevel@tonic-gate is_a_tty = TRUE;
2757c478bd9Sstevel@tonic-gate }
2767c478bd9Sstevel@tonic-gate
2777c478bd9Sstevel@tonic-gate
2787c478bd9Sstevel@tonic-gate /*
2797c478bd9Sstevel@tonic-gate * push modules on stream
2807c478bd9Sstevel@tonic-gate */
2817c478bd9Sstevel@tonic-gate if (push) {
2827c478bd9Sstevel@tonic-gate /*
2837c478bd9Sstevel@tonic-gate * pull mod names out of comma-separated list
2847c478bd9Sstevel@tonic-gate */
2857c478bd9Sstevel@tonic-gate for (i = 0, modp = strtok(modnamep, ",");
286*4b908718Smeem modp != NULL; ++i, modp = strtok(NULL, ",")) {
2877c478bd9Sstevel@tonic-gate if (push_module(modp) == FAILURE) {
2887c478bd9Sstevel@tonic-gate /* pop the 'i' modules we just added */
2897c478bd9Sstevel@tonic-gate restore(i, 0);
2907c478bd9Sstevel@tonic-gate return (ERR_STDIN);
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate return (SUCCESS);
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate
2967c478bd9Sstevel@tonic-gate /*
2977c478bd9Sstevel@tonic-gate * read configuration from a file
2987c478bd9Sstevel@tonic-gate */
2997c478bd9Sstevel@tonic-gate if (fromfile) {
3007c478bd9Sstevel@tonic-gate
301*4b908718Smeem if ((fp = fopen(file_namep, "r")) == NULL) {
3027c478bd9Sstevel@tonic-gate perror("fopen");
3037c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
3047c478bd9Sstevel@tonic-gate "%s: could not open file '%s'\n",
3057c478bd9Sstevel@tonic-gate Cmd_namep, file_namep);
3067c478bd9Sstevel@tonic-gate return (ERR_OPEN);
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate
3097c478bd9Sstevel@tonic-gate /*
3107c478bd9Sstevel@tonic-gate * read file and construct a new strlist
3117c478bd9Sstevel@tonic-gate */
3127c478bd9Sstevel@tonic-gate i = 0;
313*4b908718Smeem while (fgets(buf, BUFSIZ, fp) != NULL) {
3147c478bd9Sstevel@tonic-gate
3157c478bd9Sstevel@tonic-gate if (buf[0] == '#')
3167c478bd9Sstevel@tonic-gate continue; /* skip comments */
3177c478bd9Sstevel@tonic-gate
3187c478bd9Sstevel@tonic-gate /*
3197c478bd9Sstevel@tonic-gate * skip trailing newline, trailing and leading
3207c478bd9Sstevel@tonic-gate * whitespace
3217c478bd9Sstevel@tonic-gate */
322*4b908718Smeem if ((modp = strtok(buf, " \t\n")) == NULL)
3237c478bd9Sstevel@tonic-gate continue; /* blank line */
3247c478bd9Sstevel@tonic-gate
3257c478bd9Sstevel@tonic-gate (void) strncpy(newlist.sl_modlist[i].l_name,
3267c478bd9Sstevel@tonic-gate modp, FMNAMESZ);
3277c478bd9Sstevel@tonic-gate ++i;
328*4b908718Smeem if ((modp = strtok(NULL, " \t\n")) != NULL) {
3297c478bd9Sstevel@tonic-gate /*
3307c478bd9Sstevel@tonic-gate * bad format
3317c478bd9Sstevel@tonic-gate * should only be one name per line
3327c478bd9Sstevel@tonic-gate */
3337c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
334*4b908718Smeem "%s: error on line %d in file %s: "
335*4b908718Smeem "multiple module names??\n",
3367c478bd9Sstevel@tonic-gate Cmd_namep, i, file_namep);
3377c478bd9Sstevel@tonic-gate return (ERR_MODULE);
3387c478bd9Sstevel@tonic-gate }
3397c478bd9Sstevel@tonic-gate if (i > newlist.sl_nmods)
3407c478bd9Sstevel@tonic-gate if (more_modules(&newlist, i) != SUCCESS)
3417c478bd9Sstevel@tonic-gate return (ERR_MEM);
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate newlist.sl_nmods = i;
3447c478bd9Sstevel@tonic-gate
3457c478bd9Sstevel@tonic-gate /*
3467c478bd9Sstevel@tonic-gate * If an empty file, exit silently
3477c478bd9Sstevel@tonic-gate */
3487c478bd9Sstevel@tonic-gate if (i == 0)
3497c478bd9Sstevel@tonic-gate return (SUCCESS);
3507c478bd9Sstevel@tonic-gate
3517c478bd9Sstevel@tonic-gate /*
3527c478bd9Sstevel@tonic-gate * Pop all modules currently on the stream.
3537c478bd9Sstevel@tonic-gate */
3547c478bd9Sstevel@tonic-gate if ((i = pop_modules(Oldlist.sl_nmods - 1))
3557c478bd9Sstevel@tonic-gate != (Oldlist.sl_nmods - 1)) {
3567c478bd9Sstevel@tonic-gate /* put back whatever we've popped */
3577c478bd9Sstevel@tonic-gate restore(0, i);
3587c478bd9Sstevel@tonic-gate return (ERR_STDIN);
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate
3617c478bd9Sstevel@tonic-gate /*
3627c478bd9Sstevel@tonic-gate * Push new modules
3637c478bd9Sstevel@tonic-gate */
3647c478bd9Sstevel@tonic-gate for (i = newlist.sl_nmods - 1; i >= 0; --i) {
365*4b908718Smeem if (push_module(newlist.sl_modlist[i].l_name) ==
366*4b908718Smeem FAILURE) {
3677c478bd9Sstevel@tonic-gate
3687c478bd9Sstevel@tonic-gate /*
3697c478bd9Sstevel@tonic-gate * pop whatever new modules we've pushed
3707c478bd9Sstevel@tonic-gate * then push old module list back on
3717c478bd9Sstevel@tonic-gate */
3727c478bd9Sstevel@tonic-gate restore((newlist.sl_nmods - 1 - i),
3737c478bd9Sstevel@tonic-gate (Oldlist.sl_nmods - 1));
3747c478bd9Sstevel@tonic-gate
3757c478bd9Sstevel@tonic-gate /*
3767c478bd9Sstevel@tonic-gate * If the stream is a tty line, at least try
3777c478bd9Sstevel@tonic-gate * to set the state to what it was before.
3787c478bd9Sstevel@tonic-gate */
379*4b908718Smeem if (is_a_tty &&
380*4b908718Smeem ioctl(STDIN, TCSETA, &termio) < 0) {
3817c478bd9Sstevel@tonic-gate perror("TCSETA");
3827c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
383*4b908718Smeem "%s: WARNING: Could not restore "
384*4b908718Smeem "the states of the terminal line "
385*4b908718Smeem "discipline\n", Cmd_namep);
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate return (ERR_STDIN);
3887c478bd9Sstevel@tonic-gate }
3897c478bd9Sstevel@tonic-gate }
3907c478bd9Sstevel@tonic-gate return (SUCCESS);
3917c478bd9Sstevel@tonic-gate } /* end if-fromfile */
3927c478bd9Sstevel@tonic-gate
3937c478bd9Sstevel@tonic-gate
3947c478bd9Sstevel@tonic-gate /*
3957c478bd9Sstevel@tonic-gate * pop all modules (except driver)
3967c478bd9Sstevel@tonic-gate */
3977c478bd9Sstevel@tonic-gate if (popall) {
3987c478bd9Sstevel@tonic-gate if (Oldlist.sl_nmods > 1) {
399*4b908718Smeem if ((i = pop_modules(Oldlist.sl_nmods - 1)) !=
400*4b908718Smeem (Oldlist.sl_nmods - 1)) {
4017c478bd9Sstevel@tonic-gate restore(0, i);
4027c478bd9Sstevel@tonic-gate return (ERR_STDIN);
4037c478bd9Sstevel@tonic-gate }
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate return (SUCCESS);
4067c478bd9Sstevel@tonic-gate }
4077c478bd9Sstevel@tonic-gate
4087c478bd9Sstevel@tonic-gate /*
4097c478bd9Sstevel@tonic-gate * pop up to (but not including) a module
4107c478bd9Sstevel@tonic-gate */
4117c478bd9Sstevel@tonic-gate if (popupto) {
4127c478bd9Sstevel@tonic-gate /*
4137c478bd9Sstevel@tonic-gate * check that the module is in fact on the stream
4147c478bd9Sstevel@tonic-gate */
4157c478bd9Sstevel@tonic-gate for (i = 0; i < Oldlist.sl_nmods; ++i)
4167c478bd9Sstevel@tonic-gate if (strncmp(Oldlist.sl_modlist[i].l_name, modnamep,
417*4b908718Smeem FMNAMESZ) == 0)
4187c478bd9Sstevel@tonic-gate break;
4197c478bd9Sstevel@tonic-gate if (i == Oldlist.sl_nmods) {
4207c478bd9Sstevel@tonic-gate /* no match found */
4217c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s not found on stream\n",
4227c478bd9Sstevel@tonic-gate Cmd_namep, modnamep);
4237c478bd9Sstevel@tonic-gate return (ERR_MODULE);
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate
4267c478bd9Sstevel@tonic-gate if ((j = pop_modules(i)) != i) {
4277c478bd9Sstevel@tonic-gate /* put back whatever we've popped */
4287c478bd9Sstevel@tonic-gate restore(0, j);
4297c478bd9Sstevel@tonic-gate return (ERR_STDIN);
4307c478bd9Sstevel@tonic-gate }
4317c478bd9Sstevel@tonic-gate return (SUCCESS);
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate /*
4357c478bd9Sstevel@tonic-gate * pop the topmost module
4367c478bd9Sstevel@tonic-gate */
4377c478bd9Sstevel@tonic-gate if (pop) {
4387c478bd9Sstevel@tonic-gate if (Oldlist.sl_nmods > 1)
4397c478bd9Sstevel@tonic-gate if (pop_modules(1) != 1)
4407c478bd9Sstevel@tonic-gate /* no need to restore */
4417c478bd9Sstevel@tonic-gate return (ERR_STDIN);
4427c478bd9Sstevel@tonic-gate return (SUCCESS);
4437c478bd9Sstevel@tonic-gate }
4447c478bd9Sstevel@tonic-gate
445*4b908718Smeem return (SUCCESS);
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate
4487c478bd9Sstevel@tonic-gate /*
4497c478bd9Sstevel@tonic-gate * pop_module(n) pop 'n' modules from stream
4507c478bd9Sstevel@tonic-gate *
4517c478bd9Sstevel@tonic-gate * returns # of modules popped
4527c478bd9Sstevel@tonic-gate */
4537c478bd9Sstevel@tonic-gate static int
pop_modules(int num_modules)454*4b908718Smeem pop_modules(int num_modules)
4557c478bd9Sstevel@tonic-gate {
456*4b908718Smeem int i;
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gate for (i = 0; i < num_modules; i++) {
4597c478bd9Sstevel@tonic-gate if (ioctl(STDIN, I_POP, 0) < 0) {
4607c478bd9Sstevel@tonic-gate perror("I_POP");
4617c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
4627c478bd9Sstevel@tonic-gate "%s: I_POP ioctl failed\n", Cmd_namep);
4637c478bd9Sstevel@tonic-gate return (i);
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate return (i);
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate
4697c478bd9Sstevel@tonic-gate /*
4707c478bd9Sstevel@tonic-gate * push_module(modnamep) pushes 'modnamep' module on stream
4717c478bd9Sstevel@tonic-gate *
4727c478bd9Sstevel@tonic-gate * returns SUCCESS or FAILURE
4737c478bd9Sstevel@tonic-gate */
4747c478bd9Sstevel@tonic-gate static int
push_module(const char * modnamep)475*4b908718Smeem push_module(const char *modnamep)
4767c478bd9Sstevel@tonic-gate {
4777c478bd9Sstevel@tonic-gate if (ioctl(STDIN, I_PUSH, modnamep) < 0) {
4787c478bd9Sstevel@tonic-gate perror("I_PUSH");
4797c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
4807c478bd9Sstevel@tonic-gate "%s: I_PUSH ioctl of %s failed\n", Cmd_namep, modnamep);
4817c478bd9Sstevel@tonic-gate return (FAILURE);
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate return (SUCCESS);
4847c478bd9Sstevel@tonic-gate }
4857c478bd9Sstevel@tonic-gate
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate /*
4887c478bd9Sstevel@tonic-gate * restore(npop, npush) restore original state of stream
4897c478bd9Sstevel@tonic-gate *
4907c478bd9Sstevel@tonic-gate * pops 'npop' modules, then pushes the topmost 'npush' modules from
4917c478bd9Sstevel@tonic-gate * Oldlist
4927c478bd9Sstevel@tonic-gate *
4937c478bd9Sstevel@tonic-gate */
4947c478bd9Sstevel@tonic-gate static void
restore(int npop,int npush)495*4b908718Smeem restore(int npop, int npush)
4967c478bd9Sstevel@tonic-gate {
497*4b908718Smeem int i;
4987c478bd9Sstevel@tonic-gate
4997c478bd9Sstevel@tonic-gate if ((i = pop_modules(npop)) != npop) {
5007c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
501*4b908718Smeem "%s: WARNING: could not restore state of stream\n",
502*4b908718Smeem Cmd_namep);
5037c478bd9Sstevel@tonic-gate return;
5047c478bd9Sstevel@tonic-gate }
505*4b908718Smeem
5067c478bd9Sstevel@tonic-gate if (npush >= Oldlist.sl_nmods) { /* "cannot" happen */
5077c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
5087c478bd9Sstevel@tonic-gate "%s: internal logic error in restore\n", Cmd_namep);
5097c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
510*4b908718Smeem "%s: WARNING: could not restore state of stream\n",
511*4b908718Smeem Cmd_namep);
5127c478bd9Sstevel@tonic-gate return;
5137c478bd9Sstevel@tonic-gate }
514*4b908718Smeem
5157c478bd9Sstevel@tonic-gate for (i = npush - 1; i >= 0; --i) {
5167c478bd9Sstevel@tonic-gate if (push_module(Oldlist.sl_modlist[i].l_name) == FAILURE) {
5177c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
5187c478bd9Sstevel@tonic-gate "%s: WARNING: could not restore state of stream\n",
5197c478bd9Sstevel@tonic-gate Cmd_namep);
5207c478bd9Sstevel@tonic-gate return;
5217c478bd9Sstevel@tonic-gate }
5227c478bd9Sstevel@tonic-gate }
5237c478bd9Sstevel@tonic-gate }
5247c478bd9Sstevel@tonic-gate
5257c478bd9Sstevel@tonic-gate /*
5267c478bd9Sstevel@tonic-gate * more_modules(listp, n) allocate space for 'n' modules in 'listp'
5277c478bd9Sstevel@tonic-gate *
5287c478bd9Sstevel@tonic-gate * returns: SUCCESS or FAILURE
5297c478bd9Sstevel@tonic-gate */
5307c478bd9Sstevel@tonic-gate
5317c478bd9Sstevel@tonic-gate static int
more_modules(struct str_list * listp,int n)532*4b908718Smeem more_modules(struct str_list *listp, int n)
5337c478bd9Sstevel@tonic-gate {
534*4b908718Smeem int i;
535*4b908718Smeem struct str_mlist *modp;
5367c478bd9Sstevel@tonic-gate
5377c478bd9Sstevel@tonic-gate if (n > MAXMODULES) {
5387c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
5397c478bd9Sstevel@tonic-gate "%s: too many modules (%d) -- max is %d\n",
5407c478bd9Sstevel@tonic-gate Cmd_namep, n, MAXMODULES);
5417c478bd9Sstevel@tonic-gate return (FAILURE);
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate
544*4b908718Smeem if ((modp = calloc(n, sizeof (struct str_mlist))) == NULL) {
5457c478bd9Sstevel@tonic-gate perror("calloc");
5467c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
5477c478bd9Sstevel@tonic-gate "%s: failed to allocate space for module list\n",
5487c478bd9Sstevel@tonic-gate Cmd_namep);
5497c478bd9Sstevel@tonic-gate return (FAILURE);
5507c478bd9Sstevel@tonic-gate }
5517c478bd9Sstevel@tonic-gate
5527c478bd9Sstevel@tonic-gate for (i = 0; i < listp->sl_nmods; ++i)
5537c478bd9Sstevel@tonic-gate (void) strncpy(modp[i].l_name, listp->sl_modlist[i].l_name,
5547c478bd9Sstevel@tonic-gate FMNAMESZ);
5557c478bd9Sstevel@tonic-gate listp->sl_nmods = n;
5567c478bd9Sstevel@tonic-gate listp->sl_modlist = modp;
5577c478bd9Sstevel@tonic-gate return (SUCCESS);
5587c478bd9Sstevel@tonic-gate }
559