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