1
0
Files
irix-657m-src/irix/cmd/netman/lib/sn_trace.c
2022-09-29 17:59:04 +03:00

229 lines
4.2 KiB
C

/*
* Copyright 1989 Silicon Graphics, Inc. All rights reserved.
*
* A trace file snooper implementation.
*/
#include <errno.h>
#include <stdio.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include "exception.h"
#include "heap.h"
#include "macros.h"
#include "protocol.h"
#include "snooper.h"
#define TRACEFILE_MAGIC 0x9e3779b9 /* magic version number */
DefineSnooperOperations(trace_snops,tsn)
typedef struct {
FILE *file; /* stdio file pointer */
int fd; /* file descriptor */
XDR xdr; /* stdio xdr stream */
Snooper snooper; /* base class state */
} TraceSnooper;
#define TSN(sn) ((TraceSnooper *) (sn)->sn_private)
static int sock = -1; /* socket to fake select until snooping is started */
Snooper *
tracesnooper(char *name, char *mode, Protocol *rawproto)
{
TraceSnooper *tsn;
int ronly, error;
u_long magic;
u_int rawprid;
tsn = new(TraceSnooper);
errno = 0;
tsn->fd = -1;
ronly = (mode[0] == 'r' && mode[1] != '+');
if (!strcmp(name, "-"))
tsn->file = ronly ? stdin : stdout;
else
tsn->file = fopen(name, mode);
if (tsn->file == 0)
goto sysfail;
xdrstdio_create(&tsn->xdr, tsn->file, ronly ? XDR_DECODE : XDR_ENCODE);
magic = TRACEFILE_MAGIC;
if (!xdr_u_long(&tsn->xdr, &magic))
goto sysfail;
if (magic != TRACEFILE_MAGIC) {
errno = EINVAL;
goto sysfail;
}
if (tsn->xdr.x_op == XDR_ENCODE)
rawprid = rawproto->pr_id;
if (!xdr_u_int(&tsn->xdr, &rawprid))
goto sysfail;
if (tsn->xdr.x_op == XDR_DECODE) {
rawproto = findprotobyid(rawprid);
if (rawproto == 0) {
errno = EPROTONOSUPPORT;
goto sysfail;
}
}
if (!sn_init(&tsn->snooper, tsn, &trace_snops, name, fileno(tsn->file),
rawproto)) {
error = tsn->snooper.sn_error;
goto fail;
}
if (ronly) {
if (sock < 0)
sock = socket(PF_INET, SOCK_DGRAM, 0);
tsn->fd = dup(fileno(tsn->file));
if (tsn->fd < 0)
goto sysfail;
if (dup2(sock, fileno(tsn->file)) < 0) {
error = errno;
close(tsn->fd);
errno = error;
goto sysfail;
}
}
return &tsn->snooper;
sysfail:
error = errno;
exc_raise(error, "cannot snoop %s tracefile %s",
ronly ? "from" : "to", name);
fail:
if (tsn->file)
fclose(tsn->file);
delete(tsn);
errno = error;
return 0;
}
/* ARGSUSED */
static int
tsn_add(Snooper *sn, struct expr **exp, struct exprerror *err)
{
return 1;
}
/* ARGSUSED */
static int
tsn_delete(Snooper *sn)
{
return 1;
}
static int
tsn_read(Snooper *sn, SnoopPacket *sp, int len)
{
TraceSnooper *tsn;
bool_t more;
u_int cc;
tsn = TSN(sn);
if (tsn->xdr.x_op != XDR_DECODE) {
sn->sn_error = EBADF;
return -1;
}
if (!xdr_bool(&tsn->xdr, &more) || !more)
return 0;
cc = len;
errno = 0;
if (!xdr_snooppacket(&tsn->xdr, sp, &cc, (unsigned int) len)) {
if (errno == 0)
return 0;
sn->sn_error = errno;
return -1;
}
return cc;
}
static int
tsn_write(Snooper *sn, SnoopPacket *sp, int len)
{
TraceSnooper *tsn;
bool_t more;
tsn = TSN(sn);
if (tsn->xdr.x_op != XDR_ENCODE) {
sn->sn_error = EBADF;
return -1;
}
more = TRUE;
errno = 0;
if (!xdr_bool(&tsn->xdr, &more)
|| !xdr_snooppacket(&tsn->xdr, sp, (u_int *) &len, (u_int) len)) {
if (errno == 0)
return 0;
sn->sn_error = errno;
return -1;
}
return len;
}
/* ARGSUSED */
static int
tsn_ioctl(Snooper *sn, int cmd, void *arg)
{
switch (cmd) {
case SIOCSNOOPING:
{
TraceSnooper *tsn = TSN(sn);
if (*(int *)arg == 0)
return dup2(sock, fileno(tsn->file));
else
return dup2(tsn->fd, fileno(tsn->file));
}
case SIOCRAWSTATS:
bzero(arg, sizeof(struct snoopstats));
break;
}
return 1;
}
/* ARGSUSED */
static int
tsn_getaddr(Snooper *sn, int cmd, struct sockaddr *sa)
{
sn->sn_error = EOPNOTSUPP;
return 0;
}
/* ARGSUSED */
static int
tsn_shutdown(Snooper *sn, enum snshutdownhow how)
{
TraceSnooper *tsn;
int rc;
tsn = TSN(sn);
if (tsn->fd >= 0)
dup2(tsn->fd, fileno(tsn->file));
fflush(tsn->file);
rc = ferror(tsn->file);
if (tsn->fd >= 0)
dup2(sock, fileno(tsn->file));
return rc;
}
static void
tsn_destroy(Snooper *sn)
{
TraceSnooper *tsn;
bool_t eof;
tsn = TSN(sn);
if (tsn->fd >= 0)
dup2(tsn->fd, fileno(tsn->file));
eof = FALSE;
(void) xdr_bool(&tsn->xdr, &eof);
xdr_destroy(&tsn->xdr);
if (tsn->file != stdin && tsn->file != stdout)
fclose(tsn->file);
if (tsn->fd >= 0)
close(tsn->fd);
delete(tsn);
}