ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
mkbookimg.c File Reference

Host tool that streams compiled books into an atomic FAT32 image. More...

#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "mkbookimg_internal.h"
#include "mkbookimg_names.h"
#include "ra8_attributes.h"
#include "ra8_fs.h"
Include dependency graph for mkbookimg.c:

Go to the source code of this file.

Data Structures

struct  mkbookimg_output_t
 Caller-owned atomic-publication state. More...

Functions

void priv_mkbookimg_diag (const char *text)
 Write a complete diagnostic fragment to the standard-error descriptor.
void priv_mkbookimg_diag_u64 (uint64_t value)
 Emit an unsigned decimal value without a formatting runtime.
bool priv_mkbookimg_pread_exact (int fd, uint64_t offset, uint8_t *bytes, size_t length)
 Read exactly one bounded positioned byte range.
static bool internal_pwrite_exact (int fd, uint64_t offset, const uint8_t *bytes, size_t length)
 Write exactly one bounded positioned byte range.
static bool internal_block_range (const mkbookimg_disk_t *disk, uint64_t lba, uint32_t count, uint64_t *out_offset, size_t *out_bytes)
 Validate and translate a block range to a host byte range.
static ra8_err_t internal_disk_read (void *ctx, uint64_t lba, uint32_t count, uint8_t *buffer)
 Read sectors from the temporary image for ra8_fs.
static ra8_err_t internal_disk_write (void *ctx, uint64_t lba, uint32_t count, const uint8_t *buffer)
 Write sectors to the temporary image for ra8_fs.
static ra8_err_t internal_disk_capacity (void *ctx, uint64_t *block_count, uint32_t *block_size)
 Report fixed image geometry to ra8_fs.
static bool internal_split_output (const char *path, char parent[k_host_path_cap], char final_name[k_host_name_cap])
 Split an output path into an existing parent directory and safe leaf.
static bool internal_temp_name (char out[k_host_name_cap], uint64_t process, uint32_t attempt)
 Build one hidden sibling-temporary leaf from process id and attempt.
static bool internal_output_begin (const char *final_path, mkbookimg_output_t *output)
 Create and size a private sibling temporary for atomic publication.
static void internal_output_abort (mkbookimg_output_t *output)
 Close and remove an unpublished temporary image.
static bool internal_output_commit (mkbookimg_output_t *output)
 Durably publish the complete image with one same-directory rename.
static void internal_print_success (const char *out_path, int book_count)
 Print the final success diagnostic line.
int main (int argc, char **argv)
 Validate CLI input, construct, verify, and atomically publish one image.

Detailed Description

Host tool that streams compiled books into an atomic FAT32 image.

Streams a 64 MiB FAT32 image through firmware ra8_fs over a sparse sibling. Fixed chunks are verified before sync/rename; no POSIX type crosses into reusable code. This unit owns the host container: descriptor-level diagnostics, exact positioned I/O, the block device, the atomic sibling-temporary publication, and main. The population pass that streams and verifies each book is src/mkbookimg_books.c; the seam between the two is inc/mkbookimg_internal.h.

Since
0.1.0

Definition in file mkbookimg.c.

Function Documentation

◆ internal_block_range()

bool internal_block_range ( const mkbookimg_disk_t * disk,
uint64_t lba,
uint32_t count,
uint64_t * out_offset,
size_t * out_bytes )
static

Validate and translate a block range to a host byte range.

Checks geometry, multiplication, host-offset, and size limits first.

Parameters
[in]diskDescriptor-backed device geometry.
[in]lbaFirst sector.
[in]countSector count.
[out]out_offsetHost byte offset.
[out]out_bytesHost byte count.
Returns
true when the whole range is in bounds and representable.
Return values
trueBoth outputs describe the requested range.
falseThe range exceeds geometry or host integer limits.
Precondition
All pointers are non-NULL.
disk carries non-zero valid geometry.
Postcondition
On true both outputs are initialized.
On false both outputs are untouched.
Note
Pure; thread-safe.
Since
0.1.0

Definition at line 157 of file mkbookimg.c.

References mkbookimg_disk_t::block_count, mkbookimg_disk_t::block_size, and RA8_INTERNAL.

◆ internal_disk_capacity()

ra8_err_t internal_disk_capacity ( void * ctx,
uint64_t * block_count,
uint32_t * block_size )
static

Report fixed image geometry to ra8_fs.

Copies immutable descriptor-backed geometry into caller outputs.

