Building an Erlang-native 9p2000 Protocol Implementation for Process Introspection
#Infrastructure

Building an Erlang-native 9p2000 Protocol Implementation for Process Introspection

Tech Essays Reporter
4 min read

A developer has created a pure Erlang implementation of the 9p2000 file protocol, aiming to expose Erlang's internal process tree through a filesystem-like API without requiring native code compilation, offering a cross-platform alternative to existing solutions.

The 9p2000 protocol, originally developed by Bell Labs for the Plan 9 operating system, is a network filesystem protocol designed for simplicity and composability. Its stateless nature and straightforward message structure have made it an attractive target for modern implementations, particularly in environments where traditional filesystem abstractions are too heavy or inflexible. A recent project, hauleth.dev/e9p, brings this protocol to the Erlang ecosystem with a specific, pragmatic goal: to create a pure Erlang implementation that can serve as a foundation for novel filesystem abstractions, particularly for introspecting Erlang's own runtime.

The core motivation behind this work is the desire to provide a familiar, filesystem-like interface to Erlang's internal state. Erlang's process tree and runtime data are typically accessed through the Erlang shell or specialized libraries, which can be a barrier for operators who are not fluent in the language. The project's author, hauleth, draws inspiration from the fuserl library, which uses FUSE (Filesystem in Userspace) to expose Erlang data via a filesystem. However, fuserl relies on a NIF (Native Implemented Function) that requires compiling native code, introducing potential cross-compilation hurdles and platform dependencies. By implementing the 9p2000 protocol entirely in Erlang, the project eliminates these native code requirements, enabling pure Erlang deployments and facilitating remote access to the filesystem over a network.

The implementation is structured around two primary components: a client and a server. The client handles the protocol's message parsing, connection establishment, and tree-walking operations, which are essential for navigating the filesystem hierarchy. It also implements the IO server logic for reading and writing files, as well as operations for creating and deleting files and directories. On the server side, the implementation mirrors these capabilities, providing the infrastructure to serve a custom filesystem. The server's design emphasizes extensibility, allowing developers to define their own filesystem implementations by adhering to a specific interface. This is a key architectural decision that unlocks the project's potential for diverse use cases.

Two example filesystem implementations are provided to demonstrate this flexibility. The first, UnixFs, is a work-in-progress implementation that aims to expose a real directory from the host system's filesystem. While directory traversal, file reading, writing, and deletion are implemented, the creation of new files and directories is still under development. The second, ErlProcFS, is the project's flagship use case. It is designed to expose the Erlang process tree and other internal runtime data through an API that mimics the Linux /proc filesystem. Initially, this will be read-only, providing a safe and stable way for operators to inspect the Erlang node's state using standard filesystem tools like ls, cat, and find.

The choice of 9p2000 as the underlying protocol is deliberate. Its design as a network protocol means that the filesystem can be accessed remotely, a significant advantage over FUSE-based solutions that are typically local to a single machine. This opens up possibilities for centralized monitoring of distributed Erlang clusters, where a single node could serve a unified view of the entire cluster's process tree to any number of clients. The protocol's simplicity also aligns well with Erlang's philosophy of building robust systems from small, composable parts.

The project's licensing reflects a pragmatic approach to open-source dependencies. The core code is licensed under Apache-2.0, a permissive license that encourages broad adoption and integration. However, the PropEr property-based testing suite, which is licensed under GPL-3.0-only, is used for testing. The author has structured the project so that the GPL-licensed test code is not included in the runtime, ensuring that the main library can be used as a dependency in projects with other licenses. This is a common workaround for projects that rely on GPL-licensed tooling for development but wish to maintain a more permissive runtime license.

The implications of this work extend beyond the immediate goal of Erlang process introspection. By providing a robust, pure-Erlang implementation of 9p2000, the project lays the groundwork for a new class of filesystems within the Erlang ecosystem. Developers could create virtual filesystems that expose configuration data, application metrics, or even dynamic content generated by Erlang applications. The network transparency of 9p2000 could be leveraged to build distributed filesystems where the logical namespace spans multiple Erlang nodes, all without the overhead of mounting FUSE filesystems or managing native code dependencies.

In essence, hauleth.dev/e9p is more than just a protocol implementation; it is an exploration of how Erlang's strengths can be applied to reimagine system introspection and data exposure. By combining the simplicity of the 9p2000 protocol with Erlang's concurrency and fault-tolerance, it offers a compelling alternative to existing solutions, prioritizing portability, network transparency, and the unique capabilities of the Erlang runtime. As the UnixFs implementation matures and ErlProcFS gains more features, this project has the potential to become a valuable tool for developers and operators working within the Erlang/OTP ecosystem.

Comments

Loading comments...