4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
31 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6 */
34 * Streams Command strchg: change the configuration of the
35 * stream associated with stdin.
37 * USAGE: strchg -h module1[,module2,module3 ...]
40 * or: strchg -p -u module
43 * -h pusHes the named module(s) onto the stdin stream
44 * -p poPs the topmost module from the stdin stream
45 * -p -a poPs All modules
46 * -p -u module poPs all modules Up to, but not including, the named module
47 * -f file reads a list of modules from the named File, pops all modules,
48 * then pushes the list of modules
52 * 1 ERR_USAGE bad invocation
53 * 2 ERR_MODULE bad module name(s)
54 * 3 ERR_STDIN an ioctl or stat on the stdin stream failed
55 * 4 ERR_MEM couldn't allocate memory
56 * 5 ERR_OPEN couldn't open file in -f opt
57 * 6 ERR_PERM not owner or superuser
63 #include <sys/stropts.h>
64 #include <sys/termio.h>
65 #include <sys/types.h>
77 #define NMODULES 16 /* "reasonable" # of modules to push */
78 /* (can push more if you like) */
79 #define MAXMODULES 2048 /* max # of modules to push */
81 #define OPTLIST "af:h:pu:"
82 #define USAGE "Usage:\t%s -h module1[,module2 ... ]\n\t%s -f file"\
83 "\n\t%s -p [-a | -u module ]\n"
85 #define ERR_USAGE 1 /* bad invocation */
86 #define ERR_MODULE 2 /* bad module name(s) or too many modules */
87 #define ERR_STDIN 3 /* an ioctl or stat on stdin failed */
88 #define ERR_MEM 4 /* couldn't allocate memory */
89 #define ERR_OPEN 5 /* couldn't open file in -f opt */
90 #define ERR_PERM 6 /* not owner or superuser */
94 static char *Cmd_namep
; /* how was it invoked? */
95 static struct str_mlist Oldmods
[NMODULES
]; /* modlist for Oldlist */
96 static struct str_list Oldlist
; /* original modules */
98 static int pop_modules(int);
99 static int push_module(const char *);
100 static int more_modules(struct str_list
*, int);
101 static void restore(int, int);
104 main(int argc
, char **argv
)
106 char buf
[BUFSIZ
]; /* input buffer */
107 char *file_namep
; /* file from -f opt */
108 char *modnamep
; /* mods from -h or -u opt */
109 char *modp
; /* for walking thru modnamep */
111 FILE *fp
; /* file pointer for -f file */
113 int i
; /* loop index and junk var */
114 int j
; /* loop index and junk var */
115 int euid
; /* effective uid */
117 short error
; /* TRUE if usage error */
118 short fromfile
; /* TRUE if -f file */
119 short is_a_tty
; /* TRUE if TCGETA succeeds */
120 short pop
; /* TRUE if -p */
121 short popall
; /* TRUE if -p -a */
122 short popupto
; /* TRUE if -p -u module */
123 short push
; /* TRUE if -h mod1[,mod2 ...] */
125 struct str_mlist newmods
[NMODULES
]; /* mod list for new list */
126 struct stat stats
; /* stream stats */
127 struct str_list newlist
; /* modules to be pushed */
128 struct termio termio
; /* save state of tty */
135 error
= fromfile
= is_a_tty
= pop
= popall
= popupto
= push
= FALSE
;
136 Oldlist
.sl_modlist
= Oldmods
;
137 Oldlist
.sl_nmods
= NMODULES
;
138 newlist
.sl_modlist
= newmods
;
139 newlist
.sl_nmods
= NMODULES
;
142 * only owner and root can change stream configuration
144 if ((euid
= geteuid()) != 0) {
145 if (fstat(0, &stats
) < 0) {
147 (void) fprintf(stderr
, "%s: fstat of stdin failed\n",
151 if (euid
!= stats
.st_uid
) {
152 (void) fprintf(stderr
,
153 "%s: not owner of stdin\n", Cmd_namep
);
164 (void) fprintf(stderr
, USAGE
, Cmd_namep
, Cmd_namep
, Cmd_namep
);
168 while (!error
&& (i
= getopt(argc
, argv
, OPTLIST
)) != -1) {
172 case 'a': /* pop All */
173 if (fromfile
|| popupto
|| push
)
179 case 'f': /* read from File */
198 if (fromfile
|| push
)
204 case 'u': /* pop Upto */
205 if (fromfile
|| popall
|| push
)
214 (void) fprintf(stderr
,
215 USAGE
, Cmd_namep
, Cmd_namep
, Cmd_namep
);
221 if (error
|| optind
< argc
) {
222 (void) fprintf(stderr
, USAGE
, Cmd_namep
, Cmd_namep
, Cmd_namep
);
226 if (!pop
&& (popall
|| popupto
)) {
227 (void) fprintf(stderr
,
228 "%s: -p option must be used with -a or -u to pop modules\n",
230 (void) fprintf(stderr
, USAGE
, Cmd_namep
, Cmd_namep
, Cmd_namep
);
236 * Save state so can restore if something goes wrong
237 * (If are only going to push modules, don't need to
238 * save original module list for restore.)
240 if (fromfile
|| pop
) {
243 * get number of modules on stream
244 * allocate more room if needed
246 if ((i
= ioctl(STDIN
, I_LIST
, NULL
)) < 0) {
248 (void) fprintf(stderr
,
249 "%s: I_LIST ioctl failed\n", Cmd_namep
);
252 if (i
> Oldlist
.sl_nmods
&&
253 more_modules(&Oldlist
, i
) != SUCCESS
)
257 * get list of modules on stream
259 Oldlist
.sl_nmods
= i
;
260 if (ioctl(STDIN
, I_LIST
, &Oldlist
) < 0) {
262 (void) fprintf(stderr
,
263 "%s: I_LIST ioctl failed\n", Cmd_namep
);
268 * The following attempts to avoid leaving a
269 * terminal line that does not respond to anything
270 * if the strchg -h or -f options failed due to
271 * specifying invalid module names for pushing
273 if (ioctl(STDIN
, TCGETA
, &termio
) >= 0)
279 * push modules on stream
283 * pull mod names out of comma-separated list
285 for (i
= 0, modp
= strtok(modnamep
, ",");
286 modp
!= NULL
; ++i
, modp
= strtok(NULL
, ",")) {
287 if (push_module(modp
) == FAILURE
) {
288 /* pop the 'i' modules we just added */
297 * read configuration from a file
301 if ((fp
= fopen(file_namep
, "r")) == NULL
) {
303 (void) fprintf(stderr
,
304 "%s: could not open file '%s'\n",
305 Cmd_namep
, file_namep
);
310 * read file and construct a new strlist
313 while (fgets(buf
, BUFSIZ
, fp
) != NULL
) {
316 continue; /* skip comments */
319 * skip trailing newline, trailing and leading
322 if ((modp
= strtok(buf
, " \t\n")) == NULL
)
323 continue; /* blank line */
325 (void) strncpy(newlist
.sl_modlist
[i
].l_name
,
328 if ((modp
= strtok(NULL
, " \t\n")) != NULL
) {
331 * should only be one name per line
333 (void) fprintf(stderr
,
334 "%s: error on line %d in file %s: "
335 "multiple module names??\n",
336 Cmd_namep
, i
, file_namep
);
339 if (i
> newlist
.sl_nmods
)
340 if (more_modules(&newlist
, i
) != SUCCESS
)
343 newlist
.sl_nmods
= i
;
346 * If an empty file, exit silently
352 * Pop all modules currently on the stream.
354 if ((i
= pop_modules(Oldlist
.sl_nmods
- 1))
355 != (Oldlist
.sl_nmods
- 1)) {
356 /* put back whatever we've popped */
364 for (i
= newlist
.sl_nmods
- 1; i
>= 0; --i
) {
365 if (push_module(newlist
.sl_modlist
[i
].l_name
) ==
369 * pop whatever new modules we've pushed
370 * then push old module list back on
372 restore((newlist
.sl_nmods
- 1 - i
),
373 (Oldlist
.sl_nmods
- 1));
376 * If the stream is a tty line, at least try
377 * to set the state to what it was before.
380 ioctl(STDIN
, TCSETA
, &termio
) < 0) {
382 (void) fprintf(stderr
,
383 "%s: WARNING: Could not restore "
384 "the states of the terminal line "
385 "discipline\n", Cmd_namep
);
391 } /* end if-fromfile */
395 * pop all modules (except driver)
398 if (Oldlist
.sl_nmods
> 1) {
399 if ((i
= pop_modules(Oldlist
.sl_nmods
- 1)) !=
400 (Oldlist
.sl_nmods
- 1)) {
409 * pop up to (but not including) a module
413 * check that the module is in fact on the stream
415 for (i
= 0; i
< Oldlist
.sl_nmods
; ++i
)
416 if (strncmp(Oldlist
.sl_modlist
[i
].l_name
, modnamep
,
419 if (i
== Oldlist
.sl_nmods
) {
421 (void) fprintf(stderr
, "%s: %s not found on stream\n",
422 Cmd_namep
, modnamep
);
426 if ((j
= pop_modules(i
)) != i
) {
427 /* put back whatever we've popped */
435 * pop the topmost module
438 if (Oldlist
.sl_nmods
> 1)
439 if (pop_modules(1) != 1)
440 /* no need to restore */
449 * pop_module(n) pop 'n' modules from stream
451 * returns # of modules popped
454 pop_modules(int num_modules
)
458 for (i
= 0; i
< num_modules
; i
++) {
459 if (ioctl(STDIN
, I_POP
, 0) < 0) {
461 (void) fprintf(stderr
,
462 "%s: I_POP ioctl failed\n", Cmd_namep
);
470 * push_module(modnamep) pushes 'modnamep' module on stream
472 * returns SUCCESS or FAILURE
475 push_module(const char *modnamep
)
477 if (ioctl(STDIN
, I_PUSH
, modnamep
) < 0) {
479 (void) fprintf(stderr
,
480 "%s: I_PUSH ioctl of %s failed\n", Cmd_namep
, modnamep
);
488 * restore(npop, npush) restore original state of stream
490 * pops 'npop' modules, then pushes the topmost 'npush' modules from
495 restore(int npop
, int npush
)
499 if ((i
= pop_modules(npop
)) != npop
) {
500 (void) fprintf(stderr
,
501 "%s: WARNING: could not restore state of stream\n",
506 if (npush
>= Oldlist
.sl_nmods
) { /* "cannot" happen */
507 (void) fprintf(stderr
,
508 "%s: internal logic error in restore\n", Cmd_namep
);
509 (void) fprintf(stderr
,
510 "%s: WARNING: could not restore state of stream\n",
515 for (i
= npush
- 1; i
>= 0; --i
) {
516 if (push_module(Oldlist
.sl_modlist
[i
].l_name
) == FAILURE
) {
517 (void) fprintf(stderr
,
518 "%s: WARNING: could not restore state of stream\n",
526 * more_modules(listp, n) allocate space for 'n' modules in 'listp'
528 * returns: SUCCESS or FAILURE
532 more_modules(struct str_list
*listp
, int n
)
535 struct str_mlist
*modp
;
537 if (n
> MAXMODULES
) {
538 (void) fprintf(stderr
,
539 "%s: too many modules (%d) -- max is %d\n",
540 Cmd_namep
, n
, MAXMODULES
);
544 if ((modp
= calloc(n
, sizeof (struct str_mlist
))) == NULL
) {
546 (void) fprintf(stderr
,
547 "%s: failed to allocate space for module list\n",
552 for (i
= 0; i
< listp
->sl_nmods
; ++i
)
553 (void) strncpy(modp
[i
].l_name
, listp
->sl_modlist
[i
].l_name
,
556 listp
->sl_modlist
= modp
;