Parameters
[in]ctxBound mkbookimg_disk_t.
[out]block_countReceives the sector count.
[out]block_sizeReceives bytes per sector.
Returns
ra8_fs block-device status.
Return values
k_ra8_okGeometry was copied to both outputs.
k_ra8_err_null_ptrAny argument was NULL.
Precondition
All arguments are non-NULL.
The disk geometry was initialized by main.
Postcondition
On success both outputs are populated.
The disk context is unchanged.
Note
Pure; thread-safe.
Since
0.1.0

Definition at line 266 of file mkbookimg.c.

References mkbookimg_disk_t::block_count, mkbookimg_disk_t::block_size, k_ra8_err_null_ptr, and k_ra8_ok.

◆ internal_disk_read()

ra8_err_t internal_disk_read ( void * ctx,
uint64_t lba,
uint32_t count,
uint8_t * buffer )
static

Read sectors from the temporary image for ra8_fs.

Translates the whole request before issuing exact positioned I/O.

Parameters
[in,out]ctxBound mkbookimg_disk_t.
[in]lbaFirst sector.
[in]countSector count.
[out]bufferDestination for exactly count sectors.
Returns
ra8_fs block-device status.
Return values
k_ra8_okEvery sector was read exactly.
k_ra8_err_out_of_rangeInvalid state, pointer, or range.
k_ra8_failPositioned host I/O failed.
Precondition
ctx and buffer are non-NULL.
The bound descriptor remains open.
Postcondition
On success buffer contains the requested sectors.
A host I/O failure is sticky in the disk context.
Note
Not thread-safe through the sticky failure flag.
Since
0.1.0

Definition at line 198 of file mkbookimg.c.

References mkbookimg_disk_t::fd, internal_block_range(), mkbookimg_disk_t::io_failed, k_ra8_err_out_of_range, k_ra8_fail, k_ra8_ok, and priv_mkbookimg_pread_exact().

◆ internal_disk_write()

ra8_err_t internal_disk_write ( void * ctx,
uint64_t lba,
uint32_t count,
const uint8_t * buffer )
static

Write sectors to the temporary image for ra8_fs.

Translates the whole request before issuing exact positioned I/O.

Parameters
[in,out]ctxBound mkbookimg_disk_t.
[in]lbaFirst sector.
[in]countSector count.
[in]bufferSource containing exactly count sectors.
Returns
ra8_fs block-device status.
Return values
k_ra8_okEvery sector was written exactly.
k_ra8_err_out_of_rangeInvalid state, pointer, or range.
k_ra8_failPositioned host I/O failed.
Precondition
ctx and buffer are non-NULL.
The bound descriptor remains open.
Postcondition
On success the temporary image contains the requested sectors.
A host I/O failure is sticky in the disk context.
Note
Not thread-safe through the sticky failure flag.
Since
0.1.0

Definition at line 233 of file mkbookimg.c.

References mkbookimg_disk_t::fd, internal_block_range(), internal_pwrite_exact(), mkbookimg_disk_t::io_failed, k_ra8_err_out_of_range, k_ra8_fail, and k_ra8_ok.

◆ internal_output_abort()

void internal_output_abort ( mkbookimg_output_t * output)
static

Close and remove an unpublished temporary image.

Idempotently releases the descriptor, private leaf, and parent handle.

Parameters
[in,out]outputPublication state from internal_output_begin.
Precondition
output is non-NULL and may be partially initialized.
No mounted filesystem still uses output->image_fd.
Postcondition
No descriptor or temporary leaf remains owned.
An existing final destination is unchanged.
Note
Not thread-safe for the same state object.
Since
0.1.0

Definition at line 441 of file mkbookimg.c.

References mkbookimg_output_t::directory_fd, mkbookimg_output_t::image_fd, RA8_INTERNAL, mkbookimg_output_t::temp_exists, and mkbookimg_output_t::temp_name.

Referenced by main().

◆ internal_output_begin()

bool internal_output_begin ( const char * final_path,
mkbookimg_output_t * output )
static

Create and size a private sibling temporary for atomic publication.

Uses exclusive no-follow creation and unwinds every partial resource.

Parameters
[in]final_pathRequested output path.
[out]outputCaller-owned publication state.
Returns
true when an empty sparse image is open and owned by output.
Return values
trueThe temporary descriptor has exact image length.
falseValidation, directory open, create, or truncate failed.
Precondition
output is writable and owns no descriptors.
final_path is NUL-terminated.
Postcondition
On true output owns one same-directory temporary.
On false no temporary or descriptor remains owned.
Note
Not thread-safe for the same destination name.
Since
0.1.0

