2026-06-12 09:21:18 +02:00
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2026 Andrea Mazzoleni
2026-10-13 11:20:19 +02:00
# ifndef APP_H
# define APP_H
2026-06-12 09:21:18 +02:00
2026-06-24 00:15:15 +02:00
# include "os/os.h"
2026-06-12 09:21:18 +02:00
/**
* Include list support to have tommy_node .
*/
# include "tommyds/tommylist.h"
2026-08-26 08:36:19 +02:00
# define STATIC_ASSERT(name, cond) typedef char static_assert_ ## name[(cond) ? 1 : -1]
2026-09-20 15:56:14 +02:00
# define EDATA (-1) /**< Silent data corruption. */
2026-06-24 00:15:15 +02:00
# define EINTERNAL EFAULT /**< Internal assertion failed. */
# define ESOFT EINVAL /**< Software error, like permission denied. */
# define EUSER EINVAL /**< Invalid value specified by the user. */
# define EEXTERNAL EINVAL /**< Invalid external interface behaviour. */
# define ECONTENT EINVAL /**< Invalid content file. */
# define EENVIRONMENT EINVAL /**< Invalid physical environment, like temperature too high. */
# define ESYSLOG EINVAL /**< Syslog error. */
2026-06-12 09:21:18 +02:00
/**
* Basic block position type .
*/
typedef uint64_t block_off_t ;
/**
* Basic data position type .
* It ' s signed as file size and offset are usually signed .
*/
typedef int64_t data_off_t ;
/**
* Another name for link ( ) to avoid confusion with local variables called " link " .
*/
static inline int hardlink ( const char * a , const char * b )
{
return link ( a , b ) ;
}
/**
* Get the device UUID .
* Return 0 on success .
*/
int devuuid ( uint64_t device_id , const char * device_path , char * uuid , size_t size ) ;
2026-08-26 08:36:19 +02:00
/**
* Filesystem identity for directory boundary checks .
*/
struct fsidentity {
uint64_t device ; /**< Device identifier (st_dev). */
uint64_t mnt_id ; /**< Mount identifier (stx_mnt_id or 0). */
uint64_t subvol ; /**< Subvolume identifier (stx_subvol or 0). */
} ;
/**
* Get the filesystem identity of a path .
*
* The caller already provides the normal stat information .
* This function must NOT repeat lstat ( ) / stat ( ) for normal metadata .
*
* mnt_id and subvol are set to zero when unavailable .
*
* Return 0 on success , - 1 on error .
*/
int fsidentity ( const char * path , const struct stat * st , struct fsidentity * identity ) ;
2026-06-12 09:21:18 +02:00
/**
* Check if the underline file - system support persistent inodes .
* Return - 1 on error , 0 on success .
*/
int fsinfo ( const char * path , int * has_persistent_inode , int * has_syncronized_hardlinks , uint64_t * total_space , uint64_t * free_space , char * fstype , size_t fstype_size , char * fslabel , size_t fslabel_size ) ;
/**
* Where snapshot are accessible
*/
# define SNAPSHOT_CONTAINER ".snapraid"
/**
* Snapshots names
*/
# define SNAPSHOT_PENDING "pending"
# define SNAPSHOT_STABLE "stable"
2026-08-12 14:53:58 +02:00
# define SNAPSHOT_SCAN "scan"
2026-09-08 22:19:55 +02:00
# define SNAPSHOT_RETIRING_SUFFIX ".retiring"
2026-06-12 09:21:18 +02:00
2026-10-07 09:09:39 +02:00
/**
2026-06-12 09:21:18 +02:00
* Snapshots context
*/
struct fssnapshot_struct {
/**
* Filesystem magic number
* 0 if no snapshot support
*/
uint32_t magic ;
/**
* Root directory of the volume / dataset mountpoint .
* It ALWAYS terminates with /
2026-08-25 23:09:39 +02:00
* - Btrfs / Bcachefs : subvolume root ( canonical path via realpath )
* - ZFS : dataset mountpoint ( canonical path via realpath )
* - Windows : volume mountpoint ( via GetVolumePathName )
2026-06-12 09:21:18 +02:00
*/
char root_dir [ PATH_MAX ] ;
/**
* Directory where snapshots are accessible as subdirectories .
* It ALWAYS terminates with /
* - Btrfs / Bcachefs : real directory ( e . g . < root > / . snapraid / )
* - ZFS : virtual directory ( e . g . < root > / . zfs / snapshot / )
2026-08-25 23:09:39 +02:00
* - Windows : symlink container directory ( e . g . < root > / . snapraid / )
2026-06-12 09:21:18 +02:00
*/
char snapshot_dir [ PATH_MAX ] ;
2026-08-25 23:09:39 +02:00
/**
* Data directory relative to root_dir in snapshots .
*
* It NEVER starts with ' / ' .
* It is empty if the configured data directory is exactly root_dir .
* If non - empty , it ALWAYS terminates with ' / ' .
* - Unix : relative suffix computed from the realpath ( ) canonical representation
2026-09-09 00:21:49 +02:00
* - Windows : relative suffix computed from the GetFullPathNameW ( ) absolute representation without resolving reparse points
2026-08-25 23:09:39 +02:00
*/
char sub_dir [ PATH_MAX ] ;
2026-06-12 09:21:18 +02:00
/*
* Dataset name for ZFS ( e . g . " pool/data " )
2026-08-25 23:09:39 +02:00
* or VolumeName in Windows ( e . g . " \\ ? \ Volume{guid} \" ).
2026-06-12 09:21:18 +02:00
* Empty string for filesystems where not applicable .
*/
char dataset [ PATH_MAX ] ;
} ;
/**
* Initialize snapshot context from an arbitrary path .
*
2026-09-09 00:21:49 +02:00
* @ param dir Path inside the filesystem ( must end with ' / ' )
2026-06-12 09:21:18 +02:00
* @ param fss Output snapshot context
2026-09-08 22:19:55 +02:00
* @ return 0 on success , 1 if snapshots are unsupported , - 1 on failure
2026-06-12 09:21:18 +02:00
*/
int fssnapshot_mount ( const char * dir , struct fssnapshot_struct * fss ) ;
/**
* Unmount the snapshots .
*
* Required in Windows to remove the temporary symlinks .
*
* @ param fss Snapshot context
*/
void fssnapshot_unmount ( const struct fssnapshot_struct * fss ) ;
/**
* Stat the snapshot directory .
*
* @ param fss Snapshot context
* @ param name Snapshot name
* @ param st Set the stat info
* @ return 0 on success , - 1 on failure
*/
int fssnapshot_stat ( struct fssnapshot_struct * fss , const char * name , struct stat * st ) ;
/**
* Create a snapshot of the filesystem root / dataset .
*
* @ param fss Snapshot context
* @ param name Snapshot name
* @ return 0 on success , - 1 on failure
*/
int fssnapshot_create ( const struct fssnapshot_struct * fss , const char * name ) ;
/**
* Delete a snapshot .
*
* @ param fss Snapshot context
* @ param name Snapshot name
* @ return 0 on success , - 1 on failure
*/
int fssnapshot_delete ( const struct fssnapshot_struct * fss , const char * name ) ;
/**
* Rename a snapshot .
*
* @ param fss Snapshot context
* @ param old_name Existing snapshot name
* @ param new_name New snapshot name
* @ return 0 on success , - 1 on failure
*/
int fssnapshot_rename ( const struct fssnapshot_struct * fss , const char * old_name , const char * new_name ) ;
2026-09-08 22:19:55 +02:00
/**
* Replace a snapshot while preserving the previous destination until the new one is published .
*
* An interrupted replacement is recovered automatically by fssnapshot_mount ( ) .
*
* @ param fss Snapshot context
* @ param old_name Existing source snapshot name
* @ param new_name Destination snapshot name
* @ return 0 on success , - 1 on failure
*/
int fssnapshot_replace ( struct fssnapshot_struct * fss , const char * old_name , const char * new_name ) ;
2026-08-26 00:37:52 +02:00
/**
* Get the path where a logical snapshot is accessible .
*
* @ param fss Snapshot context
* @ param name Logical snapshot name
* @ param path Output path
* @ param path_size Size of path
* @ return 0 on success , - 1 on failure
*/
int fssnapshot_path ( const struct fssnapshot_struct * fss , const char * name , char * path , size_t path_size ) ;
2026-10-07 09:09:39 +02:00
/**
2026-06-12 09:21:18 +02:00
* Log file .
*
* This stream if fully buffered .
*
* If no log file is selected , it ' s 0.
*/
extern FILE * stdlog ;
/**
* Exit codes for testing .
*/
extern int exit_success ;
extern int exit_failure ;
extern int exit_sync_needed ;
2026-09-18 23:28:47 +02:00
extern int exit_degraded ;
2026-06-12 09:21:18 +02:00
# undef EXIT_SUCCESS
# undef EXIT_FAILURE
# define EXIT_SUCCESS exit_success
# define EXIT_FAILURE exit_failure
# define EXIT_SYNC_NEEDED exit_sync_needed
2026-09-18 23:28:47 +02:00
# define EXIT_DEGRADED exit_degraded
2026-06-12 09:21:18 +02:00
/**
* Standard SMART attributes .
*/
# define SMART_REALLOCATED_SECTOR_COUNT 5
# define SMART_POWER_ON_HOURS 9
# define SMART_POWER_CYCLE_COUNT 12
# define SMART_UNCORRECTABLE_ERROR_CNT 187
# define SMART_COMMAND_TIMEOUT 188
# define SMART_CURRENT_PENDING_SECTOR 197
# define SMART_OFFLINE_UNCORRECTABLE 198
# define SMART_START_STOP_COUNT 4
# define SMART_POWER_ON_HOURS 9
# define SMART_AIRFLOW_TEMPERATURE_CELSIUS 190
# define SMART_LOAD_CYCLE_COUNT 193
# define SMART_TEMPERATURE_CELSIUS 194
/**
* Flags returned by smartctl via exit code
*/
# define SMART_FLAGS 256
2026-10-07 09:09:39 +02:00
/**
2026-06-12 09:21:18 +02:00
* Counts command , transport , or controller - level errors reported by the device .
* These reflect failed I / O operations not directly caused by media defects
* ( for example interface , firmware , or power - related errors ) .
* This counter is cumulative and never resets to zero , even if the underlying
* error condition is resolved .
*/
# define SMART_ERROR_PROTOCOL 257
2026-10-07 09:09:39 +02:00
/**
2026-06-12 09:21:18 +02:00
* Counts media - level errors where data could not be reliably read or written .
* These indicate actual storage surface or flash failures and may imply data loss .
* This counter is cumulative and never resets to zero , even if the underlying
* error condition is resolved .
*/
# define SMART_ERROR_MEDIUM 258
/**
* Unified Wear Level Metric ( 0 - 100 )
*
* Represents the remaining life of an SSD .
* - 0 : Brand new drive ( 0 % wear ) .
* - 100 : Drive has reached or exceeded its manufacturer - rated design life .
*/
# define SMART_WEAR_LEVEL 259
/**
* SMART attributes count .
*/
# define SMART_COUNT 260
/**
* NVME custom SMART attributes
*
* The numbers are just arbitrary to put them in unused space
*/
# define SMART_NVME_CRITICAL_WARNING 100
# define SMART_NVME_AVAILABLE_SPARE 101
# define SMART_NVME_DATA_UNITS_READ 102
# define SMART_NVME_DATA_UNITS_WRITTEN 103
# define SMART_NVME_HOST_READ_COMMANDS 104
# define SMART_NVME_HOST_WRITE_COMMANDS 105
# define SMART_NVME_CONTROLLER_BUSY_TIME 106
# define SMART_NVME_UNSAFE_SHUTDOWNS 107
# define SMART_NVME_WARNING_COMP_TEMPERATURE_TIME 108
# define SMART_NVME_CRITICAL_COMP_TEMPERATURE_TIME 109
/**
* Info attributes .
*/
# define INFO_SIZE 0 /**< Size in bytes. */
# define INFO_ROTATION_RATE 1 /**< Rotation speed. 0 for SSD. */
/**
* Info attributes count .
*/
# define INFO_COUNT 2
/**
* Max number of ignored smart attributes
*/
# define SMART_IGNORE_MAX 4
/**
* Flags returned by smartctl .
*/
# define SMARTCTL_FLAG_UNSUPPORTED (1 << 0) /**< Device not recognized, requiring the -d option. */
# define SMARTCTL_FLAG_OPEN (1 << 1) /**< Device open or identification failed. */
# define SMARTCTL_FLAG_COMMAND (1 << 2) /**< Some SMART or ATA commands failed. This is a common error, also happening with full info gathering. */
# define SMARTCTL_FLAG_FAIL (1 << 3) /**< SMART status check returned "DISK FAILING". */
# define SMARTCTL_FLAG_PREFAIL (1 << 4) /**< We found prefail Attributes <= threshold. */
# define SMARTCTL_FLAG_PREFAIL_LOGGED (1 << 5) /**< SMART status check returned "DISK OK" but we found that some (usage or prefail) Attributes have been <= threshold at some time in the past. */
# define SMARTCTL_FLAG_ERROR_LOGGED (1 << 6) /**< The device error log contains records of errors. */
# define SMARTCTL_FLAG_SELFERROR_LOGGED (1 << 7) /**< The device self-test log contains records of errors. */
/**
2026-06-25 22:36:47 +02:00
* SMART max attribute name or value length .
2026-06-12 09:21:18 +02:00
*/
2026-06-15 14:41:03 +02:00
# define SMART_MAX 128
2026-06-12 09:21:18 +02:00
2026-09-14 15:40:54 +02:00
/**
* Max smartctl custom option length .
*/
# define SMARTCTL_MAX 512
2026-06-25 22:52:53 +02:00
/**
* Smart ignore structure .
*/
struct smartignore_struct {
int attr_index ; /**< 0 if not set */
char attr_name [ SMART_MAX ] ; /**< Empty if not set */
} ;
2026-06-12 09:21:18 +02:00
/**
* Value for unassigned SMART attribute .
*/
# define SMART_UNASSIGNED 0xFFFFFFFFFFFFFFFFULL
/**
* SMART Attribute flags
*/
# define SMART_ATTR_TYPE_PREFAIL 1
# define SMART_ATTR_TYPE_OLDAGE 2
# define SMART_ATTR_UPDATE_ALWAYS 4
# define SMART_ATTR_UPDATE_OFFLINE 8
# define SMART_ATTR_WHEN_FAILED_NOW 16
# define SMART_ATTR_WHEN_FAILED_PAST 32
# define SMART_ATTR_WHEN_FAILED_NEVER 64
struct smart_attr {
2026-06-25 22:36:47 +02:00
char name [ SMART_MAX ] ; /**< SMART attribute name. */
2026-06-12 09:21:18 +02:00
uint64_t raw ; /**< SMART attributes raw. It can be SMART_UNASSIGNED. */
uint64_t norm ; /**< SMART attributes normalized. It can be SMART_UNASSIGNED even if raw is not. */
uint64_t worst ; /**< SMART attributes worst. It can be SMART_UNASSIGNED even if raw/norm is not. */
uint64_t thresh ; /**< SMART attributes threshold. It can be SMART_UNASSIGNED even if raw/norm/worst is not. */
int flags ; /**< SMART_ATTR_* flags */
} ;
/**
* Power mode
*/
# define POWER_STANDBY 0
# define POWER_ACTIVE 1
# define POWER_UNKNOWN -1
struct devinfo_struct {
uint64_t device ; /**< Device ID. */
char name [ PATH_MAX ] ; /**< Name of the disk combined with the split index if any */
char mount [ PATH_MAX ] ; /**< Mount point or other contained directory. */
2026-09-14 15:40:54 +02:00
char smartctl [ SMARTCTL_MAX ] ; /**< Custom option for smartctl. Empty means auto. */
2026-10-07 09:09:39 +02:00
char smartctl_info [ SMARTCTL_MAX ] ; /**< Info options for smartctl. Empty means -a. */
2026-06-25 22:52:53 +02:00
struct smartignore_struct smartignore [ SMART_IGNORE_MAX ] ; /**< Attributes to ignore */
2026-06-12 09:21:18 +02:00
char file [ PATH_MAX ] ; /**< File device. */
# ifdef _WIN32
char wfile [ PATH_MAX ] ; /**< File device in Windows format. Like \\.\PhysicalDriveX, or \\?\Volume{X}. */
# endif
struct devinfo_struct * parent ; /**< Pointer at the parent if any. */
2026-08-17 11:10:49 +02:00
int is_array ; /**< 1 if this is an array disk (data or parity), 0 if extra disk. */
2026-06-12 09:21:18 +02:00
struct devinfo_struct * split ; /**< Pointer at first split if this one is not the first. */
struct smart_attr smart [ SMART_COUNT ] ; /**< All smart values. */
uint64_t info [ INFO_COUNT ] ; /**< Informational attributes not related to SMART telemetry. */
uint64_t access_stat ; /**< Access stat info. */
char serial [ SMART_MAX ] ; /**< Serial number. */
char family [ SMART_MAX ] ; /**< Family. */
char model [ SMART_MAX ] ; /**< Model. */
char interf [ SMART_MAX ] ; /**< Interface of the device: ata, sata, pata, nvme, usb */
int power ; /**< POWER mode. */
# if HAVE_THREAD
thread_id_t thread ;
# endif
tommy_node node ;
} ;
typedef struct devinfo_struct devinfo_t ;
void device_name_set ( devinfo_t * dev , const char * name , int index ) ;
# define DEVICE_LIST 0
# define DEVICE_DOWN 1
# define DEVICE_UP 2
# define DEVICE_SMART 3
# define DEVICE_PROBE 4
# define DEVICE_DOWNIFUP 5
/**
2026-08-17 11:10:49 +02:00
* Sync filesystems associated with the " high " level devices .
2026-09-28 14:21:33 +02:00
* Return 0 on success , - 1 on error .
2026-08-17 11:10:49 +02:00
*/
2026-09-28 14:21:33 +02:00
int devsync ( tommy_list * high ) ;
2026-08-17 11:10:49 +02:00
/**
* Query all the " high " level devices and produce a list of " low " level devices .
2026-06-12 09:21:18 +02:00
*
* The passed " low " device list must be already initialized .
*/
2026-08-17 11:10:49 +02:00
int devquery ( tommy_list * high , tommy_list * low ) ;
/**
* Execute an operation on the " low " level devices .
*/
int devrun ( tommy_list * low , int operation ) ;
2026-06-12 09:21:18 +02:00
/**
* Fill with fake data the device list .
*/
int devtest ( tommy_list * high , tommy_list * low , int operation ) ;
/**
* Query all the " low " devices and log their unique identifiers
*/
int devmap ( void ) ;
/**
* Get the ambient temperature in degree
*
* Return 0 if not available .
*/
int ambient_temperature ( void ) ;
/**
* Size of the spaceholder file for Windows to avoid the message of low disk space
*/
# define WINDOWS_SPACEHOLDER_SIZE (256 * 1024 * 1024)
/****************************************************************************/
/* app */
/**
* Initializes the application .
*/
void app_init ( void ) ;
/**
* Deinitializes the application .
*/
void app_done ( void ) ;
/**
* Default paths .
*/
void app_default_conf ( char * dst , size_t dst_size , const char * argv0 ) ;
/**
* Signal handler .
*/
void app_signal_handler ( int signum ) ;
2026-08-27 17:23:49 +02:00
/****************************************************************************/
/* machine */
# define MACHINEINFO_MAX 256
/**
* Host machine and CPU information .
*/
struct machineinfo_struct {
char cpu_brand [ MACHINEINFO_MAX ] ; /**< CPU model brand name. */
char cpu_vendor [ MACHINEINFO_MAX ] ; /**< CPU vendor string (e.g. GenuineIntel, AuthenticAMD). */
char cpu_arch [ MACHINEINFO_MAX ] ; /**< CPU architecture string. */
char cpu_clock [ MACHINEINFO_MAX ] ; /**< CPU clock frequency description. */
unsigned cpu_family ; /**< CPU family id. */
unsigned cpu_model ; /**< CPU model id. */
unsigned cpu_stepping ; /**< CPU stepping id. */
unsigned cpu_cores_physical ; /**< Number of physical CPU cores (0 if unavailable). */
unsigned cpu_cores_logical ; /**< Number of logical CPU threads (0 if unavailable). */
uint64_t cache_l1_data ; /**< L1 data cache in bytes (0 if unavailable). */
uint64_t cache_l1_instruction ; /**< L1 instruction cache in bytes (0 if unavailable). */
uint64_t cache_l2 ; /**< L2 cache in bytes (0 if unavailable). */
uint64_t cache_l3 ; /**< L3 cache in bytes (0 if unavailable). */
uint64_t memory_total_bytes ; /**< Total system RAM in bytes (0 if unavailable). */
uint32_t memory_page_size ; /**< Page size in bytes (0 if unavailable). */
char os_name [ MACHINEINFO_MAX ] ; /**< Operating system name and kernel version. */
char os_distribution [ MACHINEINFO_MAX ] ; /**< Operating system distribution name. */
char system_model [ MACHINEINFO_MAX ] ; /**< Motherboard or system model name. */
char hypervisor [ MACHINEINFO_MAX ] ; /**< Hypervisor name (empty if bare metal). */
} ;
/**
* Query host machine information .
*/
void machineinfo ( struct machineinfo_struct * info ) ;
2026-06-12 09:21:18 +02:00
# endif