1 /* unittest_util.h
2 * Copyright 2022 The ChromiumOS Authors
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 *
6 * Utility functions for unit tests.
7 */
8
9 #include <errno.h>
10 #include <ftw.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14
15 #include "util.h"
16
17 namespace {
18
is_android_constexpr()19 constexpr bool is_android_constexpr() {
20 #if defined(__ANDROID__)
21 return true;
22 #else
23 return false;
24 #endif
25 }
26
27 // Returns a template path that can be used as an argument to mkstemp / mkdtemp.
temp_path_pattern()28 constexpr const char* temp_path_pattern() {
29 if (is_android_constexpr())
30 return "/data/local/tmp/minijail.tests.XXXXXX";
31 else
32 return "minijail.tests.XXXXXX";
33 }
34
35 // Recursively deletes the subtree rooted at |path|.
rmdir_recursive(const std::string & path)36 bool rmdir_recursive(const std::string& path) {
37 auto callback = [](const char* child, const struct stat*, int file_type,
38 struct FTW*) -> int {
39 if (file_type == FTW_DP) {
40 if (rmdir(child) == -1) {
41 fprintf(stderr, "rmdir(%s): %s\n", child, strerror(errno));
42 return -1;
43 }
44 } else if (file_type == FTW_F) {
45 if (unlink(child) == -1) {
46 fprintf(stderr, "unlink(%s): %s\n", child, strerror(errno));
47 return -1;
48 }
49 }
50 return 0;
51 };
52
53 return nftw(path.c_str(), callback, 128, FTW_DEPTH) == 0;
54 }
55
56 } // namespace
57
58 // Creates a temporary directory that will be cleaned up upon leaving scope.
59 class TemporaryDir {
60 public:
TemporaryDir()61 TemporaryDir() : path(temp_path_pattern()) {
62 if (mkdtemp(const_cast<char*>(path.c_str())) == nullptr)
63 path.clear();
64 }
~TemporaryDir()65 ~TemporaryDir() {
66 if (!is_valid())
67 return;
68 rmdir_recursive(path.c_str());
69 }
70
is_valid()71 bool is_valid() const { return !path.empty(); }
72
73 std::string path;
74
75 private:
76 TemporaryDir(const TemporaryDir&) = delete;
77 TemporaryDir& operator=(const TemporaryDir&) = delete;
78 };
79
80 // Creates a named temporary file that will be cleaned up upon leaving scope.
81 class TemporaryFile {
82 public:
TemporaryFile()83 TemporaryFile() : path(temp_path_pattern()) {
84 int fd = mkstemp(const_cast<char*>(path.c_str()));
85 if (fd == -1) {
86 path.clear();
87 return;
88 }
89 close(fd);
90 }
~TemporaryFile()91 ~TemporaryFile() {
92 if (!is_valid())
93 return;
94 unlink(path.c_str());
95 }
96
is_valid()97 bool is_valid() const { return !path.empty(); }
98
99 std::string path;
100
101 private:
102 TemporaryFile(const TemporaryFile&) = delete;
103 TemporaryFile& operator=(const TemporaryFile&) = delete;
104 };
105