Definition at line 385 of file mkbookimg.c.

References mkbookimg_output_t::directory_fd, mkbookimg_output_t::final_name, mkbookimg_output_t::image_fd, internal_split_output(), internal_temp_name(), k_block_size, k_host_path_cap, k_img_sectors, k_output_create_mode, k_temp_create_attempts, O_CLOEXEC, O_DIRECTORY, O_NOFOLLOW, RA8_INTERNAL, mkbookimg_output_t::temp_exists, and mkbookimg_output_t::temp_name.

Referenced by main().

◆ internal_output_commit()

bool internal_output_commit ( mkbookimg_output_t * output)
static

Durably publish the complete image with one same-directory rename.

Syncs file data before rename and parent metadata after publication.

Parameters
[in,out]outputPublication state owning the complete temporary image.
Returns
true when file sync, close, rename, and directory sync all succeed.
Return values
trueThe final leaf atomically names the complete image.
falsePublication failed; before rename the old final is preserved.
Precondition
No mount or backend call will use output->image_fd again.
output owns a complete temporary image.
Postcondition
The temporary descriptor and directory descriptor are closed.
No temporary leaf remains after a successful rename.
Note
A directory-sync failure after rename reports false although the complete image is already visible; no API can safely roll that rename back.
Since
0.1.0

Definition at line 472 of file mkbookimg.c.

References mkbookimg_output_t::directory_fd, mkbookimg_output_t::final_name, mkbookimg_output_t::image_fd, RA8_INTERNAL, renameat(), mkbookimg_output_t::temp_exists, and mkbookimg_output_t::temp_name.

Referenced by main().

◆ internal_print_success()

void internal_print_success ( const char * out_path,
int book_count )
static

Print the final success diagnostic line.

Emits the published path and the book count as one bounded run of diagnostic fragments through the same descriptor-level writer every failure message uses, so the two can never reach different sinks.

Parameters
[in]out_pathPublished destination path.
[in]book_countNumber of books written.
Returns
Nothing.
Precondition
out_path is a NUL-terminated string.
The publication rename already succeeded, so the path names the image.
Postcondition
Exactly one diagnostic line has been written.
No descriptor, image, or publication state is inspected or changed.
Note
Not thread-safe for a shared diagnostic sink.
Since
0.1.0

Definition at line 515 of file mkbookimg.c.

References priv_mkbookimg_diag(), priv_mkbookimg_diag_u64(), and RA8_INTERNAL.

Referenced by main().

◆ internal_pwrite_exact()

bool internal_pwrite_exact ( int fd,
uint64_t offset,
const uint8_t * bytes,
size_t length )
static

Write exactly one bounded positioned byte range.

Retries interrupted calls and treats a zero write as an I/O failure.

Parameters
[in]fdOpen regular-file descriptor.
[in]offsetAbsolute starting byte offset.
[in]bytesSource spanning length bytes.
[in]lengthExact byte count.
Returns
true only when every byte was written.
Return values
trueThe complete range reached the page cache.
falseOverflow or an unrecoverable/zero write occurred.
Precondition
bytes spans length readable bytes.
The descriptor remains open for this call.
Postcondition
Descriptor position is unchanged.
On false the file may contain a strict prefix in the temporary image.
Note
Not thread-safe for overlapping ranges.
Since
0.1.0

Definition at line 116 of file mkbookimg.c.

Referenced by internal_disk_write().

◆ internal_split_output()

bool internal_split_output ( const char * path,
char parent[k_host_path_cap],
char final_name[k_host_name_cap] )
static

Split an output path into an existing parent directory and safe leaf.

Rejects truncation, empty leaves, and dot traversal components.

Parameters
[in]pathRequested destination path.
[out]parentParent path buffer.
[out]final_nameDestination leaf buffer.
Returns
true when both components fit and the leaf is usable.
Return values
trueBoth outputs are populated.
falseThe path is empty, too long, or names ./../a directory.
Precondition
Output buffers have their declared fixed capacities.
path is non-NULL and NUL-terminated.
Postcondition
On true the two outputs reconstruct path.
On false no filesystem object was touched.
Note
Pure; thread-safe.
Since
0.1.0

Definition at line 293 of file mkbookimg.c.

References k_host_name_cap, k_host_path_cap, memcpy(), RA8_INTERNAL, strcmp(), and strlen().

