layout: post title: "The debug file system" subtitle: "It's still in the kernel!" tags: [osdev, filesystems] This far in my vfs rewrite, I've made a [vfs mount tree](/blog/2013/12/Virtual-File-System2/) and written some [file operation syscalls](/blog/2013/12/VFS-syscalls/). Now it's time to actually use this, by writing a filesystem that can be mounted and then manipulated through the syscall interface. The filesystem I want to start with is what I call the `debug` file. It is a single file, which mounts to `/` for now (later `/dev/debug`) and cannot be read from. Writing to it will print the written text on the screen. Three functions are needed for newlib `fprintf` to be able to write to it: `stat`, `isatty` and `write`. Those are all rather simple, since they won't need to keep track of which file we're referencing. :::c uint32_t debug_stat(INODE node, struct stat *st) { memset(st, 0, sizeof(struct stat)); st->st_mode = S_IFCHR; return 0; } I don't care much about the stat for the debug file. Maybe I'll add some creation time or so later... :::c uint32_t debug_isatty(INODE node) { return 1; } The debug output is a terminal. :::c uint32_t debug_write(INODE node, void *buffer, uint32_t size, uint32_t offset) { char *buf = calloc(size + 1, 1); memcpy(buf, buffer, size); kdbg_puts(buf); free(buf); return size; } `kdbg_puts` is a function I wrote [a long time ago](/blog/2012/06/Kernel-Debug-Functions/) which prints a string to the screen. The first two lines are just to make sure that the data is null-terminated. With this, I can define a driver for the "debug device": :::c vfs_driver_t debug_driver = { 0, // open 0, // close 0, // read debug_write, // write 0, // link 0, // unlink debug_stat, // stat debug_isatty, // isatty 0, // mkdir 0, // readdir 0 // finddir }; And then write a function to setup the device: :::c INODE debug_dev_init() { INODE node = calloc(1, sizeof(vfs_node_t)); strcpy(node->name, "debug"); node->d = &debug_driver; node->type = FS_CHARDEV; return node; } Then, to activate it, all I need to do is add :::c vfs_init(); vfs_mount("/", debug_dev_init()); in my kernel boot code. After that I can use the standard library functions: :::c FILE *dbg = fopen("/", "w"); fprintf(dbg, "Hello, world!\n"); or even: :::c fopen("/", "r"); fopen("/", "w"); printf("Hello, world!\n"); That's it for this time. Next time, we'll do some piping!