1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <lib/devmgr-integration-test/fixture.h>
6
7 #include <fcntl.h>
8
9 #include <fbl/unique_fd.h>
10 #include <lib/fdio/watcher.h>
11
12 namespace devmgr_integration_test {
13
14 // Waits for |file| to appear in |dir|, and opens it when it does. Times out if
15 // the deadline passes.
WaitForFile(const fbl::unique_fd & dir,const char * file,zx::time deadline,fbl::unique_fd * out)16 zx_status_t WaitForFile(const fbl::unique_fd& dir, const char* file, zx::time deadline,
17 fbl::unique_fd* out) {
18 auto watch_func = [](int dirfd, int event, const char* fn, void* cookie) -> zx_status_t {
19 auto file = reinterpret_cast<const char*>(cookie);
20 if (event != WATCH_EVENT_ADD_FILE) {
21 return ZX_OK;
22 }
23 if (!strcmp(fn, file)) {
24 return ZX_ERR_STOP;
25 }
26 return ZX_OK;
27 };
28
29 zx_status_t status = fdio_watch_directory(dir.get(), watch_func, deadline.get(),
30 const_cast<char*>(file));
31 if (status != ZX_ERR_STOP) {
32 return status;
33 }
34 out->reset(openat(dir.get(), file, O_RDWR));
35 if (!out->is_valid()) {
36 return ZX_ERR_IO;
37 }
38 return ZX_OK;
39 }
40
41 namespace {
42
43 // Version of recursive_wait_for_file that can mutate its path
RecursiveWaitForFileHelper(const fbl::unique_fd & dir,char * path,zx::time deadline,fbl::unique_fd * out)44 zx_status_t RecursiveWaitForFileHelper(const fbl::unique_fd& dir, char* path,
45 zx::time deadline, fbl::unique_fd* out) {
46 char* first_slash = strchr(path, '/');
47 if (first_slash == nullptr) {
48 // If there's no first slash, then we're just waiting for the file
49 // itself to appear.
50 return WaitForFile(dir, path, deadline, out);
51 }
52 *first_slash = 0;
53
54 fbl::unique_fd next_dir;
55 zx_status_t status = WaitForFile(dir, path, deadline, &next_dir);
56 if (status != ZX_OK) {
57 return status;
58 }
59 return RecursiveWaitForFileHelper(next_dir, first_slash + 1, deadline, out);
60 }
61
62 } // namespace
63
64 // Waits for the relative |path| starting in |dir| to appear, and opens it.
RecursiveWaitForFile(const fbl::unique_fd & dir,const char * path,zx::time deadline,fbl::unique_fd * out)65 zx_status_t RecursiveWaitForFile(const fbl::unique_fd& dir, const char* path,
66 zx::time deadline, fbl::unique_fd* out) {
67 char path_copy[PATH_MAX];
68 if (strlen(path) >= sizeof(path_copy)) {
69 return ZX_ERR_INVALID_ARGS;
70 }
71 strcpy(path_copy, path);
72 return RecursiveWaitForFileHelper(dir, path_copy, deadline, out);
73 }
74
75 } // namespace devmgr_integration_test
76