xref: /aosp_15_r20/external/minijail/unittest_util.h (revision 4b9c6d91573e8b3a96609339b46361b5476dd0f9)
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