Another day, another file system.

dmesgfs is another example file system, which displays the device tree
information gained from dmesg(8) as a directory hierarchy. The information
can be displayed in files, or as targets of symbolic links.

% l /mnt/mainbus0
total 320
drwxr-xr-x  2 agc   agc    512 May 21 22:21 .
drwxr-xr-x  2 root  wheel    0 Jan  1  1970 ..
drwxr-xr-x  2 agc   agc    512 May 21 22:21 acpi0
lrwxr-xr-x  1 agc   agc     41 May 21 22:21 cpu0 -> cpu0 at mainbus0 apid 0: (boot processor)
lrwxr-xr-x  1 agc   agc     40 May 21 22:21 ioapic -> ioapic at mainbus0 apid 1 not configured
drwxr-xr-x  2 agc   agc    512 May 21 22:21 pci0
% l /mnt/mainbus0/pci0/piixide0/atabus1/atapibus0
total 256
drwxr-xr-x  2 agc  agc  512 May 21 22:21 .
drwxr-xr-x  2 agc  agc  512 May 21 22:21 ..
lrwxr-xr-x  1 agc  agc   31 May 21 22:21 Description -> atapibus0 at atabus1: 2 targets
lrwxr-xr-x  1 agc  agc  104 May 21 22:21 cd0 -> cd0 at atapibus0 drive 0: <VMware Virtual IDE CDROM Drive, 1000000000000000000, 0000000> cdrom removable
%
This commit is contained in:
agc 2007-05-21 21:29:23 +00:00
parent cfb41894f8
commit d49e2683be
3 changed files with 455 additions and 0 deletions

View File

@ -0,0 +1,13 @@
# $NetBSD: Makefile,v 1.1 2007/05/21 21:29:23 agc Exp $
PROG=dmesgfs
SRCS=dmesgfs.c virtdir.c
LDADD+= -lrefuse
CPPFLAGS+= -g -I${.CURDIR}/../virtdir
LDFLAGS+=-g
MAN=dmesgfs.8
WARNS=4
.PATH: ${.CURDIR}/../virtdir
.include <bsd.prog.mk>

View File

@ -0,0 +1,96 @@
.\"
.\" Copyright © 2007 Alistair Crooks. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. The name of the author may not be used to endorse or promote
.\" products derived from this software without specific prior written
.\" permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
.\" NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
.\" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd May 16, 2007
.Dt DMESGFS 8
.Os
.Sh NAME
.Nm dmesgfs
.Nd refuse-based virtual file system to display devices found in dmesg
.Sh SYNOPSIS
.Nm
.Op Fl f
.Op Fl l
.Op Fl n Ar nexus
.Op Fl v
.Ar mount_point
.Sh DESCRIPTION
The
.Nm
utility can be used to mount a virtual file system which
shows the tree of devices present in the computer.
This tree is found by using the output of the
.Xr dmesg 8
command.
.Pp
The following arguments can be used:
.Bl -tag -width Ds
.It Fl f
present the attachment information in the virtual file system
as files.
.It Fl l
present the attachment information in the virtual file system
as symbolic links.
This is the default mode of operation.
.It Fl n Ar nexus
Use the nexus name
as the root of the device tree.
The default value for Nexus is
.Dq mainbus0 .
.It Fl v
Produce verbose output
.El
.Pp
The
.Nm
utility makes use of the
.Xr virtdir 3
virtual directory routines.
.Pp
The
.Xr refuse 3
library is used to provide the file system features.
.Pp
The mandatory parameter is
the local mount
point.
.Pp
The
.Xr dmesg 8
utility is used to retrieve the information.
.Sh SEE ALSO
.Xr librefuse 3 ,
.Xr puffs 3 ,
.Xr virtdir 3 ,
.Xr dmesg 8 .
.Sh HISTORY
The
.Nm
utility first appeared in
.Nx 5.0 .
.Sh AUTHORS
.An Alistair Crooks Aq agc@NetBSD.org

View File

