4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
31 * autopush(1) is the command interface to the STREAMS autopush
32 * mechanism. The autopush command can be used to configure autopush
33 * information about a STREAMS driver, remove autopush information,
34 * and report on current configuration information. Its use is as
38 * autopush -r -M major -m minor
39 * autopush -g -M major -m minor
41 * The -f option allows autopush information to be set from a file. The
42 * format of the file is as follows:
44 * # Comment lines begin with a # in column one.
45 * # The fields are separated by white space and are:
46 * # major minor lastminor module1 module2 ... module8
48 * "lastminor" is used to configure ranges of minor devices, from "minor"
49 * to "lastminor" inclusive. It should be set to zero when not in use.
50 * The -r option allows autopush information to be removed for the given
51 * major/minor pair. The -g option allows the configuration information
52 * to be printed. The format of printing is the same as for the file.
56 * Use autopush version 1; keep before #include <sys/sad.h>.
57 * See <sys/sad.h> for details.
61 #include <sys/types.h>
63 #include <sys/modctl.h>
76 #define OPTIONS "M:f:gm:r" /* command line options for getopt(3C) */
84 #define OHEADER " Major Minor Lastminor\tModules\n"
85 #define OFORMAT1_ONE "%10ld %10ld - \t"
86 #define OFORMAT1_RANGE "%10ld %10ld %10ld\t"
87 #define OFORMAT1_ALL "%10ld ALL - \t"
89 #define AP_ANCHOR "[anchor]"
91 #define Openerr gettext("%s: ERROR: Could not open %s: ")
92 #define Digiterr gettext("%s: ERROR: argument to %s option must be " \
94 #define Badline gettext("%s: WARNING: File %s: bad input line %d " \
98 static int rem_info(), get_info(), set_info();
99 static int is_white_space(), parse_line();
101 static char *Cmdp
; /* command name */
105 * process command line arguments.
108 main(int argc
, char *argv
[])
110 int c
; /* character read by getopt(3C) */
111 char *filenamep
; /* name of configuration file */
112 major_t major
; /* major device number */
113 minor_t minor
; /* minor device number */
116 ushort_t minflag
= 0; /* -m option used */
117 ushort_t majflag
= 0; /* -M option used */
118 ushort_t fflag
= 0; /* -f option used */
119 ushort_t rflag
= 0; /* -r option used */
120 ushort_t gflag
= 0; /* -g option used */
121 ushort_t errflag
= 0; /* options usage error */
123 (void) setlocale(LC_ALL
, "");
124 #if !defined(TEXT_DOMAIN)
125 #define TEXT_DOMAIN "SYS_TEST"
127 (void) textdomain(TEXT_DOMAIN
);
133 for (filenamep
= argv
[0]; *filenamep
; filenamep
++)
134 if (*filenamep
== SLASH
)
135 Cmdp
= filenamep
+ 1;
140 while (!errflag
&& ((c
= getopt(argc
, argv
, OPTIONS
)) != -1)) {
147 for (cp
= optarg
; *cp
; cp
++)
149 (void) fprintf(stderr
,
150 Digiterr
, Cmdp
, "-M");
153 major
= (major_t
)atol(optarg
);
162 for (cp
= optarg
; *cp
; cp
++)
164 (void) fprintf(stderr
,
165 Digiterr
, Cmdp
, "-m");
168 minor
= (minor_t
)atol(optarg
);
173 if (fflag
|gflag
|rflag
|majflag
|minflag
)
182 if (fflag
|gflag
|rflag
)
189 if (fflag
|gflag
|rflag
)
204 if (((gflag
|| rflag
) && (!majflag
|| !minflag
)) || (optind
!= argc
)) {
209 if (getzoneid() != GLOBAL_ZONEID
) {
210 (void) fprintf(stderr
, gettext("autopush "
211 "can only be run from the global zone.\n"));
216 exitcode
= set_info(filenamep
);
218 exitcode
= rem_info(major
, minor
);
220 exitcode
= get_info(major
, minor
);
231 * print out usage statement.
236 (void) fprintf(stderr
, gettext("%s: USAGE:\n\t%s -f filename\n"
237 "\t%s -r -M major -m minor\n"
238 "\t%s -g -M major -m minor\n"), Cmdp
, Cmdp
, Cmdp
, Cmdp
);
243 * set autopush configuration information.
244 * namep: autopush configuration filename
247 set_info(char *namep
)
249 int line
; /* line number of file */
250 FILE *fp
; /* file pointer of config file */
251 char buf
[256]; /* input buffer */
252 struct strapush push
; /* configuration information */
253 int sadfd
; /* file descriptor to SAD driver */
254 int retcode
= 0; /* return code */
255 int parsecode
; /* return value from parse function */
257 if ((sadfd
= open(ADMINDEV
, O_RDWR
)) < 0) {
258 (void) fprintf(stderr
, Openerr
, Cmdp
, ADMINDEV
);
262 if ((fp
= fopen(namep
, "r")) == NULL
) {
263 (void) fprintf(stderr
, Openerr
, Cmdp
, namep
);
268 while (fgets(buf
, sizeof (buf
), fp
) != NULL
) {
270 if ((buf
[0] == COMMENT
) || is_white_space(buf
))
272 (void) memset(&push
, 0, sizeof (struct strapush
));
274 parsecode
= parse_line(buf
, line
, namep
, &push
);
275 if (parsecode
!= 0) {
280 if (push
.sap_minor
== (minor_t
)-1)
281 push
.sap_cmd
= SAP_ALL
;
282 else if (push
.sap_lastminor
== 0)
283 push
.sap_cmd
= SAP_ONE
;
285 push
.sap_cmd
= SAP_RANGE
;
287 if (ioctl(sadfd
, SAD_SAP
, &push
) < 0) {
291 (void) fprintf(stderr
,
292 gettext("%s: ERROR: File %s: could not configure "
293 "autopush for line %d\n"), Cmdp
, namep
, line
);
296 (void) fprintf(stderr
, gettext("%s: ERROR: "
297 "You don't have permission to set autopush "
298 "information\n"), Cmdp
);
302 (void) fprintf(stderr
, gettext("%s: ERROR: "
303 "Invalid major device number or invalid "
304 "module name or too many modules\n"), Cmdp
);
308 (void) fprintf(stderr
, gettext("%s: ERROR: "
309 "Major device is not a STREAMS "
314 (void) fprintf(stderr
, gettext("%s: ERROR: "
315 "Major/minor already configured\n"), Cmdp
);
319 (void) fprintf(stderr
, gettext("%s: ERROR: Ran "
320 "out of autopush structures\n"), Cmdp
);
324 (void) fprintf(stderr
, gettext("%s: ERROR: "
325 "lastminor must be greater than minor\n"),
330 (void) fprintf(stderr
, gettext("%s: ERROR: "),
332 (void) fprintf(stderr
, "%s\n", strerror(error
));
342 * remove autopush configuration information.
345 rem_info(major_t maj
, minor_t min
)
347 struct strapush push
; /* configuration information */
348 int sadfd
; /* file descriptor to SAD driver */
349 int retcode
= 0; /* return code */
351 if ((sadfd
= open(ADMINDEV
, O_RDWR
)) < 0) {
352 (void) fprintf(stderr
, Openerr
, Cmdp
, ADMINDEV
);
356 push
.sap_cmd
= SAP_CLEAR
;
357 push
.sap_minor
= min
;
358 push
.sap_major
= maj
;
360 if (ioctl(sadfd
, SAD_SAP
, &push
) < 0) {
364 (void) fprintf(stderr
, gettext("%s: ERROR: Could not remove "
365 "autopush information\n"), Cmdp
);
368 (void) fprintf(stderr
, gettext("%s: ERROR: You don't "
369 "have permission to remove autopush "
370 "information\n"), Cmdp
);
374 if ((min
!= 0) && (ioctl(sadfd
, SAD_GAP
, &push
) == 0) &&
375 (push
.sap_cmd
== SAP_ALL
))
376 (void) fprintf(stderr
, gettext("%s: ERROR: "
377 "When removing an entry for ALL minors, "
378 "minor must be set to 0\n"), Cmdp
);
380 (void) fprintf(stderr
, gettext("%s: ERROR: "
381 "Invalid major device number\n"), Cmdp
);
385 (void) fprintf(stderr
, gettext("%s: ERROR: Major/minor "
386 "not configured for autopush\n"), Cmdp
);
390 (void) fprintf(stderr
, gettext("%s: ERROR: minor must "
391 "be set to begining of range when clearing\n"),
396 (void) fprintf(stderr
, gettext("%s: ERROR: "), Cmdp
);
397 (void) fprintf(stderr
, "%s\n", strerror(error
));
406 * get autopush configuration information.
409 get_info(major_t maj
, minor_t min
)
411 struct strapush push
; /* configuration information */
413 int sadfd
; /* file descriptor to SAD driver */
415 if ((sadfd
= open(USERDEV
, O_RDWR
)) < 0) {
416 (void) fprintf(stderr
, Openerr
, Cmdp
, USERDEV
);
420 push
.sap_major
= maj
;
421 push
.sap_minor
= min
;
423 if (ioctl(sadfd
, SAD_GAP
, &push
) < 0) {
426 (void) fprintf(stderr
, gettext("%s: ERROR: Could not get "
427 "autopush information\n"), Cmdp
);
430 (void) fprintf(stderr
, gettext("%s: ERROR: Invalid "
431 "major device number\n"), Cmdp
);
435 (void) fprintf(stderr
, gettext("%s: ERROR: Major "
436 "device is not a STREAMS driver\n"), Cmdp
);
440 (void) fprintf(stderr
, gettext("%s: ERROR: Major/minor "
441 "not configured for autopush\n"), Cmdp
);
445 (void) fprintf(stderr
, gettext("%s: ERROR: "), Cmdp
);
446 (void) fprintf(stderr
, "%s\n", strerror(error
));
451 (void) printf(OHEADER
);
452 switch (push
.sap_cmd
) {
454 (void) printf(OFORMAT1_ONE
, push
.sap_major
, push
.sap_minor
);
458 (void) printf(OFORMAT1_RANGE
, push
.sap_major
, push
.sap_minor
,
463 (void) printf(OFORMAT1_ALL
, push
.sap_major
);
467 (void) fprintf(stderr
,
468 gettext("%s: ERROR: Unknown configuration type\n"), Cmdp
);
472 for (i
= 0; i
< push
.sap_npush
; i
++) {
474 (void) printf("%s", push
.sap_list
[i
]);
476 if (push
.sap_anchor
== (i
+ 1))
477 (void) printf(" %s", AP_ANCHOR
);
479 if (i
< push
.sap_npush
- 1)
490 * Return 1 if buffer is all white space.
491 * Return 0 otherwise.
494 is_white_space(char *bufp
)
506 * Parse input line from file and report any errors found. Fill
507 * strapush structure along the way. Returns 1 if the line has
508 * errors and 0 if the line is well-formed. Another hidden
509 * dependency on MAXAPUSH. `linep' is the input buffer, `lineno'
510 * is the current line number, and `namep' is the filename.
513 parse_line(char *linep
, int lineno
, char *namep
, struct strapush
*pushp
)
515 char *wp
; /* word pointer */
516 char *cp
; /* character pointer */
517 int midx
; /* module index */
518 int npush
; /* number of modules to push */
522 pushp
->sap_anchor
= 0; /* by default, no anchor */
525 * Find the major device number.
527 for (wp
= linep
; isspace(*wp
); wp
++)
529 for (cp
= wp
; !isspace(*cp
); cp
++)
532 (void) fprintf(stderr
, Badline
, Cmdp
, namep
, lineno
);
537 if (modctl(MODGETMAJBIND
, wp
, strlen(wp
) + 1, &major_num
) != 0) {
538 (void) fprintf(stderr
, Badline
, Cmdp
, namep
, lineno
);
542 pushp
->sap_major
= major_num
;
545 * Find the minor device number. Must handle negative values here.
547 for (wp
= cp
; isspace(*wp
); wp
++)
549 for (cp
= wp
; (isdigit(*cp
) || (*cp
== MINUS
)); cp
++)
552 (void) fprintf(stderr
, Badline
, Cmdp
, namep
, lineno
);
555 pushp
->sap_minor
= (minor_t
)atol(wp
);
558 * Find the lastminor.
560 for (wp
= cp
; isspace(*wp
); wp
++)
562 for (cp
= wp
; isdigit(*cp
); cp
++)
565 (void) fprintf(stderr
, Badline
, Cmdp
, namep
, lineno
);
568 pushp
->sap_lastminor
= (minor_t
)atol(wp
);
571 * Read the list of module names.
574 while ((npush
< MAXAPUSH
) && (*cp
)) {
579 if (strncasecmp(cp
, AP_ANCHOR
, sizeof (AP_ANCHOR
) - 1) == 0) {
580 if (pushp
->sap_anchor
!= 0) {
581 (void) fprintf(stderr
,
582 gettext("%s: ERROR: File %s: more than "
583 "one anchor in line, line %d ignored\n"),
584 Cmdp
, namep
, lineno
);
588 (void) fprintf(stderr
,
589 gettext("%s: WARNING: File %s: anchor at "
590 "beginning of stream on line %d ignored\n"),
591 Cmdp
, namep
, lineno
);
592 pushp
->sap_anchor
= npush
;
593 cp
+= sizeof (AP_ANCHOR
) - 1;
597 for (midx
= 0; !isspace(*cp
) && *cp
; midx
++) {
598 if (midx
== FMNAMESZ
) {
599 (void) fprintf(stderr
, gettext("%s: ERROR: "
600 "File %s: module name too long, line %d "
601 "ignored\n"), Cmdp
, namep
, lineno
);
604 pushp
->sap_list
[npush
][midx
] = *cp
++;
608 pushp
->sap_list
[npush
][midx
] = '\0';
612 pushp
->sap_npush
= npush
;
615 * We have everything we want from the line.
616 * Now make sure there is no extra garbage on the line.
621 (void) fprintf(stderr
,
622 gettext("%s: ERROR: File %s: too many modules, line %d "
623 "ignored\n"), Cmdp
, namep
, lineno
);