2026-04-02 16:00:27 +02:00
// SPDX-License-Identifier: GPL-3.0-or-later
2026-04-02 16:25:49 +02:00
// Copyright (C) 2011 Andrea Mazzoleni
2011-03-01 22:21:30 +01:00
# ifndef __PORTABLE_H
# define __PORTABLE_H
# if HAVE_CONFIG_H
# include "config.h" /* Use " to include first in the same directory of this file */
# endif
/***************************************************************************/
/* Config */
2015-02-16 19:22:59 +01:00
# ifdef __MINGW32__
/**
* Enable the GNU printf functions instead of using the MSVCRT ones .
*
* Note that this is the default if _POSIX is also defined .
* To disable it you have to set it to 0.
*/
# define __USE_MINGW_ANSI_STDIO 1
2016-04-01 22:12:47 +02:00
/**
2026-04-30 12:00:04 +02:00
* Define the MSVCRT version targeting Windows 7.
2015-02-16 19:22:59 +01:00
*/
2026-04-30 12:00:04 +02:00
# define __MSVCRT_VERSION__ 0x0601
2015-02-16 19:22:59 +01:00
/**
2026-04-30 12:00:04 +02:00
* Include Windows 7 headers .
2015-02-16 19:22:59 +01:00
*
2016-02-12 19:12:38 +01:00
* Like for InitializeCriticalSection ( ) .
2015-02-16 19:22:59 +01:00
*/
2026-04-30 12:00:04 +02:00
# define _WIN32_WINNT 0x601
2015-02-16 19:22:59 +01:00
2026-03-02 01:13:19 +01:00
/**
* Undef as it clashes with windows . h declarations
*/
# undef DATADIR
2011-03-12 10:09:59 +01:00
# include <windows.h>
2011-03-01 22:21:30 +01:00
# endif
2015-02-16 18:42:52 +01:00
/**
* Specify the format attribute for printf .
*/
# ifdef __MINGW32__
2015-02-16 19:22:59 +01:00
# if defined(__USE_MINGW_ANSI_STDIO) && __USE_MINGW_ANSI_STDIO == 1
2015-02-16 18:42:52 +01:00
# define attribute_printf gnu_printf /* GNU format */
2026-05-03 22:29:11 +02:00
# define printf __mingw_printf
2015-02-16 18:42:52 +01:00
# else
# define attribute_printf ms_printf /* MSVCRT format */
# endif
# else
# define attribute_printf printf /* GNU format is the default one */
# endif
2014-01-26 10:16:59 +01:00
/**
* Compiler extension
*/
# ifndef __always_inline
# define __always_inline inline __attribute__((always_inline))
# endif
2015-12-02 23:21:33 +01:00
# ifndef __noreturn
# define __noreturn __attribute__((noreturn))
# endif
2013-12-30 21:12:29 +01:00
/**
2016-01-08 22:43:04 +01:00
* Architecture for inline assembly .
2013-12-30 21:12:29 +01:00
*/
2016-01-08 22:43:04 +01:00
# if HAVE_ASSEMBLY
2013-12-30 21:12:29 +01:00
# if defined(__i386__)
# define CONFIG_X86 1
# define CONFIG_X86_32 1
# endif
# if defined(__x86_64__)
# define CONFIG_X86 1
# define CONFIG_X86_64 1
# endif
2016-01-08 22:43:04 +01:00
# endif
2013-12-30 21:12:29 +01:00
2013-08-29 00:23:14 +02:00
/**
* Includes some platform specific headers .
*/
# if HAVE_SYS_PARAM_H
# include <sys/param.h>
# endif
# if HAVE_SYS_MOUNT_H
# include <sys/mount.h>
# endif
# if HAVE_SYS_VFS_H
# include <sys/vfs.h>
# endif
# if HAVE_SYS_STATFS_H
# include <sys/statfs.h>
# endif
# if HAVE_SYS_FILE_H
# include <sys/file.h>
# endif
# if HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
# endif
# if HAVE_LINUX_FS_H
# include <linux/fs.h>
# endif
2026-04-21 15:19:25 +02:00
# if HAVE_LINUX_BTRFS_H
# include <linux/btrfs.h>
# endif
2013-08-29 00:23:14 +02:00
# if HAVE_LINUX_FIEMAP_H
# include <linux/fiemap.h>
# endif
2015-12-10 22:50:20 +01:00
# if HAVE_BLKID_BLKID_H
# include <blkid/blkid.h>
# if HAVE_BLKID_DEVNO_TO_DEVNAME && HAVE_BLKID_GET_TAG_VALUE
# define HAVE_BLKID 1
# endif
# endif
2013-08-29 00:23:14 +02:00
/**
* Includes some standard headers .
*/
2011-03-01 22:21:30 +01:00
# include <stdio.h>
# include <stdlib.h> /* On many systems (e.g., Darwin), `stdio.h' is a prerequisite. */
# include <stdarg.h>
# include <string.h>
# include <ctype.h>
# include <fcntl.h>
# include <assert.h>
# include <errno.h>
# include <signal.h>
2011-03-12 10:09:59 +01:00
# include <limits.h>
2011-03-01 22:21:30 +01:00
# if HAVE_STDINT_H
# include <stdint.h>
# endif
2011-04-29 22:37:40 +02:00
# if HAVE_INTTYPES_H
# include <inttypes.h>
# endif
2011-03-01 22:21:30 +01:00
# if HAVE_UNISTD_H
# include <unistd.h>
# endif
# if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
# else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
# endif
2014-07-11 18:39:45 +02:00
# if HAVE_MACH_MACH_TIME_H
# include <mach/mach_time.h>
# endif
2011-03-01 22:21:30 +01:00
# if HAVE_DIRENT_H
# include <dirent.h>
# define NAMLEN(dirent) strlen((dirent)->d_name)
# else
# define dirent direct
# define NAMLEN(dirent) (dirent)->d_namlen
# if HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif
# if HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif
# if HAVE_NDIR_H
# include <ndir.h>
# endif
# endif
# if HAVE_SYS_TYPES_H
# include <sys/types.h>
# endif
2018-11-12 21:20:02 +01:00
# if HAVE_SYS_MKDEV
2017-01-04 00:25:56 +01:00
# include <sys/mkdev.h>
2018-11-12 21:20:02 +01:00
# endif
# if HAVE_SYS_SYSMACROS_H
2017-01-04 00:25:56 +01:00
# include <sys/sysmacros.h>
# endif
2011-03-01 22:21:30 +01:00
# if HAVE_SYS_STAT_H
# include <sys/stat.h>
# endif
2015-01-02 23:00:19 +01:00
# if HAVE_SYS_WAIT_H
# include <sys/wait.h>
# endif
2011-03-01 22:21:30 +01:00
# if HAVE_GETOPT_H
# include <getopt.h>
# endif
2015-01-17 23:36:44 +01:00
# if HAVE_MATH_H
# include <math.h>
# endif
2015-12-02 23:21:33 +01:00
# if HAVE_EXECINFO_H
# include <execinfo.h>
# endif
2025-02-03 17:41:54 -06:00
# ifdef __APPLE__
# include <CoreFoundation/CoreFoundation.h>
# include <DiskArbitration/DiskArbitration.h>
2026-03-30 10:07:11 +02:00
# include <mach-o/dyld.h>
2025-02-03 17:41:54 -06:00
# endif
2011-03-20 13:54:05 +01:00
# if HAVE_IO_H
# include <io.h>
2011-03-16 23:52:10 +01:00
# endif
2011-03-01 22:21:30 +01:00
# if HAVE_GETOPT_LONG
2014-09-27 00:32:39 +02:00
# define SWITCH_GETOPT_LONG(a, b) a
2011-03-01 22:21:30 +01:00
# else
2014-09-27 00:32:39 +02:00
# define SWITCH_GETOPT_LONG(a, b) b
2011-03-01 22:21:30 +01:00
# endif
2013-06-17 23:50:26 +02:00
/**
2013-08-29 00:23:14 +02:00
* Enables lock file support .
2013-06-17 23:50:26 +02:00
*/
2026-07-29 16:09:48 +02:00
# if (HAVE_FLOCK && HAVE_FTRUNCATE) || defined(_WIN32)
2013-06-18 21:06:31 +02:00
# define HAVE_LOCKFILE 1
2013-06-17 23:50:26 +02:00
# endif
2026-05-18 09:31:53 +02:00
# ifdef HAVE_LINUX_CLOSE_RANGE_H
# include <linux/close_range.h>
# endif
/* implement close_range for glibc 2.33 or earlier */
# if defined(__linux__) && !defined(HAVE_CLOSE_RANGE)
# include <sys/syscall.h>
# ifndef __NR_close_range
# define __NR_close_range 436
# endif
# define close_range close_range_impl
static inline int close_range_impl ( unsigned int first , unsigned int last , unsigned int flags )
{
return syscall ( __NR_close_range , first , last , flags ) ;
}
# define HAVE_CLOSE_RANGE 1
# endif
2026-05-16 17:14:59 +02:00
/*
* Flags for open ( )
*/
# ifndef O_PATH
# ifdef O_SEARCH
# define O_PATH O_SEARCH /* macOS */
# else
# define O_PATH O_RDONLY /* POSIX */
# endif
# endif
2012-09-19 21:52:15 +02:00
/**
2013-02-27 20:20:49 +01:00
* Includes specific support for Windows or Linux .
2012-09-19 21:52:15 +02:00
*/
2013-02-27 20:20:49 +01:00
# ifdef __MINGW32__
# include "mingw.h"
2012-11-04 00:26:30 +01:00
# else
2013-02-27 20:20:49 +01:00
# include "unix.h"
2012-11-03 23:57:12 +01:00
# endif
2026-03-02 01:13:19 +01:00
/****************************************************************************/
/* os */
2026-05-21 12:21:36 +02:00
/**
* Default paths .
*/
void os_default_conf ( char * dst , size_t dst_size , const char * argv0 ) ;
2026-05-09 17:44:08 +02:00
/**
* Initialize signal handling .
*/
void os_signal_init ( ) ;
/**
* Restore signal handlers after fork in child process .
* This resets signals to default handling .
*/
void os_signal_restore_after_fork ( void ) ;
/**
* Global variable to identify if Ctrl + C is pressed .
*/
int os_global_interrupt ( void ) ;
2026-03-02 01:13:19 +01:00
/**
* Get the os_tick counter value .
*
* Note that the frequency is unspecified , because the time measure
* is meant to be used to compare the ratio between usage times .
*/
uint64_t os_tick ( void ) ;
/**
* Get the os_tick counter value in millisecond .
*/
uint64_t os_tick_ms ( void ) ;
/**
* Initializes the system .
*/
void os_init ( int opt ) ;
/**
* Deinitialize the system .
*/
void os_done ( void ) ;
/**
* Abort the process with a stacktrace .
*/
void os_abort ( void ) __noreturn ;
/**
* Clear the screen .
*/
void os_clear ( void ) ;
2026-05-16 17:14:59 +02:00
/**
* Opaque handle tracking a process execution stream and its process ID .
*
* This structure encapsulates a standard buffered I / O stream tied to the
* redirected standard output of a child process spawned via os_popen ( ) .
*/
# ifdef __MINGW32__
# define OS_FILE FILE
# else
typedef struct OS_FILE {
FILE * fp ; /**< Standard I/O buffered stream wrapper. */
pid_t pid ; /**< Process ID of the child process. */
} OS_FILE ;
# endif
/**
* Spawns a child process and opens a buffered stream to read its stdout .
*
* This function acts as a safer alternative to standard popen ( ) , accepting an
* explicit argument vector rather than evaluating a shell command string .
*
* The child process is completely isolated in its own process group ( via setpgid )
* with its stdin and stderr redirected to / dev / null . The underlying pipe is
* created with O_CLOEXEC set to prevent leakage across concurrent forks .
*
* @ param argv A NULL - terminated array of strings representing the argument vector .
* argv [ 0 ] must contain the absolute path to the verified executable .
* @ param extra_args A mutable string containing additional arguments separated by
* spaces , or NULL if no extra arguments are needed .
* @ return A pointer to an initialized OS_FILE structure on success , or NULL on failure .
* On failure , errno is set appropriately .
*/
OS_FILE * os_popen ( const char * * argv , char * extra_args ) ;
/**
* Reads a line from an OS execution stream .
*
* Reads characters from the specified stream into the buffer string until
* ( size - 1 ) characters are read , a newline character is read and transferred ,
* or an end - of - file ( EOF ) condition is encountered . A terminating null
* character is appended .
*
* @ param s Pointer to an array of chars where the string read is stored .
* @ param size Maximum number of characters to be read ( including the null character ) .
* @ param stream Pointer to the OS_FILE tracking context .
*
* @ return On success , returns the buffer pointer @ p s . If EOF is reached or a read
* error occurs before any characters are read , returns NULL .
*/
char * os_fgets ( char * s , int size , OS_FILE * stream ) ;
/**
* Closes an execution stream and reaps the associated child process .
*
* Closes the underlying buffered standard I / O stream , releases the allocated
* tracking context container , and blocks until the associated child process
* terminates to prevent the creation of zombie processes .
*
* @ param stream Pointer to the active OS_FILE context to close and free .
*
* @ return The termination status of the child process on success , or - 1 on failure .
* On failure , errno is set appropriately .
*/
int os_pclose ( OS_FILE * stream ) ;
2026-03-02 01:13:19 +01:00
/****************************************************************************/
/* app */
2015-01-02 22:51:10 +01:00
/**
* Include list support to have tommy_node .
*/
2015-01-02 15:53:15 +01:00
# include "tommyds/tommylist.h"
2026-03-02 01:13:19 +01:00
/**
* Basic block position type .
* With 32 bits and 128 k blocks you can address 256 TB .
*/
typedef uint32_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 ;
2011-12-08 22:40:30 +01:00
/**
2013-02-27 20:20:49 +01:00
* Another name for link ( ) to avoid confusion with local variables called " link " .
2011-12-08 22:40:30 +01:00
*/
2013-02-27 20:20:49 +01:00
static inline int hardlink ( const char * a , const char * b )
2011-12-08 22:40:30 +01:00
{
2013-02-27 20:20:49 +01:00
return link ( a , b ) ;
2011-12-08 22:40:30 +01:00
}
2012-04-11 22:03:14 +02:00
2013-03-03 22:39:46 +01:00
/**
* Get the device UUID .
2015-10-07 22:07:20 +02:00
* Return 0 on success .
2013-03-03 22:39:46 +01:00
*/
2026-04-23 00:19:03 +02:00
int devuuid ( uint64_t device_id , const char * device_path , char * uuid , size_t size ) ;
2013-03-03 22:39:46 +01:00
2013-09-28 15:33:56 +02:00
/**
2014-10-03 21:28:56 +02:00
* Physical offset not yet read .
2013-09-28 15:33:56 +02:00
*/
2014-10-03 21:28:56 +02:00
# define FILEPHY_UNREAD_OFFSET 0
2013-09-28 15:33:56 +02:00
/**
2016-01-02 16:52:20 +01:00
* Special value returned when the file - system doesn ' t report any offset for unknown reason .
2013-09-28 15:33:56 +02:00
*/
# define FILEPHY_UNREPORTED_OFFSET 1
2014-10-03 21:28:56 +02:00
/**
* Special value returned when the file doesn ' t have a real offset .
* For example , because it ' s stored in the NTFS MFT .
*/
# define FILEPHY_WITHOUT_OFFSET 2
2013-09-28 15:33:56 +02:00
/**
* Value indicating real offsets . All offsets greater or equal at this one are real .
*/
2014-10-03 21:28:56 +02:00
# define FILEPHY_REAL_OFFSET 3
2013-09-28 15:33:56 +02:00
2013-06-25 22:41:10 +02:00
/**
2022-06-21 01:16:00 +02:00
* Get the physical address of the specified file .
2016-01-02 16:52:20 +01:00
* This is expected to be just a hint and not necessarily correct or unique .
2015-10-07 22:07:20 +02:00
* Return 0 on success .
2013-06-25 22:41:10 +02:00
*/
2014-10-03 21:28:56 +02:00
int filephy ( const char * path , uint64_t size , uint64_t * physical ) ;
2013-06-25 22:41:10 +02:00
2013-08-25 22:39:58 +02:00
/**
2016-01-02 16:52:20 +01:00
* Check if the underline file - system support persistent inodes .
2015-10-07 22:07:20 +02:00
* Return - 1 on error , 0 on success .
2013-08-25 22:39:58 +02:00
*/
2026-01-29 18:43:00 +01:00
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 ) ;
2013-08-25 22:39:58 +02:00
2026-05-07 17:23:48 +02:00
/**
* Where snapshot are accessible
*/
# define SNAPSHOT_CONTAINER ".snapraid"
/**
* Snapshots names
*/
# define SNAPSHOT_PENDING "pending"
# define SNAPSHOT_STABLE "stable"
2026-05-11 23:24:36 +02:00
/*
2026-05-04 10:59:12 +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 /
* - Btrfs / Bcachefs : subvolume root
* - ZFS : dataset mountpoint
*/
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 / )
*/
char snapshot_dir [ PATH_MAX ] ;
/*
2026-05-07 17:23:48 +02:00
* Dataset name for ZFS ( e . g . " pool/data " )
* or VolumeName in Windows .
2026-05-04 10:59:12 +02:00
* Empty string for filesystems where not applicable .
*/
char dataset [ PATH_MAX ] ;
} ;
/**
* Initialize snapshot context from an arbitrary path .
*
2026-05-04 11:36:34 +02:00
* @ param dir Full path inside the filesystem ( must end with ' / ' )
2026-05-04 10:59:12 +02:00
* @ param fss Output snapshot context
* @ return 0 on success , - 1 on failure
2026-04-21 15:19:25 +02:00
*/
2026-05-15 09:15:27 +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 ) ;
2026-05-04 11:36:34 +02:00
/**
* 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 ) ;
2026-04-21 15:19:25 +02:00
/**
2026-05-04 10:59:12 +02:00
* Create a snapshot of the filesystem root / dataset .
*
2026-05-04 11:36:34 +02:00
* @ param fss Snapshot context
2026-05-04 10:59:12 +02:00
* @ param name Snapshot name
* @ return 0 on success , - 1 on failure
2026-04-21 15:19:25 +02:00
*/
2026-05-04 10:59:12 +02:00
int fssnapshot_create ( const struct fssnapshot_struct * fss , const char * name ) ;
2026-04-21 15:19:25 +02:00
/**
2026-05-04 10:59:12 +02:00
* Delete a snapshot .
*
* @ param fss Snapshot context
* @ param name Snapshot name
* @ return 0 on success , - 1 on failure
2026-04-21 15:19:25 +02:00
*/
2026-05-04 10:59:12 +02:00
int fssnapshot_delete ( const struct fssnapshot_struct * fss , const char * name ) ;
2026-04-21 15:19:25 +02:00
/**
2026-05-04 10:59:12 +02:00
* Rename a snapshot .
*
2026-05-04 11:36:34 +02:00
* @ param fss Snapshot context
* @ param old_name Existing snapshot name
* @ param new_name New snapshot name
2026-05-04 10:59:12 +02:00
* @ return 0 on success , - 1 on failure
2026-04-21 15:19:25 +02:00
*/
2026-05-04 10:59:12 +02:00
int fssnapshot_rename ( const struct fssnapshot_struct * fss , const char * old_name , const char * new_name ) ;
2026-04-21 15:19:25 +02:00
2026-04-28 00:35:15 +02:00
/*
2015-02-07 16:57:36 +01:00
* Log file .
*
* This stream if fully buffered .
*
* If no log file is selected , it ' s 0.
2013-03-01 20:13:56 +01:00
*/
2020-05-18 15:21:42 +02:00
extern FILE * stdlog ;
2013-03-01 20:13:56 +01:00
2014-03-20 22:10:19 +01:00
/**
* Exit codes for testing .
*/
2020-05-18 15:21:42 +02:00
extern int exit_success ;
extern int exit_failure ;
extern int exit_sync_needed ;
2014-03-20 22:10:19 +01:00
# undef EXIT_SUCCESS
# undef EXIT_FAILURE
# define EXIT_SUCCESS exit_success
# define EXIT_FAILURE exit_failure
2015-04-28 19:15:16 +02:00
# define EXIT_SYNC_NEEDED exit_sync_needed
2014-03-20 22:10:19 +01:00
2015-01-02 18:07:59 +01:00
/**
2016-05-23 22:37:18 +02:00
* Fill memory with pseudo - random values .
2015-01-02 18:07:59 +01:00
*/
int randomize ( void * ptr , size_t size ) ;
2016-10-04 23:55:39 +02:00
/**
* Standard SMART attributes .
*/
# define SMART_REALLOCATED_SECTOR_COUNT 5
2026-02-16 10:47:43 +01:00
# define SMART_POWER_ON_HOURS 9
2026-02-21 17:27:26 +01:00
# define SMART_POWER_CYCLE_COUNT 12
2025-12-21 22:46:21 +01:00
# 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
2016-10-04 23:55:39 +02:00
# define SMART_POWER_ON_HOURS 9
# define SMART_AIRFLOW_TEMPERATURE_CELSIUS 190
2025-12-21 22:46:21 +01:00
# define SMART_LOAD_CYCLE_COUNT 193
2016-10-04 23:55:39 +02:00
# define SMART_TEMPERATURE_CELSIUS 194
2026-02-26 12:53:55 +01:00
/**
* Flags returned by smartctl via exit code
*/
# define SMART_FLAGS 256
2026-01-19 14:33:55 +01: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
/*
* 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
2025-12-18 18:16:02 +01:00
2026-01-19 22:57:53 +01:00
/**
* Unified Wear Level Metric ( 0 - 100 )
*
2026-01-26 09:42:03 +01:00
* Represents the remaining life of an SSD .
2026-01-19 22:57:53 +01:00
* - 0 : Brand new drive ( 0 % wear ) .
* - 100 : Drive has reached or exceeded its manufacturer - rated design life .
*/
# define SMART_WEAR_LEVEL 259
2015-01-02 15:53:15 +01:00
/**
2025-12-18 18:16:02 +01:00
* SMART attributes count .
2015-01-14 22:29:20 +01:00
*/
2026-01-19 22:57:53 +01:00
# define SMART_COUNT 260
2015-01-15 22:47:21 +01:00
2026-02-26 12:53:55 +01:00
/**
* 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
2015-01-15 22:47:21 +01:00
/**
2025-12-18 18:16:02 +01:00
* Info attributes .
2015-01-15 22:47:21 +01:00
*/
2025-12-18 18:16:02 +01:00
# define INFO_SIZE 0 /**< Size in bytes. */
# define INFO_ROTATION_RATE 1 /**< Rotation speed. 0 for SSD. */
/**
* Info attributes count .
*/
# define INFO_COUNT 2
2026-02-26 12:53:55 +01:00
/**
* Max number of ignored smart attributes
*/
# define SMART_IGNORE_MAX 4
2025-09-15 16:56:09 +02:00
2015-01-24 17:55:59 +01:00
/**
* Flags returned by smartctl .
*/
2015-01-29 22:52:17 +01:00
# define SMARTCTL_FLAG_UNSUPPORTED (1 << 0) /**< Device not recognized, requiring the -d option. */
2015-04-07 21:59:09 +02:00
# 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. */
2015-01-24 17:55:59 +01:00
# 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. */
2026-01-21 14:47:26 +01:00
# 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. */
2015-01-14 22:29:20 +01:00
/**
* SMART max attribute length .
*/
# define SMART_MAX 64
/**
* Value for unassigned SMART attribute .
*/
# define SMART_UNASSIGNED 0xFFFFFFFFFFFFFFFFULL
2025-09-23 22:38:13 +02:00
/**
2026-02-16 15:43:25 +01:00
* SMART Attribute flags
2025-09-23 22:38:13 +02:00
*/
2026-02-16 15:43:25 +01:00
# 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
2025-09-23 22:38:13 +02:00
2026-02-16 15:43:25 +01:00
struct smart_attr {
2026-02-16 10:47:43 +01:00
char name [ 128 ] ; /**< SMART attribute name. */
2026-05-14 15:23:34 +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. */
2026-02-16 15:43:25 +01:00
int flags ; /**< SMART_ATTR_* flags */
2026-02-16 10:47:43 +01:00
} ;
2026-02-16 15:43:25 +01:00
/**
* Power mode
*/
# define POWER_STANDBY 0
# define POWER_ACTIVE 1
# define POWER_UNKNOWN -1
2015-01-14 22:29:20 +01:00
/**
* Device info entry .
2015-01-02 15:53:15 +01:00
*/
2015-01-11 17:43:31 +01:00
struct devinfo_struct {
2015-01-02 15:53:15 +01:00
uint64_t device ; /**< Device ID. */
2025-12-21 15:55:52 +01:00
char name [ PATH_MAX ] ; /**< Name of the disk combined with the split index if any */
2015-01-11 17:43:31 +01:00
char mount [ PATH_MAX ] ; /**< Mount point or other contained directory. */
2015-04-08 22:56:44 +02:00
char smartctl [ PATH_MAX ] ; /**< Options for smartctl. */
2025-09-15 16:56:09 +02:00
int smartignore [ SMART_IGNORE_MAX ] ; /**< Attribues to ignore */
2015-01-11 17:43:31 +01:00
char file [ PATH_MAX ] ; /**< File device. */
2015-02-17 22:27:11 +01:00
# ifdef _WIN32
char wfile [ PATH_MAX ] ; /**< File device in Windows format. Like \\.\PhysicalDriveX, or \\?\Volume{X}. */
# endif
2015-01-14 22:29:20 +01:00
struct devinfo_struct * parent ; /**< Pointer at the parent if any. */
2026-03-03 12:41:16 +01:00
struct devinfo_struct * split ; /**< Pointer at first split if this one is not the first. */
2026-02-16 15:43:25 +01:00
struct smart_attr smart [ SMART_COUNT ] ; /**< All smart values. */
2026-02-26 12:53:55 +01:00
uint64_t info [ INFO_COUNT ] ; /**< Informational attributes not related to SMART telemetry. */
2025-12-26 11:12:22 +01:00
uint64_t access_stat ; /**< Access stat info. */
2025-12-18 18:16:02 +01:00
char serial [ SMART_MAX ] ; /**< Serial number. */
2025-12-21 22:46:21 +01:00
char family [ SMART_MAX ] ; /**< Family. */
2025-12-18 18:16:02 +01:00
char model [ SMART_MAX ] ; /**< Model. */
2026-01-29 16:47:02 +01:00
char interf [ SMART_MAX ] ; /**< Interface of the device: ata, sata, pata, nvme, usb */
2025-09-23 22:38:13 +02:00
int power ; /**< POWER mode. */
2021-05-25 22:08:12 +02:00
# if HAVE_THREAD
thread_id_t thread ;
2015-01-02 15:53:15 +01:00
# endif
tommy_node node ;
} ;
2015-01-11 17:43:31 +01:00
typedef struct devinfo_struct devinfo_t ;
2015-01-02 15:53:15 +01:00
2025-12-21 15:55:52 +01:00
void device_name_set ( devinfo_t * dev , const char * name , int index ) ;
2015-01-14 22:29:20 +01:00
# define DEVICE_LIST 0
# define DEVICE_DOWN 1
# define DEVICE_UP 2
# define DEVICE_SMART 3
2025-09-23 22:38:13 +02:00
# define DEVICE_PROBE 4
2025-10-26 11:24:14 +01:00
# define DEVICE_DOWNIFUP 5
2015-01-02 15:53:15 +01:00
/**
2015-01-14 22:29:20 +01:00
* Query all the " high " level devices with the specified operation ,
* and produces a list of " low " level devices to operate on .
*
2015-01-16 18:52:31 +01:00
* The passed " low " device list must be already initialized .
2015-01-02 15:53:15 +01:00
*/
2026-03-11 13:53:42 +01:00
int devquery ( tommy_list * high , tommy_list * low , int operation ) ;
2015-01-02 15:53:15 +01:00
2025-10-28 00:05:49 +01:00
/**
* Fill with fake data the device list .
*/
int devtest ( tommy_list * high , tommy_list * low , int operation ) ;
2026-03-16 12:00:53 +01:00
/**
* Query all the " low " devices and log their unique identifiers
*/
int devmap ( void ) ;
2025-09-21 19:54:10 +02:00
/**
* Get the ambient temperature in degree
*
* Return 0 if not available .
*/
int ambient_temperature ( void ) ;
2026-01-30 09:54:54 +01:00
/**
* Size of the spaceholder file for Windows to avoid the message of low disk space
*/
# define WINDOWS_SPACEHOLDER_SIZE (256 * 1024 * 1024)
2026-02-01 20:21:28 +01:00
/**
* Generic errors
*/
# define EINTERNAL EFAULT /**< Internal assertion failed. */
# define EDATA EIO /**< Silent data corruption. */
# 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. */
2011-03-01 22:21:30 +01:00
# endif