diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 45a92df..0e1e56d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,19 +36,24 @@ jobs: test -f build/dmf/blkid.dmf test -f build/dmf/dmpart.dmf test -f build/dmf/test_dmpart.dmf + test -f build/dmf/automount.dmf + test -f build/dmf/libautomount.dmf + test -f build/dmf/test_libautomount.dmf echo "Module files present" # dmblkid uses the 64-bit file API (Dmod_FileSeek/_FileTell/_FileSize # 2.0, dmod#312). The dmod_loader in the 1.0.4 image predates it, so # the tests run in one built from the same dmod develop the module - # is built against. + # is built against. Cloned into a fresh directory: the image already + # has a /tmp/dmod of its own. - name: Build dmod_loader from dmod develop run: | - git clone --depth 1 -b develop https://github.com/choco-technologies/dmod.git /tmp/dmod - cmake -S /tmp/dmod -B /tmp/dmod/build -DDMOD_MODE=DMOD_SYSTEM \ + DMOD_SRC=$(mktemp -d) + git clone --depth 1 -b develop https://github.com/choco-technologies/dmod.git "$DMOD_SRC" + cmake -S "$DMOD_SRC" -B "$DMOD_SRC/build" -DDMOD_MODE=DMOD_SYSTEM \ -DDMOD_BUILD_EXAMPLES=ON -DDMOD_BUILD_TESTS=OFF - cmake --build /tmp/dmod/build --target dmod_loader - echo "DMOD_LOADER=/tmp/dmod/build/examples/system/dmod_loader/dmod_loader" >> $GITHUB_ENV + cmake --build "$DMOD_SRC/build" --target dmod_loader + echo "DMOD_LOADER=$DMOD_SRC/build/examples/system/dmod_loader/dmod_loader" >> $GITHUB_ENV - name: Run tests with dmod_loader run: | @@ -57,6 +62,8 @@ jobs: ${DMOD_LOADER} build/dmf/test_dmpart.dmf dmf-get install -d ${DMOD_DMF_DIR}/test_dmblkid-local.dmd -y ${DMOD_LOADER} build/dmf/test_dmblkid.dmf + dmf-get install -d ${DMOD_DMF_DIR}/test_libautomount-local.dmd -y + ${DMOD_LOADER} build/dmf/test_libautomount.dmf build-targets: name: Build for ${{ matrix.arch }} @@ -87,3 +94,5 @@ jobs: test -f dmf/dmblkid.dmf test -f dmf/blkid.dmf test -f dmf/dmpart.dmf + test -f dmf/automount.dmf + test -f dmf/libautomount.dmf diff --git a/CMakeLists.txt b/CMakeLists.txt index 855475b..b3f7276 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,5 +91,11 @@ add_subdirectory(libs/dmpart) # blkid - command line front end add_subdirectory(services/blkid) +# libautomount - mounting block nodes (everything automount does, loaded once) +add_subdirectory(libs/libautomount) + +# automount - the per-node service around libautomount +add_subdirectory(services/automount) + enable_testing() add_subdirectory(tests) diff --git a/README.md b/README.md index 4380a81..8da4175 100644 --- a/README.md +++ b/README.md @@ -24,9 +24,10 @@ prints it. | blank, damaged or unsupported | `unknown` | - | size | Every type is mapped to the DMOD filesystem module that handles it and -whether that module can mount the node. Today none can: FAT and exFAT have -no module yet, and dmffs mounts memory-mapped flash rather than a node - so -they are reported, but marked not mountable. +whether that module can mount the node: FAT and exFAT are mounted by +[dmfatfs](https://github.com/choco-technologies/dmfatfs) from the node +itself; dmffs is reported, but marked not mountable - it mounts +memory-mapped flash rather than a node. Detection is strict, so that nothing is mounted by mistake: @@ -72,11 +73,20 @@ The command line front end: ``` > blkid /dev/dmsdio0/0 /dev/dmsdio0/0p1 /dev/dmsdio0/0: PTTYPE="mbr" PTUUID="1a2b3c4d" PARTITIONS="1" BLOCK_SIZE="512" SIZE="15931539456" -/dev/dmsdio0/0p1: TYPE="vfat" VERSION="FAT32" LABEL="SDCARD" UUID="CAFE-BABE" SIZE="15930490880" MOUNTABLE="no" +/dev/dmsdio0/0p1: TYPE="vfat" VERSION="FAT32" LABEL="SDCARD" UUID="CAFE-BABE" SIZE="15930490880" MODULE="dmfatfs" MOUNTABLE="yes" ``` See [services/blkid/README.md](services/blkid/README.md). +### Automount + +The `automount` service mounts every block node dmdevfs reports that holds +a mountable file system, at `/mnt/` (or `/mnt/` +when there is no label or it is taken), and unmounts it when the node goes +away. It is a thin `main()` around [libautomount](libs/libautomount/README.md), +which does the work once for all instances. See +[services/automount/README.md](services/automount/README.md). + ## API | Function | Description | @@ -172,8 +182,10 @@ dmblkid/ ├── include/ │ └── dmblkid.h # Public API ├── libs/ -│ └── dmpart/ # dmpart - MBR/GPT parser library (also used by dmdevfs) +│ ├── dmpart/ # dmpart - MBR/GPT parser library (also used by dmdevfs) +│ └── libautomount/ # libautomount - the automount logic, loaded once ├── services/ +│ ├── automount/ # automount service (per node, around libautomount) │ └── blkid/ # blkid command line application ├── src/ │ ├── dmblkid.c # dmblkid_probe(), result accessors @@ -187,6 +199,7 @@ dmblkid/ ├── tests/ │ ├── CMakeLists.txt │ ├── dmblkid_test.c +│ ├── libautomount_test.c # libautomount mount logic │ └── test_images.c # Image builders ├── CMakeLists.txt ├── Makefile diff --git a/docs/api-reference.md b/docs/api-reference.md index 6b70f95..55b22f1 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -123,9 +123,9 @@ const char* dmblkid_get_uuid(const dmblkid_t* result); const char* dmblkid_get_module(const dmblkid_t* result); ``` -The DMOD filesystem module that handles the type: `"dmffs"` for dmffs. -`NULL` for types the ecosystem has no module for yet (FAT, exFAT), for -partition tables and for unknown contents. +The DMOD filesystem module that handles the type: `"dmfatfs"` for FAT and +exFAT, `"dmffs"` for dmffs. `NULL` for partition tables and for unknown +contents. ### `dmblkid_is_mountable` @@ -133,9 +133,9 @@ partition tables and for unknown contents. bool dmblkid_is_mountable(const dmblkid_t* result); ``` -`true` only if `dmblkid_get_module()` can mount the node itself. `false` for -dmffs: its module mounts memory-mapped flash (`flash_addr`/`flash_size`), not -a node. +`true` only if `dmblkid_get_module()` can mount the node itself - FAT and +exFAT (`dmvfs_mount_fs("dmfatfs", , )`). `false` for dmffs: its +module mounts memory-mapped flash (`flash_addr`/`flash_size`), not a node. ### `dmblkid_get_size` diff --git a/include/dmblkid.h b/include/dmblkid.h index 4a46a23..2de2f94 100644 --- a/include/dmblkid.h +++ b/include/dmblkid.h @@ -76,8 +76,8 @@ dmod_dmblkid_api(1.0, const char*, _get_label, ( const dmblkid_t* result )); dmod_dmblkid_api(1.0, const char*, _get_uuid, ( const dmblkid_t* result )); /** - * @return Name of the DMOD filesystem module that handles this format, or - * NULL if the ecosystem has none (FAT, exFAT today). + * @return Name of the DMOD filesystem module that handles this format + * ("dmfatfs" for FAT/exFAT, "dmffs"), or NULL if there is none. */ dmod_dmblkid_api(1.0, const char*, _get_module, ( const dmblkid_t* result )); diff --git a/libs/libautomount/CMakeLists.txt b/libs/libautomount/CMakeLists.txt new file mode 100644 index 0000000..a85395f --- /dev/null +++ b/libs/libautomount/CMakeLists.txt @@ -0,0 +1,33 @@ +# ===================================================================== +# libautomount - mounting block nodes as they appear +# ===================================================================== +# Everything the automount service (services/automount) does, as a library: +# loaded once, while the service runs once per block node - see README.md. +# Built and released with dmblkid. +set(DMOD_MODULE_NAME libautomount) +set(DMOD_AUTHOR_NAME "Patryk Kubiak") +set(DMOD_STACK_SIZE 1024) +set(DMOD_DMR_PATH ${CMAKE_CURRENT_SOURCE_DIR}/libautomount.dmr) + +dmod_add_library(${DMOD_MODULE_NAME} ${DMOD_MODULE_VERSION} + src/libautomount.c + src/libautomount_core.c + src/libautomount_os.c +) + +target_include_directories(${DMOD_MODULE_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/src +) + +target_include_directories(${DMOD_MODULE_NAME}_if INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/include +) + +# dmblkid - local sibling (repository root): headers from its _if target +target_link_libraries(${DMOD_MODULE_NAME} dmblkid_if) + +dmod_link_modules(${DMOD_MODULE_NAME} + dmosi + libsystemd +) diff --git a/libs/libautomount/README.md b/libs/libautomount/README.md new file mode 100644 index 0000000..a3a7d5c --- /dev/null +++ b/libs/libautomount/README.md @@ -0,0 +1,56 @@ +# libautomount + +Mounting block nodes as they appear - everything the +[automount](../../services/automount/README.md) service does, as a library. + +A library module is loaded once, while the service runs once per block node +(one instance per partition of every card). Keeping the logic here means it +is in memory once, however many volumes are mounted: the service itself is +only a `main()` calling `libautomount_run()`. + +## API + +```c +#include "libautomount.h" + +/* The whole service: mount, wait for a libsystemd stop, unmount. */ +int libautomount_run(const char* node, const char* name, const char* base_dir); + +/* The same without waiting. */ +libautomount_t* libautomount_mount(const char* node, const char* name, const char* base_dir, int* error); +void libautomount_unmount(libautomount_t* mount); +const char* libautomount_get_dir(const libautomount_t* mount); +``` + +- `node` - device node, e.g. `/dev/dmsdio0/0p1` +- `name` - directory used when the volume label cannot be, e.g. `dmsdio0_0p1` +- `base_dir` - directory volumes are mounted in, `NULL` for `/mnt` + +The node is probed with dmblkid. A file system that a module can mount from +a node (`dmblkid_is_mountable()`; FAT and exFAT through dmfatfs) is mounted +with that module at `/