LCOV - code coverage report
Current view: top level - AP_Filesystem - AP_Filesystem_Sys.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 98 142 69.0 %
Date: 2026-09-09 11:02:08 Functions: 8 9 88.9 %

          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

Generated by: LCOV version 1.14