[qemu-edu] Replace hard-coded path with search.

Update qemu-edu driver client and system test to recursively search
devfs for the matching device file instead of relying on the fully
qualified path as a hard-coded constant.

Bug: 114888
Change-Id: Ic7ef84e0d005b2f09440e3064bcdb897d2cb42b8
Reviewed-on: https://fuchsia-review.googlesource.com/c/sdk-samples/drivers/+/758724
Reviewed-by: Suraj Malhotra <surajmalhotra@google.com>
Reviewed-by: Wayne Piekarski <waynepie@google.com>
Commit-Queue: Dave Smith <smithdave@google.com>
diff --git a/src/qemu_edu/tests/qemu_edu_system_test.cc b/src/qemu_edu/tests/qemu_edu_system_test.cc
index 6b951e8..c0dafb3 100644
--- a/src/qemu_edu/tests/qemu_edu_system_test.cc
+++ b/src/qemu_edu/tests/qemu_edu_system_test.cc
@@ -9,18 +9,23 @@
 #include <lib/fdio/directory.h>
 #include <sys/types.h>
 
+#include <filesystem>
+
 #include <gtest/gtest.h>
 // [END imports]
 
 // [START main_body]
 namespace {
 
-constexpr char kEduDevicePath[] = "/dev/sys/platform/pt/PCI0/bus/00:06.0_/qemu-edu";
+constexpr char kDevfsRootPath[] = "/dev/sys/platform";
+constexpr char kEduDevicePath[] = "qemu-edu";
 
 class QemuEduSystemTest : public testing::Test {
  public:
   void SetUp() {
-    int device = open(kEduDevicePath, O_RDWR);
+    auto device_path = SearchDevicePath();
+    ASSERT_TRUE(device_path.has_value());
+    int device = open(device_path.value().c_str(), O_RDWR);
     ASSERT_GE(device, 0);
 
     fidl::ClientEnd<examples_qemuedu::Device> client_end;
@@ -28,6 +33,20 @@
     device_ = fidl::WireSyncClient(std::move(client_end));
   }
 
+  // [START_EXCLUDE silent]
+  // TODO(fxbug.dev/114888): Remove this once we can alias a stable path for generic devices.
+  // [END_EXCLUDE]
+  // Search for the device file entry in devfs
+  std::optional<std::string> SearchDevicePath() {
+    for (auto const& dir_entry : std::filesystem::recursive_directory_iterator(kDevfsRootPath)) {
+      if (dir_entry.path().string().find(kEduDevicePath) != std::string::npos) {
+        return {dir_entry.path()};
+      }
+    }
+
+    return {};
+  }
+
   fidl::WireSyncClient<examples_qemuedu::Device>& device() { return device_; }
 
  private:
diff --git a/src/qemu_edu/tools/eductl.cc b/src/qemu_edu/tools/eductl.cc
index e76edce..2f1ff75 100644
--- a/src/qemu_edu/tools/eductl.cc
+++ b/src/qemu_edu/tools/eductl.cc
@@ -14,6 +14,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
+
+#include <filesystem>
 // [END imports]
 
 // [START fidl_imports]
@@ -21,7 +23,8 @@
 // [END fidl_imports]
 
 // [START device_path]
-constexpr char kEduDevicePath[] = "/dev/sys/platform/pt/PCI0/bus/00:06.0_/qemu-edu";
+constexpr char kDevfsRootPath[] = "/dev/sys/platform";
+constexpr char kEduDevicePath[] = "qemu-edu";
 // [END device_path]
 
 // [START cli_helpers]
@@ -57,9 +60,28 @@
 // [END cli_helpers]
 
 // [START device_client]
+// [START_EXCLUDE silent]
+// TODO(fxbug.dev/114888): Remove this once we can alias a stable path for generic devices.
+// [END_EXCLUDE]
+// Search for the device file entry in devfs
+std::optional<std::string> SearchDevicePath() {
+  for (auto const& dir_entry : std::filesystem::recursive_directory_iterator(kDevfsRootPath)) {
+    if (dir_entry.path().string().find(kEduDevicePath) != std::string::npos) {
+      return {dir_entry.path()};
+    }
+  }
+
+  return {};
+}
+
 // Open a FIDL client connection to the examples.qemuedu.Device
 fidl::WireSyncClient<examples_qemuedu::Device> OpenDevice() {
-  int device = open(kEduDevicePath, O_RDWR);
+  auto device_path = SearchDevicePath();
+  if (!device_path.has_value()) {
+    fprintf(stderr, "Unable to locate qemu-edu device path.\n");
+    return {};
+  }
+  int device = open(device_path.value().c_str(), O_RDWR);
 
   if (device < 0) {
     fprintf(stderr, "Failed to open qemu edu device: %s\n", strerror(errno));