Referenced by internal_output_begin().

◆ internal_temp_name()

bool internal_temp_name ( char out[k_host_name_cap],
uint64_t process,
uint32_t attempt )
static

Build one hidden sibling-temporary leaf from process id and attempt.

Uses fixed decimal buffers so collision retries require no allocation.

Parameters
[out]outTemporary-name buffer.
[in]processPositive process identifier.
[in]attemptCollision retry index.
Returns
true when the name fits.
Return values
trueout contains a complete NUL-terminated name.
falseThe fixed output capacity was insufficient.
Precondition
out has k_host_name_cap bytes.
process and attempt are finite unsigned values.
Postcondition
No filesystem object was touched.
The resulting name contains no slash.
Note
Pure; thread-safe.
Since
0.1.0

Definition at line 346 of file mkbookimg.c.

References k_decimal_base, k_decimal_u64_digits, k_host_name_cap, memcpy(), and s_prefix.

Referenced by internal_output_begin().

◆ main()

int main ( int argc,
char ** argv )

Validate CLI input, construct, verify, and atomically publish one image.

Parameters
[in]argcArgument count.
[in]argvOutput path followed by one or more book paths.
Returns
Process status: zero success, one runtime failure, two usage error.
Return values
0A complete verified image was atomically published.
1Generation or durable publication failed.
2The command line did not contain a supported input count.
Precondition
argv contains argc entries as required by the hosted C runtime.
The process may open the explicitly supplied paths.
Postcondition
On zero the destination is a complete deterministic FAT32 image.
Before the publication rename, every failure preserves the destination.
Note
Not thread-safe through global ra8_fs slots.
Since
0.1.0

Definition at line 539 of file mkbookimg.c.

References mkbookimg_output_t::image_fd, internal_disk_capacity(), internal_disk_read(), internal_disk_write(), internal_output_abort(), internal_output_begin(), internal_output_commit(), internal_print_success(), k_block_size, k_img_sectors, k_max_books, priv_mkbookimg_build_image(), and priv_mkbookimg_diag().

◆ priv_mkbookimg_diag()

void priv_mkbookimg_diag ( const char * text)

Write a complete diagnostic fragment to the standard-error descriptor.

Retries interrupted and short writes without involving stdio streams.

Parameters
[in]textNUL-terminated fragment.
Precondition
text is non-NULL and NUL-terminated.
Standard error may be written or may reject the diagnostic.
Postcondition
The complete fragment was attempted.
No application state changed.
Note
Fragments may interleave with another process's diagnostics.
Since
0.1.0

Definition at line 41 of file mkbookimg.c.

References strlen().

Referenced by internal_format_mount(), internal_print_success(), internal_write_books(), main(), and priv_mkbookimg_diag_u64().

◆ priv_mkbookimg_diag_u64()

void priv_mkbookimg_diag_u64 ( uint64_t value)

Emit an unsigned decimal value without a formatting runtime.

Converts into fixed local buffers and forwards one bounded string.

Parameters
[in]valueValue to emit.
Precondition
Standard error may be written or may reject the diagnostic.
k_decimal_u64_digits holds every uint64 decimal spelling.
Postcondition
The decimal spelling was attempted on standard error.
No application state changed.
Note
Fragments may interleave with another process's diagnostics.
Since
0.1.0

Definition at line 58 of file mkbookimg.c.

References k_decimal_base, k_decimal_u64_digits, and priv_mkbookimg_diag().

Referenced by internal_print_success(), and internal_write_books().

◆ priv_mkbookimg_pread_exact()

bool priv_mkbookimg_pread_exact ( int fd,
uint64_t offset,
uint8_t * bytes,
size_t length )

Read exactly one bounded positioned byte range.

Retries interrupted calls and rejects EOF before the requested end.

Parameters
[in]fdOpen regular-file descriptor.
[in]offsetAbsolute starting byte offset.
[out]bytesDestination spanning length bytes.
[in]lengthExact byte count.
Returns
true only when every byte was read.
Return values
trueThe destination contains the complete requested range.
falseEOF, overflow, or an unrecoverable read error occurred.
Precondition
bytes spans length writable bytes.
The descriptor remains open for this call.
Postcondition
Descriptor position is unchanged.
On false bytes may hold a strict prefix.
Note
Thread-safe for independent buffers while the descriptor remains open.
Since
0.1.0

Definition at line 75 of file mkbookimg.c.

Referenced by internal_disk_read(), internal_stream_book(), and internal_verify_book().