Convert the snp(4) driver to use cdevpriv.
Now we have a single /dev/snp device node, which can be opened by watch(8) multiple times. Even though snp(4) will be dead as of next week, it's nice having this in SVN, because: - We may want to MFC it to RELENG_7. - By the time we fix snp(4) again, it's already there, existing watch(8) binaries should already work. Just like bpf(4), I'm adding a symlink from snp0 to snp to remain binary compatible.
This commit is contained in:
parent
854d77bdd6
commit
2e37c8eacb
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=181755
@ -16,8 +16,8 @@
|
|||||||
.Ft int
|
.Ft int
|
||||||
.Fn ioctl fd FIONREAD &result
|
.Fn ioctl fd FIONREAD &result
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
.Pa /dev/snp?
|
.Pa /dev/snp
|
||||||
are snoop devices which allow users to attach to any tty
|
is a snoop device which allows users to attach to any tty
|
||||||
and watch activities on it.
|
and watch activities on it.
|
||||||
The kernel must be compiled with
|
The kernel must be compiled with
|
||||||
.Cd "device snp" ,
|
.Cd "device snp" ,
|
||||||
|
@ -36,7 +36,6 @@ __FBSDID("$FreeBSD$");
|
|||||||
static l_close_t snplclose;
|
static l_close_t snplclose;
|
||||||
static l_write_t snplwrite;
|
static l_write_t snplwrite;
|
||||||
static d_open_t snpopen;
|
static d_open_t snpopen;
|
||||||
static d_close_t snpclose;
|
|
||||||
static d_read_t snpread;
|
static d_read_t snpread;
|
||||||
static d_write_t snpwrite;
|
static d_write_t snpwrite;
|
||||||
static d_ioctl_t snpioctl;
|
static d_ioctl_t snpioctl;
|
||||||
@ -46,7 +45,6 @@ static struct cdevsw snp_cdevsw = {
|
|||||||
.d_version = D_VERSION,
|
.d_version = D_VERSION,
|
||||||
.d_flags = D_PSEUDO | D_NEEDGIANT | D_NEEDMINOR,
|
.d_flags = D_PSEUDO | D_NEEDGIANT | D_NEEDMINOR,
|
||||||
.d_open = snpopen,
|
.d_open = snpopen,
|
||||||
.d_close = snpclose,
|
|
||||||
.d_read = snpread,
|
.d_read = snpread,
|
||||||
.d_write = snpwrite,
|
.d_write = snpwrite,
|
||||||
.d_ioctl = snpioctl,
|
.d_ioctl = snpioctl,
|
||||||
@ -70,7 +68,6 @@ static struct linesw snpdisc = {
|
|||||||
*/
|
*/
|
||||||
struct snoop {
|
struct snoop {
|
||||||
LIST_ENTRY(snoop) snp_list; /* List glue. */
|
LIST_ENTRY(snoop) snp_list; /* List glue. */
|
||||||
int snp_unit; /* Device number. */
|
|
||||||
struct cdev *snp_target; /* Target tty device. */
|
struct cdev *snp_target; /* Target tty device. */
|
||||||
struct tty *snp_tty; /* Target tty pointer. */
|
struct tty *snp_tty; /* Target tty pointer. */
|
||||||
u_long snp_len; /* Possible length. */
|
u_long snp_len; /* Possible length. */
|
||||||
@ -111,13 +108,11 @@ static MALLOC_DEFINE(M_SNP, "snp", "Snoop device data");
|
|||||||
* module load time.
|
* module load time.
|
||||||
*/
|
*/
|
||||||
static int snooplinedisc;
|
static int snooplinedisc;
|
||||||
|
static struct cdev *snoopdev;
|
||||||
|
|
||||||
static LIST_HEAD(, snoop) snp_sclist = LIST_HEAD_INITIALIZER(&snp_sclist);
|
static LIST_HEAD(, snoop) snp_sclist = LIST_HEAD_INITIALIZER(&snp_sclist);
|
||||||
static struct clonedevs *snpclones;
|
|
||||||
|
|
||||||
static struct tty *snpdevtotty(struct cdev *dev);
|
static struct tty *snpdevtotty(struct cdev *dev);
|
||||||
static void snp_clone(void *arg, struct ucred *cred, char *name,
|
|
||||||
int namelen, struct cdev **dev);
|
|
||||||
static void snp_detach(void *arg);
|
static void snp_detach(void *arg);
|
||||||
static int snp_down(struct snoop *snp);
|
static int snp_down(struct snoop *snp);
|
||||||
static int snp_in(struct snoop *snp, char *buf, int n);
|
static int snp_in(struct snoop *snp, char *buf, int n);
|
||||||
@ -220,14 +215,17 @@ snpwrite(struct cdev *dev, struct uio *uio, int flag)
|
|||||||
int error, i, len;
|
int error, i, len;
|
||||||
unsigned char c[SNP_INPUT_BUF];
|
unsigned char c[SNP_INPUT_BUF];
|
||||||
|
|
||||||
snp = dev->si_drv1;
|
error = devfs_get_cdevpriv((void **)&snp);
|
||||||
|
if (error != 0)
|
||||||
|
return (error);
|
||||||
|
|
||||||
tp = snp->snp_tty;
|
tp = snp->snp_tty;
|
||||||
if (tp == NULL)
|
if (tp == NULL)
|
||||||
return (EIO);
|
return (EIO);
|
||||||
if ((tp->t_state & TS_SNOOP) && tp->t_line == snooplinedisc)
|
if ((tp->t_state & TS_SNOOP) && tp->t_line == snooplinedisc)
|
||||||
goto tty_input;
|
goto tty_input;
|
||||||
|
|
||||||
printf("snp%d: attempt to write to bad tty\n", snp->snp_unit);
|
printf("snp: attempt to write to bad tty\n");
|
||||||
return (EIO);
|
return (EIO);
|
||||||
|
|
||||||
tty_input:
|
tty_input:
|
||||||
@ -255,7 +253,10 @@ snpread(struct cdev *dev, struct uio *uio, int flag)
|
|||||||
caddr_t from;
|
caddr_t from;
|
||||||
char *nbuf;
|
char *nbuf;
|
||||||
|
|
||||||
snp = dev->si_drv1;
|
error = devfs_get_cdevpriv((void **)&snp);
|
||||||
|
if (error != 0)
|
||||||
|
return (error);
|
||||||
|
|
||||||
KASSERT(snp->snp_len + snp->snp_base <= snp->snp_blen,
|
KASSERT(snp->snp_len + snp->snp_base <= snp->snp_blen,
|
||||||
("snoop buffer error"));
|
("snoop buffer error"));
|
||||||
|
|
||||||
@ -324,12 +325,12 @@ snp_in(struct snoop *snp, char *buf, int n)
|
|||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
if (snp->snp_flags & SNOOP_DOWN) {
|
if (snp->snp_flags & SNOOP_DOWN) {
|
||||||
printf("snp%d: more data to down interface\n", snp->snp_unit);
|
printf("snp: more data to down interface\n");
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (snp->snp_flags & SNOOP_OFLOW) {
|
if (snp->snp_flags & SNOOP_OFLOW) {
|
||||||
printf("snp%d: buffer overflow\n", snp->snp_unit);
|
printf("snp: buffer overflow\n");
|
||||||
/*
|
/*
|
||||||
* On overflow we just repeat the standart close
|
* On overflow we just repeat the standart close
|
||||||
* procedure...yes , this is waste of space but.. Then next
|
* procedure...yes , this is waste of space but.. Then next
|
||||||
@ -387,18 +388,30 @@ snp_in(struct snoop *snp, char *buf, int n)
|
|||||||
return (n);
|
return (n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
snp_dtor(void *data)
|
||||||
|
{
|
||||||
|
struct snoop *snp = data;
|
||||||
|
|
||||||
|
snp->snp_blen = 0;
|
||||||
|
LIST_REMOVE(snp, snp_list);
|
||||||
|
free(snp->snp_buf, M_SNP);
|
||||||
|
snp->snp_flags &= ~SNOOP_OPEN;
|
||||||
|
snp_detach(snp);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
snpopen(struct cdev *dev, int flag, int mode, struct thread *td)
|
snpopen(struct cdev *dev, int flag, int mode, struct thread *td)
|
||||||
{
|
{
|
||||||
struct snoop *snp;
|
struct snoop *snp;
|
||||||
|
int error;
|
||||||
|
|
||||||
if (dev->si_drv1 == NULL) {
|
snp = malloc(sizeof(*snp), M_SNP, M_WAITOK | M_ZERO);
|
||||||
dev->si_flags &= ~SI_CHEAPCLONE;
|
error = devfs_set_cdevpriv(snp, snp_dtor);
|
||||||
dev->si_drv1 = snp = malloc(sizeof(*snp), M_SNP,
|
if (error != 0) {
|
||||||
M_WAITOK | M_ZERO);
|
free(snp, M_SNP);
|
||||||
snp->snp_unit = dev2unit(dev);
|
return (error);
|
||||||
} else
|
}
|
||||||
return (EBUSY);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We intentionally do not OR flags with SNOOP_OPEN, but set them so
|
* We intentionally do not OR flags with SNOOP_OPEN, but set them so
|
||||||
@ -444,7 +457,7 @@ snp_detach(void *arg)
|
|||||||
tp->t_state &= ~TS_SNOOP;
|
tp->t_state &= ~TS_SNOOP;
|
||||||
tp->t_line = snp->snp_olddisc;
|
tp->t_line = snp->snp_olddisc;
|
||||||
} else
|
} else
|
||||||
printf("snp%d: bad attached tty data\n", snp->snp_unit);
|
printf("snp: bad attached tty data\n");
|
||||||
|
|
||||||
snp->snp_tty = NULL;
|
snp->snp_tty = NULL;
|
||||||
snp->snp_target = NULL;
|
snp->snp_target = NULL;
|
||||||
@ -455,23 +468,6 @@ snp_detach(void *arg)
|
|||||||
free(snp, M_SNP);
|
free(snp, M_SNP);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
snpclose(struct cdev *dev, int flags, int fmt, struct thread *td)
|
|
||||||
{
|
|
||||||
struct snoop *snp;
|
|
||||||
|
|
||||||
snp = dev->si_drv1;
|
|
||||||
snp->snp_blen = 0;
|
|
||||||
LIST_REMOVE(snp, snp_list);
|
|
||||||
free(snp->snp_buf, M_SNP);
|
|
||||||
snp->snp_flags &= ~SNOOP_OPEN;
|
|
||||||
dev->si_drv1 = NULL;
|
|
||||||
snp_detach(snp);
|
|
||||||
destroy_dev_sched(dev);
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
snp_down(struct snoop *snp)
|
snp_down(struct snoop *snp)
|
||||||
{
|
{
|
||||||
@ -495,9 +491,12 @@ snpioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags,
|
|||||||
struct tty *tp;
|
struct tty *tp;
|
||||||
struct cdev *tdev;
|
struct cdev *tdev;
|
||||||
struct file *fp;
|
struct file *fp;
|
||||||
int s;
|
int error, s;
|
||||||
|
|
||||||
|
error = devfs_get_cdevpriv((void **)&snp);
|
||||||
|
if (error != 0)
|
||||||
|
return (error);
|
||||||
|
|
||||||
snp = dev->si_drv1;
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case SNPSTTY:
|
case SNPSTTY:
|
||||||
s = *(int *)data;
|
s = *(int *)data;
|
||||||
@ -587,7 +586,10 @@ snppoll(struct cdev *dev, int events, struct thread *td)
|
|||||||
struct snoop *snp;
|
struct snoop *snp;
|
||||||
int revents;
|
int revents;
|
||||||
|
|
||||||
snp = dev->si_drv1;
|
if (devfs_get_cdevpriv((void **)&snp) != 0)
|
||||||
|
return (events &
|
||||||
|
(POLLHUP|POLLIN|POLLRDNORM|POLLOUT|POLLWRNORM));
|
||||||
|
|
||||||
revents = 0;
|
revents = 0;
|
||||||
/*
|
/*
|
||||||
* If snoop is down, we don't want to poll() forever so we return 1.
|
* If snoop is down, we don't want to poll() forever so we return 1.
|
||||||
@ -603,44 +605,22 @@ snppoll(struct cdev *dev, int events, struct thread *td)
|
|||||||
return (revents);
|
return (revents);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
snp_clone(void *arg, struct ucred *cred, char *name, int namelen,
|
|
||||||
struct cdev **dev)
|
|
||||||
{
|
|
||||||
int u, i;
|
|
||||||
|
|
||||||
if (*dev != NULL)
|
|
||||||
return;
|
|
||||||
if (dev_stdclone(name, NULL, "snp", &u) != 1)
|
|
||||||
return;
|
|
||||||
i = clone_create(&snpclones, &snp_cdevsw, &u, dev, 0);
|
|
||||||
if (i)
|
|
||||||
*dev = make_dev_credf(MAKEDEV_REF, &snp_cdevsw, unit2minor(u),
|
|
||||||
NULL, UID_ROOT, GID_WHEEL, 0600, "snp%d", u);
|
|
||||||
if (*dev != NULL) {
|
|
||||||
(*dev)->si_flags |= SI_CHEAPCLONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
snp_modevent(module_t mod, int type, void *data)
|
snp_modevent(module_t mod, int type, void *data)
|
||||||
{
|
{
|
||||||
static eventhandler_tag eh_tag;
|
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case MOD_LOAD:
|
case MOD_LOAD:
|
||||||
/* XXX error checking. */
|
|
||||||
clone_setup(&snpclones);
|
|
||||||
eh_tag = EVENTHANDLER_REGISTER(dev_clone, snp_clone, 0, 1000);
|
|
||||||
snooplinedisc = ldisc_register(LDISC_LOAD, &snpdisc);
|
snooplinedisc = ldisc_register(LDISC_LOAD, &snpdisc);
|
||||||
|
snoopdev = make_dev(&snp_cdevsw, 0, UID_ROOT, GID_WHEEL,
|
||||||
|
0600, "snp");
|
||||||
|
/* For compatibility */
|
||||||
|
make_dev_alias(snoopdev, "snp0");
|
||||||
break;
|
break;
|
||||||
case MOD_UNLOAD:
|
case MOD_UNLOAD:
|
||||||
if (!LIST_EMPTY(&snp_sclist))
|
if (!LIST_EMPTY(&snp_sclist))
|
||||||
return (EBUSY);
|
return (EBUSY);
|
||||||
EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
|
destroy_dev(snoopdev);
|
||||||
drain_dev_clone_events();
|
|
||||||
clone_cleanup(&snpclones);
|
|
||||||
destroy_dev_drain(&snp_cdevsw);
|
|
||||||
ldisc_deregister(snooplinedisc);
|
ldisc_deregister(snooplinedisc);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -152,30 +152,21 @@ fatal(int error, const char *buf)
|
|||||||
static int
|
static int
|
||||||
open_snp(void)
|
open_snp(void)
|
||||||
{
|
{
|
||||||
char snp[] = {_PATH_DEV "snpXXX"};
|
int f, mode;
|
||||||
int f, mode, pos, c;
|
|
||||||
|
|
||||||
pos = strlen(snp) - 3;
|
|
||||||
if (opt_write)
|
if (opt_write)
|
||||||
mode = O_RDWR;
|
mode = O_RDWR;
|
||||||
else
|
else
|
||||||
mode = O_RDONLY;
|
mode = O_RDONLY;
|
||||||
|
|
||||||
if (opt_snpdev == NULL)
|
if (opt_snpdev == NULL)
|
||||||
for (c = 0; c <= 999; c++) {
|
f = open(_PATH_DEV "snp", mode);
|
||||||
snprintf(snp+pos, 4, "%d", c);
|
|
||||||
if ((f = open(snp, mode)) < 0) {
|
|
||||||
if (errno == EBUSY)
|
|
||||||
continue;
|
|
||||||
err(1, "open %s", snp);
|
|
||||||
}
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
if ((f = open(opt_snpdev, mode)) != -1)
|
f = open(opt_snpdev, mode);
|
||||||
return (f);
|
if (f == -1)
|
||||||
fatal(EX_OSFILE, "cannot open snoop device");
|
fatal(EX_OSFILE, "cannot open snoop device");
|
||||||
return (0);
|
|
||||||
|
return (f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user