2004-11-13 22:14:48 +03:00
|
|
|
/* $NetBSD: ipscan_y.y,v 1.2 2004/11/13 19:16:10 he Exp $ */
|
2004-03-28 12:55:20 +04:00
|
|
|
|
|
|
|
%{
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include "ipf.h"
|
|
|
|
#include "opts.h"
|
|
|
|
#include "kmem.h"
|
|
|
|
#include "ipscan_l.h"
|
|
|
|
#include "netinet/ip_scan.h"
|
|
|
|
|
|
|
|
#define YYDEBUG 1
|
|
|
|
|
|
|
|
extern char *optarg;
|
|
|
|
extern void yyerror __P((char *));
|
|
|
|
extern int yyparse __P((void));
|
|
|
|
extern int yylex __P((void));
|
|
|
|
extern int yydebug;
|
|
|
|
extern FILE *yyin;
|
|
|
|
extern int yylineNum;
|
|
|
|
extern void printbuf __P((char *, int, int));
|
|
|
|
|
|
|
|
|
|
|
|
void printent __P((ipscan_t *));
|
|
|
|
void showlist __P((void));
|
|
|
|
int getportnum __P((char *));
|
|
|
|
struct in_addr gethostip __P((char *));
|
|
|
|
struct in_addr combine __P((int, int, int, int));
|
|
|
|
char **makepair __P((char *, char *));
|
|
|
|
void addtag __P((char *, char **, char **, struct action *));
|
|
|
|
int cram __P((char *, char *));
|
|
|
|
void usage __P((char *));
|
|
|
|
int main __P((int, char **));
|
|
|
|
|
|
|
|
int opts = 0;
|
|
|
|
int fd = -1;
|
|
|
|
|
|
|
|
|
|
|
|
%}
|
|
|
|
|
|
|
|
%union {
|
|
|
|
char *str;
|
|
|
|
char **astr;
|
|
|
|
u_32_t num;
|
|
|
|
struct in_addr ipa;
|
|
|
|
struct action act;
|
|
|
|
union i6addr ip6;
|
|
|
|
}
|
|
|
|
|
|
|
|
%type <str> tag
|
|
|
|
%type <act> action redirect result
|
|
|
|
%type <ipa> ipaddr
|
|
|
|
%type <num> portnum
|
|
|
|
%type <astr> matchup onehalf twohalves
|
|
|
|
|
|
|
|
%token <num> YY_NUMBER YY_HEX
|
|
|
|
%token <str> YY_STR
|
|
|
|
%token YY_COMMENT
|
|
|
|
%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
|
|
|
|
%token YY_RANGE_OUT YY_RANGE_IN
|
|
|
|
%token <ip6> YY_IPV6
|
|
|
|
%token IPSL_START IPSL_STARTGROUP IPSL_CONTENT
|
|
|
|
|
|
|
|
%token IPSL_CLOSE IPSL_TRACK IPSL_EOF IPSL_REDIRECT IPSL_ELSE
|
|
|
|
|
|
|
|
%%
|
|
|
|
file: line ';'
|
|
|
|
| assign ';'
|
|
|
|
| file line ';'
|
|
|
|
| file assign ';'
|
|
|
|
| YY_COMMENT
|
|
|
|
;
|
|
|
|
|
|
|
|
line: IPSL_START dline
|
|
|
|
| IPSL_STARTGROUP gline
|
|
|
|
| IPSL_CONTENT oline
|
|
|
|
;
|
|
|
|
|
|
|
|
dline: cline { resetlexer(); }
|
|
|
|
| sline { resetlexer(); }
|
|
|
|
| csline { resetlexer(); }
|
|
|
|
;
|
|
|
|
|
|
|
|
gline: YY_STR ':' glist '=' action
|
|
|
|
;
|
|
|
|
|
|
|
|
oline: cline
|
|
|
|
| sline
|
|
|
|
| csline
|
|
|
|
;
|
|
|
|
|
|
|
|
assign: YY_STR assigning YY_STR
|
|
|
|
{ set_variable($1, $3);
|
|
|
|
resetlexer();
|
|
|
|
free($1);
|
|
|
|
free($3);
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
assigning:
|
|
|
|
'=' { yyvarnext = 1; }
|
|
|
|
;
|
|
|
|
|
|
|
|
cline: tag ':' matchup '=' action { addtag($1, $3, NULL, &$5); }
|
|
|
|
;
|
|
|
|
|
|
|
|
sline: tag ':' '(' ')' ',' matchup '=' action { addtag($1, NULL, $6, &$8); }
|
|
|
|
;
|
|
|
|
|
|
|
|
csline: tag ':' matchup ',' matchup '=' action { addtag($1, $3, $5, &$7); }
|
|
|
|
;
|
|
|
|
|
|
|
|
glist: YY_STR
|
|
|
|
| glist ',' YY_STR
|
|
|
|
;
|
|
|
|
|
|
|
|
tag: YY_STR { $$ = $1; }
|
|
|
|
;
|
|
|
|
|
|
|
|
matchup:
|
|
|
|
onehalf { $$ = $1; }
|
|
|
|
| twohalves { $$ = $1; }
|
|
|
|
;
|
|
|
|
|
|
|
|
action: result { $$.act_val = $1.act_val;
|
|
|
|
$$.act_ip = $1.act_ip;
|
|
|
|
$$.act_port = $1.act_port; }
|
|
|
|
| result IPSL_ELSE result { $$.act_val = $1.act_val;
|
|
|
|
$$.act_else = $3.act_val;
|
|
|
|
if ($1.act_val == IPSL_REDIRECT) {
|
|
|
|
$$.act_ip = $1.act_ip;
|
|
|
|
$$.act_port = $1.act_port;
|
|
|
|
}
|
|
|
|
if ($3.act_val == IPSL_REDIRECT) {
|
|
|
|
$$.act_eip = $3.act_eip;
|
|
|
|
$$.act_eport = $3.act_eport;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result: IPSL_CLOSE { $$.act_val = IPSL_CLOSE; }
|
|
|
|
| IPSL_TRACK { $$.act_val = IPSL_TRACK; }
|
|
|
|
| redirect { $$.act_val = IPSL_REDIRECT;
|
|
|
|
$$.act_ip = $1.act_ip;
|
|
|
|
$$.act_port = $1.act_port; }
|
|
|
|
;
|
|
|
|
|
|
|
|
onehalf:
|
|
|
|
'(' YY_STR ')' { $$ = makepair($2, NULL); }
|
|
|
|
;
|
|
|
|
|
|
|
|
twohalves:
|
|
|
|
'(' YY_STR ',' YY_STR ')' { $$ = makepair($2, $4); }
|
|
|
|
;
|
|
|
|
|
|
|
|
redirect:
|
|
|
|
IPSL_REDIRECT '(' ipaddr ')' { $$.act_ip = $3;
|
|
|
|
$$.act_port = 0; }
|
|
|
|
| IPSL_REDIRECT '(' ipaddr ',' portnum ')'
|
|
|
|
{ $$.act_ip = $3;
|
|
|
|
$$.act_port = $5; }
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
ipaddr: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
|
|
|
|
{ $$ = combine($1,$3,$5,$7); }
|
|
|
|
| YY_STR { $$ = gethostip($1);
|
|
|
|
free($1);
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
portnum:
|
|
|
|
YY_NUMBER { $$ = htons($1); }
|
|
|
|
| YY_STR { $$ = getportnum($1);
|
|
|
|
free($1);
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
%%
|
|
|
|
|
|
|
|
|
|
|
|
static struct wordtab yywords[] = {
|
|
|
|
{ "close", IPSL_CLOSE },
|
|
|
|
{ "content", IPSL_CONTENT },
|
|
|
|
{ "else", IPSL_ELSE },
|
|
|
|
{ "start-group", IPSL_STARTGROUP },
|
|
|
|
{ "redirect", IPSL_REDIRECT },
|
|
|
|
{ "start", IPSL_START },
|
|
|
|
{ "track", IPSL_TRACK },
|
|
|
|
{ NULL, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
int cram(dst, src)
|
|
|
|
char *dst;
|
|
|
|
char *src;
|
|
|
|
{
|
|
|
|
char c, *s, *t, *u;
|
|
|
|
int i, j, k;
|
|
|
|
|
|
|
|
c = *src;
|
|
|
|
s = src + 1;
|
|
|
|
t = strchr(s, c);
|
|
|
|
*t = '\0';
|
|
|
|
for (u = dst, i = 0; (i <= ISC_TLEN) && (s < t); ) {
|
|
|
|
c = *s++;
|
|
|
|
if (c == '\\') {
|
|
|
|
if (s >= t)
|
|
|
|
break;
|
|
|
|
j = k = 0;
|
|
|
|
do {
|
|
|
|
c = *s++;
|
2004-11-13 22:14:48 +03:00
|
|
|
if (j && (!ISDIGIT(c) || (c > '7') ||
|
2004-03-28 12:55:20 +04:00
|
|
|
(k >= 248))) {
|
|
|
|
*u++ = k, i++;
|
|
|
|
j = k = 0;
|
|
|
|
s--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
|
2004-11-13 22:14:48 +03:00
|
|
|
if (ISALPHA(c) || (c > '7')) {
|
2004-03-28 12:55:20 +04:00
|
|
|
switch (c)
|
|
|
|
{
|
|
|
|
case 'n' :
|
|
|
|
*u++ = '\n';
|
|
|
|
break;
|
|
|
|
case 'r' :
|
|
|
|
*u++ = '\r';
|
|
|
|
break;
|
|
|
|
case 't' :
|
|
|
|
*u++ = '\t';
|
|
|
|
break;
|
|
|
|
default :
|
|
|
|
*u++ = c;
|
|
|
|
break;
|
|
|
|
}
|
2004-11-13 22:14:48 +03:00
|
|
|
} else if (ISDIGIT(c)) {
|
2004-03-28 12:55:20 +04:00
|
|
|
j = 1;
|
|
|
|
k <<= 3;
|
|
|
|
k |= (c - '0');
|
|
|
|
i--;
|
|
|
|
} else
|
|
|
|
*u++ = c;
|
|
|
|
} while ((i <= ISC_TLEN) && (s <= t) && (j > 0));
|
|
|
|
} else
|
|
|
|
*u++ = c, i++;
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void printent(isc)
|
|
|
|
ipscan_t *isc;
|
|
|
|
{
|
|
|
|
char buf[ISC_TLEN+1];
|
|
|
|
u_char *u;
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
buf[ISC_TLEN] = '\0';
|
|
|
|
bcopy(isc->ipsc_ctxt, buf, ISC_TLEN);
|
|
|
|
printf("%s : (\"", isc->ipsc_tag);
|
|
|
|
printbuf(isc->ipsc_ctxt, isc->ipsc_clen, 0);
|
|
|
|
|
|
|
|
bcopy(isc->ipsc_cmsk, buf, ISC_TLEN);
|
|
|
|
printf("\", \"%s\"), (\"", buf);
|
|
|
|
|
|
|
|
printbuf(isc->ipsc_stxt, isc->ipsc_slen, 0);
|
|
|
|
|
|
|
|
bcopy(isc->ipsc_smsk, buf, ISC_TLEN);
|
|
|
|
printf("\", \"%s\") = ", buf);
|
|
|
|
|
|
|
|
switch (isc->ipsc_action)
|
|
|
|
{
|
|
|
|
case ISC_A_TRACK :
|
|
|
|
printf("track");
|
|
|
|
break;
|
|
|
|
case ISC_A_REDIRECT :
|
|
|
|
printf("redirect");
|
|
|
|
printf("(%s", inet_ntoa(isc->ipsc_ip));
|
|
|
|
if (isc->ipsc_port)
|
|
|
|
printf(",%d", isc->ipsc_port);
|
|
|
|
printf(")");
|
|
|
|
break;
|
|
|
|
case ISC_A_CLOSE :
|
|
|
|
printf("close");
|
|
|
|
break;
|
|
|
|
default :
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isc->ipsc_else != ISC_A_NONE) {
|
|
|
|
printf(" else ");
|
|
|
|
switch (isc->ipsc_else)
|
|
|
|
{
|
|
|
|
case ISC_A_TRACK :
|
|
|
|
printf("track");
|
|
|
|
break;
|
|
|
|
case ISC_A_REDIRECT :
|
|
|
|
printf("redirect");
|
|
|
|
printf("(%s", inet_ntoa(isc->ipsc_eip));
|
|
|
|
if (isc->ipsc_eport)
|
|
|
|
printf(",%d", isc->ipsc_eport);
|
|
|
|
printf(")");
|
|
|
|
break;
|
|
|
|
case ISC_A_CLOSE :
|
|
|
|
printf("close");
|
|
|
|
break;
|
|
|
|
default :
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
|
|
|
|
if (opts & OPT_DEBUG) {
|
|
|
|
for (u = (u_char *)isc, i = sizeof(*isc); i; ) {
|
|
|
|
printf("#");
|
|
|
|
for (j = 32; (j > 0) && (i > 0); j--, i--)
|
|
|
|
printf("%s%02x", (j & 7) ? "" : " ", *u++);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (opts & OPT_VERBOSE) {
|
|
|
|
printf("# hits %d active %d fref %d sref %d\n",
|
|
|
|
isc->ipsc_hits, isc->ipsc_active, isc->ipsc_fref,
|
|
|
|
isc->ipsc_sref);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void addtag(tstr, cp, sp, act)
|
|
|
|
char *tstr;
|
|
|
|
char **cp, **sp;
|
|
|
|
struct action *act;
|
|
|
|
{
|
|
|
|
ipscan_t isc, *iscp;
|
|
|
|
|
|
|
|
bzero((char *)&isc, sizeof(isc));
|
|
|
|
|
|
|
|
strncpy(isc.ipsc_tag, tstr, sizeof(isc.ipsc_tag));
|
|
|
|
isc.ipsc_tag[sizeof(isc.ipsc_tag) - 1] = '\0';
|
|
|
|
|
|
|
|
if (cp) {
|
|
|
|
isc.ipsc_clen = cram(isc.ipsc_ctxt, cp[0]);
|
|
|
|
if (cp[1]) {
|
|
|
|
if (cram(isc.ipsc_cmsk, cp[1]) != isc.ipsc_clen) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"client text/mask strings different length\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sp) {
|
|
|
|
isc.ipsc_slen = cram(isc.ipsc_stxt, sp[0]);
|
|
|
|
if (sp[1]) {
|
|
|
|
if (cram(isc.ipsc_smsk, sp[1]) != isc.ipsc_slen) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"server text/mask strings different length\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (act->act_val == IPSL_CLOSE) {
|
|
|
|
isc.ipsc_action = ISC_A_CLOSE;
|
|
|
|
} else if (act->act_val == IPSL_TRACK) {
|
|
|
|
isc.ipsc_action = ISC_A_TRACK;
|
|
|
|
} else if (act->act_val == IPSL_REDIRECT) {
|
|
|
|
isc.ipsc_action = ISC_A_REDIRECT;
|
|
|
|
isc.ipsc_ip = act->act_ip;
|
|
|
|
isc.ipsc_port = act->act_port;
|
|
|
|
fprintf(stderr, "%d: redirect unsupported\n", yylineNum + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (act->act_else == IPSL_CLOSE) {
|
|
|
|
isc.ipsc_else = ISC_A_CLOSE;
|
|
|
|
} else if (act->act_else == IPSL_TRACK) {
|
|
|
|
isc.ipsc_else = ISC_A_TRACK;
|
|
|
|
} else if (act->act_else == IPSL_REDIRECT) {
|
|
|
|
isc.ipsc_else = ISC_A_REDIRECT;
|
|
|
|
isc.ipsc_eip = act->act_eip;
|
|
|
|
isc.ipsc_eport = act->act_eport;
|
|
|
|
fprintf(stderr, "%d: redirect unsupported\n", yylineNum + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(opts & OPT_DONOTHING)) {
|
|
|
|
iscp = &isc;
|
|
|
|
if (opts & OPT_REMOVE) {
|
|
|
|
if (ioctl(fd, SIOCRMSCA, &iscp) == -1)
|
|
|
|
perror("SIOCADSCA");
|
|
|
|
} else {
|
|
|
|
if (ioctl(fd, SIOCADSCA, &iscp) == -1)
|
|
|
|
perror("SIOCADSCA");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opts & OPT_VERBOSE)
|
|
|
|
printent(&isc);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char **makepair(s1, s2)
|
|
|
|
char *s1, *s2;
|
|
|
|
{
|
|
|
|
char **a;
|
|
|
|
|
|
|
|
a = malloc(sizeof(char *) * 2);
|
|
|
|
a[0] = s1;
|
|
|
|
a[1] = s2;
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct in_addr combine(a1, a2, a3, a4)
|
|
|
|
int a1, a2, a3, a4;
|
|
|
|
{
|
|
|
|
struct in_addr in;
|
|
|
|
|
|
|
|
a1 &= 0xff;
|
|
|
|
in.s_addr = a1 << 24;
|
|
|
|
a2 &= 0xff;
|
|
|
|
in.s_addr |= (a2 << 16);
|
|
|
|
a3 &= 0xff;
|
|
|
|
in.s_addr |= (a3 << 8);
|
|
|
|
a4 &= 0xff;
|
|
|
|
in.s_addr |= a4;
|
|
|
|
in.s_addr = htonl(in.s_addr);
|
|
|
|
return in;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct in_addr gethostip(host)
|
|
|
|
char *host;
|
|
|
|
{
|
|
|
|
struct hostent *hp;
|
|
|
|
struct in_addr in;
|
|
|
|
|
|
|
|
in.s_addr = 0;
|
|
|
|
|
|
|
|
hp = gethostbyname(host);
|
|
|
|
if (!hp)
|
|
|
|
return in;
|
|
|
|
bcopy(hp->h_addr, (char *)&in, sizeof(in));
|
|
|
|
return in;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int getportnum(port)
|
|
|
|
char *port;
|
|
|
|
{
|
|
|
|
struct servent *s;
|
|
|
|
|
|
|
|
s = getservbyname(port, "tcp");
|
|
|
|
if (s == NULL)
|
|
|
|
return -1;
|
|
|
|
return s->s_port;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void showlist()
|
|
|
|
{
|
|
|
|
ipscanstat_t ipsc, *ipscp = &ipsc;
|
|
|
|
ipscan_t isc;
|
|
|
|
|
|
|
|
if (ioctl(fd, SIOCGSCST, &ipscp) == -1)
|
|
|
|
perror("ioctl(SIOCGSCST)");
|
|
|
|
else if (opts & OPT_SHOWLIST) {
|
|
|
|
while (ipsc.iscs_list != NULL) {
|
|
|
|
if (kmemcpy((char *)&isc, (u_long)ipsc.iscs_list,
|
|
|
|
sizeof(isc)) == -1) {
|
|
|
|
perror("kmemcpy");
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
printent(&isc);
|
|
|
|
ipsc.iscs_list = isc.ipsc_next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
printf("scan entries loaded\t%d\n", ipsc.iscs_entries);
|
|
|
|
printf("scan entries matches\t%ld\n", ipsc.iscs_acted);
|
|
|
|
printf("negative matches\t%ld\n", ipsc.iscs_else);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void usage(prog)
|
|
|
|
char *prog;
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Usage:\t%s [-dnrv] -f <filename>\n", prog);
|
|
|
|
fprintf(stderr, "\t%s [-dlv]\n", prog);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int main(argc, argv)
|
|
|
|
int argc;
|
|
|
|
char *argv[];
|
|
|
|
{
|
|
|
|
FILE *fp = NULL;
|
|
|
|
int c;
|
|
|
|
|
|
|
|
(void) yysettab(yywords);
|
|
|
|
|
|
|
|
if (argc < 2)
|
|
|
|
usage(argv[0]);
|
|
|
|
|
|
|
|
while ((c = getopt(argc, argv, "df:lnrsv")) != -1)
|
|
|
|
switch (c)
|
|
|
|
{
|
|
|
|
case 'd' :
|
|
|
|
opts |= OPT_DEBUG;
|
|
|
|
yydebug++;
|
|
|
|
break;
|
|
|
|
case 'f' :
|
|
|
|
if (!strcmp(optarg, "-"))
|
|
|
|
fp = stdin;
|
|
|
|
else {
|
|
|
|
fp = fopen(optarg, "r");
|
|
|
|
if (!fp) {
|
|
|
|
perror("open");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
yyin = fp;
|
|
|
|
break;
|
|
|
|
case 'l' :
|
|
|
|
opts |= OPT_SHOWLIST;
|
|
|
|
break;
|
|
|
|
case 'n' :
|
|
|
|
opts |= OPT_DONOTHING;
|
|
|
|
break;
|
|
|
|
case 'r' :
|
|
|
|
opts |= OPT_REMOVE;
|
|
|
|
break;
|
|
|
|
case 's' :
|
|
|
|
opts |= OPT_STAT;
|
|
|
|
break;
|
|
|
|
case 'v' :
|
|
|
|
opts |= OPT_VERBOSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(opts & OPT_DONOTHING)) {
|
|
|
|
fd = open(IPL_SCAN, O_RDWR);
|
|
|
|
if (fd == -1) {
|
|
|
|
perror("open(IPL_SCAN)");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fp != NULL) {
|
|
|
|
yylineNum = 1;
|
|
|
|
|
|
|
|
while (!feof(fp))
|
|
|
|
yyparse();
|
|
|
|
fclose(fp);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opts & (OPT_SHOWLIST|OPT_STAT)) {
|
|
|
|
showlist();
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
exit(1);
|
|
|
|
}
|