2 * Copyright © 2007 Alistair Crooks. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote
13 * products derived from this software without specific prior written
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
22 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <sys/types.h>
43 static int verbose
; /* how chatty are we? */
47 /* a device node describes the device that is printed in the dmesg */
48 typedef struct devicenode_t
{
49 char *dev
; /* device name */
50 int devlen
; /* length of name */
51 char *parent
; /* its parent device name */
52 int parentlen
; /* length of parent name */
53 char *descr
; /* description of the device itself */
54 int descrlen
; /* length of description */
55 int p
; /* device node subscript of parent */
56 int dir
; /* nonzero if this is a directory */
59 DEFINE_ARRAY(devices_t
, devicenode_t
);
61 static devices_t devices
;
64 /* perform the stat operation */
65 /* if this is the root, then just synthesise the data */
67 dmesgfs_getattr(const char *path
, struct stat
*st
)
71 if (strcmp(path
, "/") == 0) {
72 (void) memset(st
, 0x0, sizeof(*st
));
73 st
->st_mode
= (S_IFDIR
| 0755);
77 if ((ep
= virtdir_find(&pci
, path
, strlen(path
))) == NULL
) {
82 (void) memcpy(st
, &pci
.file
, sizeof(*st
));
83 st
->st_size
= ep
->tgtlen
;
84 st
->st_mode
= S_IFREG
| 0644;
87 (void) memcpy(st
, &pci
.dir
, sizeof(*st
));
90 (void) memcpy(st
, &pci
.lnk
, sizeof(*st
));
91 st
->st_size
= ep
->tgtlen
;
92 st
->st_mode
= S_IFLNK
| 0755;
95 st
->st_ino
= virtdir_offset(&pci
, ep
) + 10;
99 /* readdir operation */
101 dmesgfs_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
102 off_t offset
, struct fuse_file_info
* fi
)
104 static VIRTDIR
*dirp
;
108 if ((dirp
= openvirtdir(&pci
, path
)) == NULL
) {
111 filler(buf
, ".", NULL
, 0);
112 filler(buf
, "..", NULL
, 0);
114 while ((dp
= readvirtdir(dirp
)) != NULL
) {
115 if (filler(buf
, dp
->d_name
, NULL
, 0) != 0) {
124 /* open the file in the file system */
126 dmesgfs_open(const char *path
, struct fuse_file_info
* fi
)
131 /* read the file's contents in the file system */
133 dmesgfs_read(const char *path
, char *buf
, size_t size
, off_t offset
,
134 struct fuse_file_info
* fi
)
138 if ((ep
= virtdir_find(&pci
, path
, strlen(path
))) == NULL
) {
141 if (ep
->tgt
== NULL
) {
144 (void) memcpy(buf
, &ep
->tgt
[offset
], size
);
148 /* fill in the statvfs struct */
150 dmesgfs_statfs(const char *path
, struct statvfs
*st
)
152 (void) memset(st
, 0x0, sizeof(*st
));
156 /* read the symbolic link */
158 dmesgfs_readlink(const char *path
, char *buf
, size_t size
)
162 if ((ep
= virtdir_find(&pci
, path
, strlen(path
))) == NULL
) {
165 if (ep
->tgt
== NULL
) {
168 (void) strlcpy(buf
, ep
->tgt
, size
);
172 /* operations struct */
173 static struct fuse_operations dmesgfs_oper
= {
174 .getattr
= dmesgfs_getattr
,
175 .readlink
= dmesgfs_readlink
,
176 .readdir
= dmesgfs_readdir
,
177 .open
= dmesgfs_open
,
178 .read
= dmesgfs_read
,
179 .statfs
= dmesgfs_statfs
182 /* save `n' chars of `s' in malloc'd memory */
184 strnsave(const char *s
, int n
)
191 NEWARRAY(char, cp
, n
+ 1, "strnsave", exit(EXIT_FAILURE
));
192 (void) memcpy(cp
, s
, n
);
197 /* find a device in the device node tree */
199 finddev(const char *s
, int len
, int updir
)
203 for (i
= 0 ; i
< devices
.c
; i
++) {
204 if (strncmp(devices
.v
[i
].dev
, s
, len
) == 0 &&
205 devices
.v
[i
].devlen
== len
) {
207 devices
.v
[i
].dir
= 1;
215 /* add a device to the device node tree */
217 add_dev(const char *dev
, int len
, const char *parent
, int parentlen
, const char *descr
, int descrlen
)
221 if ((d
= finddev(dev
, len
, 0)) < 0) {
222 ALLOC(devicenode_t
, devices
.v
, devices
.size
, devices
.c
, 10, 10, "add_dev", exit(EXIT_FAILURE
));
223 devices
.v
[devices
.c
].dev
= strnsave(dev
, len
);
224 devices
.v
[devices
.c
].devlen
= len
;
225 devices
.v
[devices
.c
].parent
= strnsave(parent
, parentlen
);
226 devices
.v
[devices
.c
].parentlen
= parentlen
;
227 devices
.v
[devices
.c
].descr
= strnsave(descr
, descrlen
);
228 devices
.v
[devices
.c
].descrlen
= descrlen
;
233 /* print the parent device pathname */
235 pparent(int d
, char *buf
, size_t size
)
240 cc
= pparent(devices
.v
[d
].p
, buf
, size
);
243 (void) strlcat(buf
, "/", size
);
244 (void) strlcat(buf
, devices
.v
[d
].dev
, size
- 1);
245 return devices
.v
[d
].devlen
+ 1;
248 #define NEXUS_DESCRIPTION "Nexus - the root of everything"
250 /* build up a fuse_tree from the information in the database */
252 build_tree(virtdir_t
*tp
, const char *nexus
, char type
)
256 regmatch_t matchv
[10];
263 (void) stat(".", &dir
);
264 (void) memcpy(&f
, &dir
, sizeof(f
));
265 f
.st_mode
= S_IFREG
| 0644;
266 if (regcomp(&r
, "^([a-z0-9]+) at ([a-z0-9]+)(.*)", REG_EXTENDED
) != 0) {
267 warn("can't compile regular expression\n");
270 if ((pp
= popen("dmesg", "r")) == NULL
) {
273 add_dev(nexus
, strlen(nexus
), nexus
, strlen(nexus
), NEXUS_DESCRIPTION
,
274 strlen(NEXUS_DESCRIPTION
));
275 while (fgets(buf
, sizeof(buf
), pp
) != NULL
) {
277 buf
[strlen(buf
) - 1] = 0x0;
279 if (regexec(&r
, buf
, 10, matchv
, 0) == 0) {
280 add_dev(&buf
[matchv
[1].rm_so
],
281 matchv
[1].rm_eo
- matchv
[1].rm_so
,
282 &buf
[matchv
[2].rm_so
],
283 matchv
[2].rm_eo
- matchv
[2].rm_so
,
285 matchv
[0].rm_eo
- matchv
[0].rm_so
);
288 printf("%d devices\n", devices
.c
);
290 for (i
= 0 ; i
< devices
.c
; i
++) {
291 if ((p
= finddev(devices
.v
[i
].parent
, devices
.v
[i
].parentlen
, 1)) < 0) {
292 warn("No parent device for %s\n", devices
.v
[i
].dev
);
296 for (i
= 0 ; i
< devices
.c
; i
++) {
297 pparent(i
, buf
, sizeof(buf
));
298 virtdir_add(tp
, buf
, strlen(buf
),
299 (devices
.v
[i
].dir
) ? 'd' : type
,
300 devices
.v
[i
].descr
, devices
.v
[i
].descrlen
);
301 if (devices
.v
[i
].dir
) {
302 (void) strlcat(buf
, "/", sizeof(buf
));
303 (void) strlcat(buf
, "Description", sizeof(buf
));
304 virtdir_add(tp
, buf
, strlen(buf
), type
,
305 devices
.v
[i
].descr
, devices
.v
[i
].descrlen
);
308 printf("dmesgfs: adding %s `%s' -> `%s'\n",
309 (type
== 'l') ? "symbolic link" : "file",
310 buf
, devices
.v
[i
].descr
);
318 main(int argc
, char **argv
)
326 while ((i
= getopt(argc
, argv
, "fln:v")) != -1) {
342 if (!build_tree(&pci
, (nexus
) ? nexus
: "mainbus0", type
)) {
345 return fuse_main(argc
, argv
, &dmesgfs_oper
, NULL
);