#define AP_VERSION 1
#include <sys/types.h>
#include <sys/conf.h>
#include <sys/modctl.h>
#include <sys/sad.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <locale.h>
#include <sys/stat.h>
#include <zone.h>
#define OPTIONS "M:f:gm:r"
#define COMMENT '#'
#define MINUS '-'
#define SLASH '/'
#define OHEADER " Major Minor Lastminor\tModules\n"
#define OFORMAT1_ONE "%10ld %10ld - \t"
#define OFORMAT1_RANGE "%10ld %10ld %10ld\t"
#define OFORMAT1_ALL "%10ld ALL - \t"
#define AP_ANCHOR "[anchor]"
#define Openerr gettext("%s: ERROR: Could not open %s: ")
#define Digiterr gettext("%s: ERROR: argument to %s option must be " \
"numeric\n")
#define Badline gettext("%s: WARNING: File %s: bad input line %d " \
"ignored\n")
static void usage();
static int rem_info(), get_info(), set_info();
static int is_white_space(), parse_line();
static char *Cmdp;
int
main(int argc, char *argv[])
{
int c;
char *filenamep;
major_t major;
minor_t minor;
char *cp;
int exitcode;
ushort_t minflag = 0;
ushort_t majflag = 0;
ushort_t fflag = 0;
ushort_t rflag = 0;
ushort_t gflag = 0;
ushort_t errflag = 0;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
Cmdp = argv[0];
for (filenamep = argv[0]; *filenamep; filenamep++)
if (*filenamep == SLASH)
Cmdp = filenamep + 1;
while (!errflag && ((c = getopt(argc, argv, OPTIONS)) != -1)) {
switch (c) {
case 'M':
if (fflag|majflag)
errflag++;
else {
majflag++;
for (cp = optarg; *cp; cp++)
if (!isdigit(*cp)) {
(void) fprintf(stderr,
Digiterr, Cmdp, "-M");
exit(1);
}
major = (major_t)atol(optarg);
}
break;
case 'm':
if (fflag|minflag)
errflag++;
else {
minflag++;
for (cp = optarg; *cp; cp++)
if (!isdigit(*cp)) {
(void) fprintf(stderr,
Digiterr, Cmdp, "-m");
exit(1);
}
minor = (minor_t)atol(optarg);
}
break;
case 'f':
if (fflag|gflag|rflag|majflag|minflag)
errflag++;
else {
fflag++;
filenamep = optarg;
}
break;
case 'r':
if (fflag|gflag|rflag)
errflag++;
else
rflag++;
break;
case 'g':
if (fflag|gflag|rflag)
errflag++;
else
gflag++;
break;
default:
errflag++;
break;
}
if (errflag) {
usage();
exit(1);
}
}
if (((gflag || rflag) && (!majflag || !minflag)) || (optind != argc)) {
usage();
exit(1);
}
if (getzoneid() != GLOBAL_ZONEID) {
(void) fprintf(stderr, gettext("autopush "
"can only be run from the global zone.\n"));
exit(1);
}
if (fflag)
exitcode = set_info(filenamep);
else if (rflag)
exitcode = rem_info(major, minor);
else if (gflag)
exitcode = get_info(major, minor);
else {
usage();
exit(1);
}
return (exitcode);
}
static void
usage()
{
(void) fprintf(stderr, gettext("%s: USAGE:\n\t%s -f filename\n"
"\t%s -r -M major -m minor\n"
"\t%s -g -M major -m minor\n"), Cmdp, Cmdp, Cmdp, Cmdp);
}
static int
set_info(char *namep)
{
int line;
FILE *fp;
char buf[256];
struct strapush push;
int sadfd;
int retcode = 0;
int parsecode;
if ((sadfd = open(ADMINDEV, O_RDWR)) < 0) {
(void) fprintf(stderr, Openerr, Cmdp, ADMINDEV);
perror("");
return (1);
}
if ((fp = fopen(namep, "r")) == NULL) {
(void) fprintf(stderr, Openerr, Cmdp, namep);
perror("");
return (1);
}
line = 0;
while (fgets(buf, sizeof (buf), fp) != NULL) {
line++;
if ((buf[0] == COMMENT) || is_white_space(buf))
continue;
(void) memset(&push, 0, sizeof (struct strapush));
parsecode = parse_line(buf, line, namep, &push);
if (parsecode != 0) {
retcode = parsecode;
continue;
}
if (push.sap_minor == (minor_t)-1)
push.sap_cmd = SAP_ALL;
else if (push.sap_lastminor == 0)
push.sap_cmd = SAP_ONE;
else
push.sap_cmd = SAP_RANGE;
if (ioctl(sadfd, SAD_SAP, &push) < 0) {
int error = errno;
retcode = 1;
(void) fprintf(stderr,
gettext("%s: ERROR: File %s: could not configure "
"autopush for line %d\n"), Cmdp, namep, line);
switch (error) {
case EPERM:
(void) fprintf(stderr, gettext("%s: ERROR: "
"You don't have permission to set autopush "
"information\n"), Cmdp);
break;
case EINVAL:
(void) fprintf(stderr, gettext("%s: ERROR: "
"Invalid major device number or invalid "
"module name or too many modules\n"), Cmdp);
break;
case ENOSTR:
(void) fprintf(stderr, gettext("%s: ERROR: "
"Major device is not a STREAMS "
"driver\n"), Cmdp);
break;
case EEXIST:
(void) fprintf(stderr, gettext("%s: ERROR: "
"Major/minor already configured\n"), Cmdp);
break;
case ENOSR:
(void) fprintf(stderr, gettext("%s: ERROR: Ran "
"out of autopush structures\n"), Cmdp);
break;
case ERANGE:
(void) fprintf(stderr, gettext("%s: ERROR: "
"lastminor must be greater than minor\n"),
Cmdp);
break;
default:
(void) fprintf(stderr, gettext("%s: ERROR: "),
Cmdp);
(void) fprintf(stderr, "%s\n", strerror(error));
break;
}
}
}
return (retcode);
}
static int
rem_info(major_t maj, minor_t min)
{
struct strapush push;
int sadfd;
int retcode = 0;
if ((sadfd = open(ADMINDEV, O_RDWR)) < 0) {
(void) fprintf(stderr, Openerr, Cmdp, ADMINDEV);
perror("");
return (1);
}
push.sap_cmd = SAP_CLEAR;
push.sap_minor = min;
push.sap_major = maj;
if (ioctl(sadfd, SAD_SAP, &push) < 0) {
int error = errno;
retcode = 1;
(void) fprintf(stderr, gettext("%s: ERROR: Could not remove "
"autopush information\n"), Cmdp);
switch (error) {
case EPERM:
(void) fprintf(stderr, gettext("%s: ERROR: You don't "
"have permission to remove autopush "
"information\n"), Cmdp);
break;
case EINVAL:
if ((min != 0) && (ioctl(sadfd, SAD_GAP, &push) == 0) &&
(push.sap_cmd == SAP_ALL))
(void) fprintf(stderr, gettext("%s: ERROR: "
"When removing an entry for ALL minors, "
"minor must be set to 0\n"), Cmdp);
else
(void) fprintf(stderr, gettext("%s: ERROR: "
"Invalid major device number\n"), Cmdp);
break;
case ENODEV:
(void) fprintf(stderr, gettext("%s: ERROR: Major/minor "
"not configured for autopush\n"), Cmdp);
break;
case ERANGE:
(void) fprintf(stderr, gettext("%s: ERROR: minor must "
"be set to begining of range when clearing\n"),
Cmdp);
break;
default:
(void) fprintf(stderr, gettext("%s: ERROR: "), Cmdp);
(void) fprintf(stderr, "%s\n", strerror(error));
break;
}
}
return (retcode);
}
static int
get_info(major_t maj, minor_t min)
{
struct strapush push;
int i;
int sadfd;
if ((sadfd = open(USERDEV, O_RDWR)) < 0) {
(void) fprintf(stderr, Openerr, Cmdp, USERDEV);
perror("");
return (1);
}
push.sap_major = maj;
push.sap_minor = min;
if (ioctl(sadfd, SAD_GAP, &push) < 0) {
int error = errno;
(void) fprintf(stderr, gettext("%s: ERROR: Could not get "
"autopush information\n"), Cmdp);
switch (error) {
case EINVAL:
(void) fprintf(stderr, gettext("%s: ERROR: Invalid "
"major device number\n"), Cmdp);
break;
case ENOSTR:
(void) fprintf(stderr, gettext("%s: ERROR: Major "
"device is not a STREAMS driver\n"), Cmdp);
break;
case ENODEV:
(void) fprintf(stderr, gettext("%s: ERROR: Major/minor "
"not configured for autopush\n"), Cmdp);
break;
default:
(void) fprintf(stderr, gettext("%s: ERROR: "), Cmdp);
(void) fprintf(stderr, "%s\n", strerror(error));
break;
}
return (1);
}
(void) printf(OHEADER);
switch (push.sap_cmd) {
case SAP_ONE:
(void) printf(OFORMAT1_ONE, push.sap_major, push.sap_minor);
break;
case SAP_RANGE:
(void) printf(OFORMAT1_RANGE, push.sap_major, push.sap_minor,
push.sap_lastminor);
break;
case SAP_ALL:
(void) printf(OFORMAT1_ALL, push.sap_major);
break;
default:
(void) fprintf(stderr,
gettext("%s: ERROR: Unknown configuration type\n"), Cmdp);
return (1);
}
for (i = 0; i < push.sap_npush; i++) {
(void) printf("%s", push.sap_list[i]);
if (push.sap_anchor == (i + 1))
(void) printf(" %s", AP_ANCHOR);
if (i < push.sap_npush - 1)
(void) printf(" ");
}
(void) printf("\n");
return (0);
}
static int
is_white_space(char *bufp)
{
while (*bufp) {
if (!isspace(*bufp))
return (0);
bufp++;
}
return (1);
}
static int
parse_line(char *linep, int lineno, char *namep, struct strapush *pushp)
{
char *wp;
char *cp;
int midx;
int npush;
char c;
major_t major_num;
pushp->sap_anchor = 0;
for (wp = linep; isspace(*wp); wp++)
;
for (cp = wp; !isspace(*cp); cp++)
;
if (!isspace(*cp)) {
(void) fprintf(stderr, Badline, Cmdp, namep, lineno);
return (1);
}
c = *cp;
*cp = '\0';
if (modctl(MODGETMAJBIND, wp, strlen(wp) + 1, &major_num) != 0) {
(void) fprintf(stderr, Badline, Cmdp, namep, lineno);
return (1);
}
*cp = c;
pushp->sap_major = major_num;
for (wp = cp; isspace(*wp); wp++)
;
for (cp = wp; (isdigit(*cp) || (*cp == MINUS)); cp++)
;
if (!isspace(*cp)) {
(void) fprintf(stderr, Badline, Cmdp, namep, lineno);
return (1);
}
pushp->sap_minor = (minor_t)atol(wp);
for (wp = cp; isspace(*wp); wp++)
;
for (cp = wp; isdigit(*cp); cp++)
;
if (!isspace(*cp)) {
(void) fprintf(stderr, Badline, Cmdp, namep, lineno);
return (1);
}
pushp->sap_lastminor = (minor_t)atol(wp);
npush = 0;
while ((npush < MAXAPUSH) && (*cp)) {
while (isspace(*cp))
cp++;
if (strncasecmp(cp, AP_ANCHOR, sizeof (AP_ANCHOR) - 1) == 0) {
if (pushp->sap_anchor != 0) {
(void) fprintf(stderr,
gettext("%s: ERROR: File %s: more than "
"one anchor in line, line %d ignored\n"),
Cmdp, namep, lineno);
return (1);
}
if (npush == 0)
(void) fprintf(stderr,
gettext("%s: WARNING: File %s: anchor at "
"beginning of stream on line %d ignored\n"),
Cmdp, namep, lineno);
pushp->sap_anchor = npush;
cp += sizeof (AP_ANCHOR) - 1;
continue;
}
for (midx = 0; !isspace(*cp) && *cp; midx++) {
if (midx == FMNAMESZ) {
(void) fprintf(stderr, gettext("%s: ERROR: "
"File %s: module name too long, line %d "
"ignored\n"), Cmdp, namep, lineno);
return (1);
}
pushp->sap_list[npush][midx] = *cp++;
}
if (midx > 0) {
pushp->sap_list[npush][midx] = '\0';
npush++;
}
}
pushp->sap_npush = npush;
while (isspace(*cp))
cp++;
if (*cp) {
(void) fprintf(stderr,
gettext("%s: ERROR: File %s: too many modules, line %d "
"ignored\n"), Cmdp, namep, lineno);
return (1);
}
return (0);
}