Line data Source code
1 : // 2 or 3 structures, select one that is before target point, closest to target
2 :
3 : /*
4 : This program is free software: you can redistribute it and/or modify
5 : it under the terms of the GNU General Public License as published by
6 : the Free Software Foundation, either version 3 of the License, or
7 : (at your option) any later version.
8 :
9 : This program is distributed in the hope that it will be useful,
10 : but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : GNU General Public License for more details.
13 :
14 : You should have received a copy of the GNU General Public License
15 : along with this program. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 : /*
18 : ArduPilot filesystem interface for system information
19 : */
20 : #include "AP_Filesystem.h"
21 : #include "AP_Filesystem_Sys.h"
22 :
23 : #if AP_FILESYSTEM_SYS_ENABLED
24 :
25 : #include <AP_Math/AP_Math.h>
26 : #include <AP_CANManager/AP_CANManager.h>
27 : #include <AP_Scheduler/AP_Scheduler.h>
28 : #include <AP_Common/ExpandingString.h>
29 :
30 : #ifndef AP_CRASHDUMP_FLASH_ENABLED
31 : #define AP_CRASHDUMP_FLASH_ENABLED 0
32 : #endif
33 :
34 : extern const AP_HAL::HAL& hal;
35 :
36 : struct SysFileList {
37 : const char* name;
38 : };
39 :
40 : static const SysFileList sysfs_file_list[] = {
41 : {"threads.txt"},
42 : {"tasks.txt"},
43 : {"dma.txt"},
44 : {"memory.txt"},
45 : {"uarts.txt"},
46 : {"timers.txt"},
47 : #if HAL_NUM_CAN_IFACES > 0
48 : {"can0_stats.txt"},
49 : {"can1_stats.txt"},
50 : #endif
51 : #if !defined(HAL_BOOTLOADER_BUILD) && (defined(STM32F7) || defined(STM32H7))
52 : {"persistent.parm"},
53 : #endif
54 : #if AP_CRASHDUMP_FLASH_ENABLED
55 : {"crash_dump.bin"},
56 : #endif
57 : {"storage.bin"},
58 : #if AP_FILESYSTEM_SYS_FLASH_ENABLED
59 : {"flash.bin"},
60 : #endif
61 : };
62 :
63 10325 : int8_t AP_Filesystem_Sys::file_in_sysfs(const char *fname) {
64 62737 : for (uint8_t i = 0; i < ARRAY_SIZE(sysfs_file_list); i++) {
65 60004 : if (strcmp(fname, sysfs_file_list[i].name) == 0) {
66 7592 : return i;
67 : }
68 : }
69 2733 : return -1;
70 : }
71 :
72 10322 : int AP_Filesystem_Sys::open(const char *fname, int flags, bool allow_absolute_paths)
73 : {
74 10322 : if ((flags & O_ACCMODE) != O_RDONLY) {
75 0 : errno = EROFS;
76 0 : return -1;
77 : }
78 : uint8_t idx;
79 10354 : for (idx=0; idx<max_open_file; idx++) {
80 10354 : if (!file[idx].open) {
81 10322 : break;
82 : }
83 : }
84 10322 : if (idx == max_open_file) {
85 0 : errno = ENFILE;
86 0 : return -1;
87 : }
88 10322 : struct rfile &r = file[idx];
89 10322 : r.str = NEW_NOTHROW ExpandingString;
90 10322 : if (r.str == nullptr) {
91 0 : errno = ENOMEM;
92 0 : return -1;
93 : }
94 :
95 : // This ensure that whenever new sys file is added its also added to list above
96 10322 : int8_t pos = file_in_sysfs(fname);
97 10322 : if (pos < 0) {
98 2733 : delete r.str;
99 2733 : r.str = nullptr;
100 2733 : errno = ENOENT;
101 2733 : return -1;
102 : }
103 :
104 7589 : if (strcmp(fname, "threads.txt") == 0) {
105 1263 : hal.util->thread_info(*r.str);
106 : }
107 : #if AP_SCHEDULER_ENABLED
108 7589 : if (strcmp(fname, "tasks.txt") == 0) {
109 2 : AP::scheduler().task_info(*r.str);
110 : }
111 : #endif
112 7589 : if (strcmp(fname, "dma.txt") == 0) {
113 1264 : hal.util->dma_info(*r.str);
114 : }
115 7589 : if (strcmp(fname, "memory.txt") == 0) {
116 1263 : hal.util->mem_info(*r.str);
117 : }
118 : #if HAL_UART_STATS_ENABLED
119 7589 : if (strcmp(fname, "uarts.txt") == 0) {
120 1276 : hal.util->uart_info(*r.str);
121 : }
122 : #endif
123 7589 : if (strcmp(fname, "timers.txt") == 0) {
124 1262 : hal.util->timer_info(*r.str);
125 : }
126 : #if HAL_NUM_CAN_IFACES > 0
127 7589 : int8_t can_stats_num = -1;
128 7589 : if (strcmp(fname, "can0_stats.txt") == 0) {
129 0 : can_stats_num = 0;
130 7589 : } else if (strcmp(fname, "can1_stats.txt") == 0) {
131 0 : can_stats_num = 1;
132 : }
133 7589 : if (can_stats_num != -1 && can_stats_num < HAL_NUM_CAN_IFACES) {
134 0 : if (hal.can[can_stats_num] != nullptr) {
135 0 : hal.can[can_stats_num]->get_stats(*r.str);
136 : }
137 : }
138 : #endif
139 7589 : if (strcmp(fname, "persistent.parm") == 0) {
140 0 : hal.util->load_persistent_params(*r.str);
141 : }
142 : #if AP_CRASHDUMP_FLASH_ENABLED
143 : if (strcmp(fname, "crash_dump.bin") == 0) {
144 : void *ptr = hal.util->last_crash_dump_ptr();
145 : if (ptr != nullptr) {
146 : r.str->set_buffer((char*)ptr, hal.util->last_crash_dump_size(), hal.util->last_crash_dump_size());
147 : }
148 : }
149 : #endif
150 7589 : if (strcmp(fname, "storage.bin") == 0) {
151 : // we don't want to store the contents of storage.bin
152 : // we read directly from the storage driver
153 1259 : void *ptr = nullptr;
154 1259 : size_t size = 0;
155 1259 : if (hal.storage->get_storage_ptr(ptr, size)) {
156 1259 : r.str->set_buffer((char*)ptr, size, size);
157 : }
158 : }
159 : #if AP_FILESYSTEM_SYS_FLASH_ENABLED
160 : if (strcmp(fname, "flash.bin") == 0) {
161 : void *ptr = (void*)0x08000000;
162 : const size_t size = HAL_PROGRAM_SIZE_LIMIT_KB*1024;
163 : r.str->set_buffer((char*)ptr, size, size);
164 : }
165 : #endif
166 :
167 7589 : if (r.str->get_length() == 0) {
168 5052 : errno = r.str->has_failed_allocation()?ENOMEM:ENOENT;
169 5052 : delete r.str;
170 5052 : r.str = nullptr;
171 5052 : return -1;
172 : }
173 2537 : r.file_ofs = 0;
174 2537 : r.open = true;
175 2537 : return idx;
176 : }
177 :
178 2473 : int AP_Filesystem_Sys::close(int fd)
179 : {
180 2473 : if (fd < 0 || fd >= max_open_file || !file[fd].open) {
181 0 : errno = EBADF;
182 0 : return -1;
183 : }
184 2473 : struct rfile &r = file[fd];
185 2473 : r.open = false;
186 2473 : delete r.str;
187 2473 : r.str = nullptr;
188 2473 : return 0;
189 : }
190 :
191 306361 : int32_t AP_Filesystem_Sys::read(int fd, void *buf, uint32_t count)
192 : {
193 306361 : if (fd < 0 || fd >= max_open_file || !file[fd].open) {
194 0 : errno = EBADF;
195 0 : return -1;
196 : }
197 306361 : struct rfile &r = file[fd];
198 306361 : count = MIN(count, r.str->get_length() - r.file_ofs);
199 306361 : memcpy(buf, &r.str->get_string()[r.file_ofs], count);
200 :
201 306361 : r.file_ofs += count;
202 306361 : return count;
203 : }
204 :
205 3921 : int32_t AP_Filesystem_Sys::lseek(int fd, int32_t offset, int seek_from)
206 : {
207 3921 : if (fd < 0 || fd >= max_open_file || !file[fd].open) {
208 0 : errno = EBADF;
209 0 : return -1;
210 : }
211 3921 : struct rfile &r = file[fd];
212 :
213 3921 : int64_t new_ofs = -1; // -1 being invalid
214 3921 : switch (seek_from) {
215 3921 : case SEEK_SET:
216 3921 : new_ofs = offset;
217 3921 : break;
218 0 : case SEEK_CUR:
219 : // Compute the new offset in signed 64-bit space to avoid
220 : // 32-bit overflows:
221 0 : new_ofs = int64_t(r.file_ofs) + int64_t(offset);
222 0 : break;
223 0 : case SEEK_END:
224 : // we don't support this, leave new_ofs at -1 meaning "invalid"
225 0 : break;
226 : }
227 :
228 : // special semantics for Sysfs - don't allow seeking outside the file
229 3921 : if (new_ofs < 0 || new_ofs > r.str->get_length()) {
230 1 : errno = EINVAL;
231 1 : return -1;
232 : }
233 :
234 3920 : r.file_ofs = (uint32_t)new_ofs;
235 :
236 : // note conversion from uint32_t to int32_t in return value here.
237 : // Above we clamp to r.str->get_length(), so in practise no
238 : // truncation can occur here.
239 3920 : return r.file_ofs;
240 : }
241 :
242 1 : void *AP_Filesystem_Sys::opendir(const char *pathname)
243 : {
244 1 : if (strlen(pathname) > 0) {
245 : // no sub directories
246 0 : errno = ENOENT;
247 0 : return nullptr;
248 : }
249 1 : DirReadTracker *dtracker = NEW_NOTHROW DirReadTracker;
250 1 : if (dtracker == nullptr) {
251 0 : errno = ENOMEM;
252 0 : return nullptr;
253 : }
254 1 : return dtracker;
255 : }
256 :
257 0 : struct dirent *AP_Filesystem_Sys::readdir(void *dirp)
258 : {
259 0 : DirReadTracker* dtracker = ((DirReadTracker*)dirp);
260 0 : if (dtracker->file_offset >= ARRAY_SIZE(sysfs_file_list)) {
261 : // we have reached end of list
262 0 : return nullptr;
263 : }
264 : #if AP_FILESYSTEM_HAVE_DIRENT_DTYPE
265 0 : dtracker->curr_file.d_type = DT_REG;
266 : #endif
267 0 : size_t max_length = ARRAY_SIZE(dtracker->curr_file.d_name);
268 0 : strncpy_noterm(dtracker->curr_file.d_name, sysfs_file_list[dtracker->file_offset].name, max_length);
269 0 : dtracker->file_offset++;
270 0 : return &dtracker->curr_file;
271 : }
272 :
273 1 : int AP_Filesystem_Sys::closedir(void *dirp)
274 : {
275 1 : if (dirp == nullptr) {
276 0 : errno = EINVAL;
277 0 : return -1;
278 : }
279 1 : delete (DirReadTracker*)dirp;
280 1 : return 0;
281 : }
282 :
283 3 : int AP_Filesystem_Sys::stat(const char *pathname, struct stat *stbuf)
284 : {
285 3 : if (pathname == nullptr || stbuf == nullptr || (strlen(pathname) == 0)) {
286 0 : errno = EINVAL;
287 0 : return -1;
288 : }
289 3 : memset(stbuf, 0, sizeof(*stbuf));
290 3 : if (strlen(pathname) == 1 && pathname[0] == '/') {
291 0 : stbuf->st_size = 0; // just a placeholder value
292 0 : return 0;
293 : }
294 3 : const char *pathname_noslash = pathname;
295 3 : if (pathname[0] == '/') {
296 0 : pathname_noslash = &pathname[1];
297 : }
298 3 : int8_t pos = file_in_sysfs(pathname_noslash);
299 3 : if (pos < 0) {
300 0 : errno = ENOENT;
301 0 : return -1;
302 : }
303 : // give a fixed size for stat. It is too expensive to
304 : // read every file for a directory listing
305 3 : if (strcmp(pathname_noslash, "storage.bin") == 0) {
306 1 : stbuf->st_size = HAL_STORAGE_SIZE;
307 : #if AP_CRASHDUMP_FLASH_ENABLED
308 : } else if (strcmp(pathname_noslash, "crash_dump.bin") == 0) {
309 : stbuf->st_size = hal.util->last_crash_dump_size();
310 : #endif
311 : } else {
312 2 : stbuf->st_size = 100000;
313 : }
314 3 : return 0;
315 : }
316 :
317 : #endif // AP_FILESYSTEM_SYS_ENABLED
|