~aleteoryx/muditaos

ref: 3cbbeff551230786ae13c23a7bf4fa8c50099896 muditaos/board/linux/libiosyscalls/src/iosyscalls.cpp -rw-r--r-- 5.6 KiB
3cbbeff5 — Lefucjusz [MOS-1011] Fix frequency switching stability 2 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "iosyscalls-internal.hpp"

#include <parallel_hashmap/phmap.h>

#include <dirent.h>
#include <dlfcn.h>
#include <pthread.h>

#include <algorithm>

#include <cassert>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <cstring>

namespace
{
    constexpr auto ENV_NAME       = "IOSYSCALLS_REDIRECT_TO_IMAGE";
    constexpr auto FIRST_FILEDESC = 64'566'756;
    constexpr auto SYSROOT        = "sysroot";
    constexpr auto SYSTEM_PARTITION = "system_a";
    constexpr auto SYSTEM_DATA_DIR  = "data";
    bool g_evaluated              = false;
    bool g_redirect               = false;

    constexpr auto LINUX_PATHS = {
        "/dev/", "/etc/", "/lib", "/usr/share", "/run/user", "/home", "/proc", "/tmp", "MuditaOS.log"};
    constexpr auto IMAGE_PATHS = {"/system", "/mfgconf", "/user"};

    pthread_mutex_t g_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
    phmap::flat_hash_set<vfsn::linux::internal::FILEX *> g_fdlist;
    phmap::flat_hash_set<DIR *> g_dirlist;
    std::string imageFileName;
    std::string sysroot = SYSROOT;
} // namespace

namespace vfsn::linux::internal
{
    void set_sysroot(const char *newSysroot)
    {
        sysroot = newSysroot;
    }

    void set_image_path(const char *newImageName)
    {
        imageFileName = std::string(newImageName);
    }

    bool redirect_to_image()
    {
        if (!g_evaluated) {
            const auto env = std::getenv(ENV_NAME);
            g_redirect     = env && !std::strcmp(env, "1");
            g_evaluated    = true;
        }
        return g_redirect;
    }

    bool redirect_to_image(const char *inpath)
    {
        if (!redirect_to_image()) {
            return false;
        }

        if (std::strstr(inpath, imageFileName.c_str()) == inpath) {
            return false;
        }

        for (const auto &path : LINUX_PATHS) {
            if (std::strstr(inpath, path) == inpath) {
                return false;
            }
        }

        return true;
    }

    const char *npath_translate(const char *inpath, char *buffer)
    {
        const auto inputPath = std::string(inpath);

        for (const auto &path : IMAGE_PATHS) {
            if (std::strstr(inpath, path) == inpath) {
                std::string outpath   = sysroot;
                const auto pathLength = std::strlen(path);

                if (std::strcmp(path, "/mfgconf") == 0) {
                    outpath += "/";
                    outpath += SYSTEM_PARTITION;
                    outpath += "/";
                    outpath += SYSTEM_DATA_DIR;
                    outpath += inputPath.substr(pathLength);
                }
                else if (std::strcmp(path, "/system") == 0) {
                    outpath += "/";
                    outpath += SYSTEM_PARTITION;
                    outpath += inputPath.substr(pathLength);
                }
                else if (*inpath == '/') {
                    outpath += inputPath;
                }

                assert(outpath.size() < PATH_MAX);
                std::copy_n(std::begin(outpath), outpath.size(), buffer);
                buffer[outpath.size()] = '\0';

                return buffer;
            }
        }

        return inpath;
    }

    bool is_image_handle(const FILE *fil)
    {
        return false;
    }

    int to_native_fd(int fd)
    {
        return FIRST_FILEDESC + fd;
    }

    int to_image_fd(int fd)
    {
        return fd - FIRST_FILEDESC;
    }

    bool is_image_fd(int fd)
    {
        return fd >= FIRST_FILEDESC;
    }

    FILEX *allocate_filex(int fd)
    {
        auto ret = new FILEX;
        ret->fd  = fd;
        pthread_mutex_lock(&g_lock);
        g_fdlist.emplace(ret);
        pthread_mutex_unlock(&g_lock);
        return ret;
    }

    void add_DIR_to_image_list(DIR *indir)
    {
        pthread_mutex_lock(&g_lock);
        g_dirlist.emplace(indir);
        pthread_mutex_unlock(&g_lock);
    }

    void remove_DIR_from_image_list(DIR *indir)
    {
        pthread_mutex_lock(&g_lock);
        auto fres = g_dirlist.find(indir);
        if (fres != g_dirlist.end()) {
            g_dirlist.erase(fres);
        }
        pthread_mutex_unlock(&g_lock);
    }

    bool is_image_DIR(DIR *indir)
    {
        if (indir == nullptr) {
            return false;
        }
        pthread_mutex_lock(&g_lock);
        auto fres    = g_dirlist.find(indir);
        auto isntdir = (fres != g_dirlist.end());
        pthread_mutex_unlock(&g_lock);
        return isntdir;
    }

    bool is_filex(const void *fd)
    {
        if (fd == nullptr) {
            return false;
        }
        pthread_mutex_lock(&g_lock);
        auto fres    = g_fdlist.find(reinterpret_cast<const FILEX *>(fd));
        auto isfilex = (fres != g_fdlist.end());
        pthread_mutex_unlock(&g_lock);
        return isfilex;
    }

    void remove_filex(FILEX *fil)
    {
        pthread_mutex_lock(&g_lock);
        auto fres = g_fdlist.find(fil);
        if (fres != g_fdlist.end()) {
            g_fdlist.erase(fres);
            delete fil;
        }
        pthread_mutex_unlock(&g_lock);
    }

    void debug_trace_syscall(const char *fn, const char *format, ...)
    {
        auto rvprint = reinterpret_cast<decltype(&vfprintf)>(dlsym(RTLD_NEXT, "vfprintf"));
        auto rprint  = reinterpret_cast<decltype(&fprintf)>(dlsym(RTLD_NEXT, "fprintf"));
        rprint(stderr, ">>>>>>> IOFUNC: [%s] ", fn);
        va_list args;
        va_start(args, format);
        rvprint(stderr, format, args);
        va_end(args);
        rprint(stderr, " >>>>>>>>>>>\n");
    }
} // namespace vfsn::linux::internal