@ -0,0 +1,346 @@
/*
* Copyright © 2007 Alistair Crooks. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <fuse.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "virtdir.h"
#include "defs.h"
static int verbose; /* how chatty are we? */
static virtdir_t pci;
/* a device node describes the device that is printed in the dmesg */
typedef struct devicenode_t {
char *dev; /* device name */
int devlen; /* length of name */
char *parent; /* its parent device name */
int parentlen; /* length of parent name */
char *descr; /* description of the device itself */
int descrlen; /* length of description */
int p; /* device node subscript of parent */
int dir; /* nonzero if this is a directory */
} devicenode_t;
DEFINE_ARRAY(devices_t, devicenode_t);
static devices_t devices;
/* perform the stat operation */
/* if this is the root, then just synthesise the data */
static int
dmesgfs_getattr(const char *path, struct stat *st)
{
virt_dirent_t *ep;
if (strcmp(path, "/") == 0) {
(void) memset(st, 0x0, sizeof(*st));
st->st_mode = (S_IFDIR | 0755);
st->st_nlink = 2;
return 0;
}
if ((ep = virtdir_find(&pci, path, strlen(path))) == NULL) {
return -ENOENT;
}
switch(ep->type) {
case 'f':
(void) memcpy(st, &pci.file, sizeof(*st));
st->st_size = ep->tgtlen;
st->st_mode = S_IFREG | 0644;
break;
case 'd':
(void) memcpy(st, &pci.dir, sizeof(*st));
break;
case 'l':
(void) memcpy(st, &pci.lnk, sizeof(*st));
st->st_size = ep->tgtlen;
st->st_mode = S_IFLNK | 0755;
break;
}
st->st_ino = virtdir_offset(&pci, ep) + 10;
return 0;
}
/* readdir operation */
static int
dmesgfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info * fi)
{
static VIRTDIR *dirp;
virt_dirent_t *dp;
if (offset == 0) {
if ((dirp = openvirtdir(&pci, path)) == NULL) {
return 0;
}
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
}
while ((dp = readvirtdir(dirp)) != NULL) {
if (filler(buf, dp->d_name, NULL, 0) != 0) {
return 0;
}
}
closevirtdir(dirp);
dirp = NULL;
return 0;
}
/* open the file in the file system */
static int
dmesgfs_open(const char *path, struct fuse_file_info * fi)
{
return 0;
}
/* read the file's contents in the file system */
static int
dmesgfs_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info * fi)
{
virt_dirent_t *ep;
if ((ep = virtdir_find(&pci, path, strlen(path))) == NULL) {
return -ENOENT;
}
if (ep->tgt == NULL) {
return -ENOENT;
}
(void) memcpy(buf, &ep->tgt[offset], size);
return ep->tgtlen;
}
/* fill in the statvfs struct */
static int
dmesgfs_statfs(const char *path, struct statvfs *st)
{
(void) memset(st, 0x0, sizeof(*st));
return 0;
}
/* read the symbolic link */
static int
dmesgfs_readlink(const char *path, char *buf, size_t size)
{
virt_dirent_t *ep;
if ((ep = virtdir_find(&pci, path, strlen(path))) == NULL) {
return -ENOENT;
}
if (ep->tgt == NULL) {
return -ENOENT;
}
(void) strlcpy(buf, ep->tgt, size);
return 0;
}
/* operations struct */
static struct fuse_operations dmesgfs_oper = {
.getattr = dmesgfs_getattr,
.readlink = dmesgfs_readlink,
.readdir = dmesgfs_readdir,
.open = dmesgfs_open,
.read = dmesgfs_read,
.statfs = dmesgfs_statfs
};
/* save `n' chars of `s' in malloc'd memory */
static char *
strnsave(const char *s, int n)
{
char *cp;
if (n < 0) {
n = strlen(s);
}
NEWARRAY(char, cp, n + 1, "strnsave", exit(EXIT_FAILURE));
(void) memcpy(cp, s, n);
cp[n] = 0x0;
return cp;
}
/* find a device in the device node tree */
static int
finddev(const char *s, int len, int updir)
{
int i;
for (i = 0 ; i < devices.c ; i++) {
if (strncmp(devices.v[i].dev, s, len) == 0 &&
devices.v[i].devlen == len) {
if (updir) {
devices.v[i].dir = 1;
}
return i;
}
}
return -1;
}
/* add a device to the device node tree */
static void
add_dev(const char *dev, int len, const char *parent, int parentlen, const char *descr, int descrlen)
{
int d;
if ((d = finddev(dev, len, 0)) < 0) {
ALLOC(devicenode_t, devices.v, devices.size, devices.c, 10, 10, "add_dev", exit(EXIT_FAILURE));
devices.v[devices.c].dev = strnsave(dev, len);
devices.v[devices.c].devlen = len;
devices.v[devices.c].parent = strnsave(parent, parentlen);
devices.v[devices.c].parentlen = parentlen;
devices.v[devices.c].descr = strnsave(descr, descrlen);
devices.v[devices.c].descrlen = descrlen;
devices.c += 1;
}
}
/* print the parent device pathname */
static int
pparent(int d, char *buf, size_t size)
{
int cc;
if (d != 0) {
cc = pparent(devices.v[d].p, buf, size);
size -= cc;
}
(void) strlcat(buf, "/", size);
(void) strlcat(buf, devices.v[d].dev, size - 1);
return devices.v[d].devlen + 1;
}
#define NEXUS_DESCRIPTION "Nexus - the root of everything"
/* build up a fuse_tree from the information in the database */
static int
build_tree(virtdir_t *tp, const char *nexus, char type)
{
struct stat dir;
struct stat f;
regmatch_t matchv[10];
regex_t r;
FILE *pp;
char buf[BUFSIZ];
int i;
int p;
(void) stat(".", &dir);
(void) memcpy(&f, &dir, sizeof(f));
f.st_mode = S_IFREG | 0644;
if (regcomp(&r, "^([a-z0-9]+) at ([a-z0-9]+)(.*)", REG_EXTENDED) != 0) {
warn("can't compile regular expression\n");
return 0;
}
if ((pp = popen("dmesg", "r")) == NULL) {
return 0;
}
add_dev(nexus, strlen(nexus), nexus, strlen(nexus), NEXUS_DESCRIPTION,
strlen(NEXUS_DESCRIPTION));
while (fgets(buf, sizeof(buf), pp) != NULL) {
if (type == 'l') {
buf[strlen(buf) - 1] = 0x0;
}
if (regexec(&r, buf, 10, matchv, 0) == 0) {
add_dev(&buf[matchv[1].rm_so],
matchv[1].rm_eo - matchv[1].rm_so,
&buf[matchv[2].rm_so],
matchv[2].rm_eo - matchv[2].rm_so,
buf,
matchv[0].rm_eo - matchv[0].rm_so);
}
}
printf("%d devices\n", devices.c);
(void) pclose(pp);
for (i = 0 ; i < devices.c ; i++) {
if ((p = finddev(devices.v[i].parent, devices.v[i].parentlen, 1)) < 0) {
warn("No parent device for %s\n", devices.v[i].dev);
}
devices.v[i].p = p;
}
for (i = 0 ; i < devices.c ; i++) {
pparent(i, buf, sizeof(buf));
virtdir_add(tp, buf, strlen(buf),
(devices.v[i].dir) ? 'd' : type,
devices.v[i].descr, devices.v[i].descrlen);
if (devices.v[i].dir) {
(void) strlcat(buf, "/", sizeof(buf));
(void) strlcat(buf, "Description", sizeof(buf));
virtdir_add(tp, buf, strlen(buf), type,
devices.v[i].descr, devices.v[i].descrlen);
}
if (verbose) {
printf("dmesgfs: adding %s `%s' -> `%s'\n",
(type == 'l') ? "symbolic link" : "file",
buf, devices.v[i].descr);
}
buf[0] = 0x0;
}
return 1;
}
int
main(int argc, char **argv)
{
char *nexus;
char type;
int i;
nexus = NULL;
type = 'l';
while ((i = getopt(argc, argv, "fln:v")) != -1) {
switch(i) {
case 'f':
type = 'f';
break;
case 'l':
type = 'l';
break;
case 'n':
nexus = optarg;
break;
case 'v':
verbose += 1;
break;
}
}
if (!build_tree(&pci, (nexus) ? nexus : "mainbus0", type)) {
exit(EXIT_FAILURE);
}
return fuse_main(argc, argv, &dmesgfs_oper, NULL);
}