Line data Source code
1 : // SPDX-License-Identifier: GPL-3.0-or-later
2 : // Copyright (C) 2011 Andrea Mazzoleni
3 :
4 : #ifndef __PORTABLE_H
5 : #define __PORTABLE_H
6 :
7 : #if HAVE_CONFIG_H
8 : #include "config.h" /* Use " to include first in the same directory of this file */
9 : #endif
10 :
11 : /***************************************************************************/
12 : /* Config */
13 :
14 : #ifdef __MINGW32__
15 : /**
16 : * Enable the GNU printf functions instead of using the MSVCRT ones.
17 : *
18 : * Note that this is the default if _POSIX is also defined.
19 : * To disable it you have to set it to 0.
20 : */
21 : #define __USE_MINGW_ANSI_STDIO 1
22 :
23 : /**
24 : * Define the MSVCRT version targeting Windows Vista.
25 : */
26 : #define __MSVCRT_VERSION__ 0x0600
27 :
28 : /**
29 : * Include Windows Vista headers.
30 : *
31 : * Like for InitializeCriticalSection().
32 : */
33 : #define _WIN32_WINNT 0x600
34 :
35 : /**
36 : * Undef as it clashes with windows.h declarations
37 : */
38 : #undef DATADIR
39 :
40 : #include <windows.h>
41 : #endif
42 :
43 : /**
44 : * Specify the format attribute for printf.
45 : */
46 : #ifdef __MINGW32__
47 : #if defined(__USE_MINGW_ANSI_STDIO) && __USE_MINGW_ANSI_STDIO == 1
48 : #define attribute_printf gnu_printf /* GNU format */
49 : #else
50 : #define attribute_printf ms_printf /* MSVCRT format */
51 : #endif
52 : #else
53 : #define attribute_printf printf /* GNU format is the default one */
54 : #endif
55 :
56 : /**
57 : * Compiler extension
58 : */
59 : #ifndef __always_inline
60 : #define __always_inline inline __attribute__((always_inline))
61 : #endif
62 :
63 : #ifndef __noreturn
64 : #define __noreturn __attribute__((noreturn))
65 : #endif
66 :
67 :
68 : /**
69 : * Architecture for inline assembly.
70 : */
71 : #if HAVE_ASSEMBLY
72 : #if defined(__i386__)
73 : #define CONFIG_X86 1
74 : #define CONFIG_X86_32 1
75 : #endif
76 :
77 : #if defined(__x86_64__)
78 : #define CONFIG_X86 1
79 : #define CONFIG_X86_64 1
80 : #endif
81 : #endif
82 :
83 : /**
84 : * Includes some platform specific headers.
85 : */
86 : #if HAVE_SYS_PARAM_H
87 : #include <sys/param.h>
88 : #endif
89 :
90 : #if HAVE_SYS_MOUNT_H
91 : #include <sys/mount.h>
92 : #endif
93 :
94 : #if HAVE_SYS_VFS_H
95 : #include <sys/vfs.h>
96 : #endif
97 :
98 : #if HAVE_SYS_STATFS_H
99 : #include <sys/statfs.h>
100 : #endif
101 :
102 : #if HAVE_SYS_FILE_H
103 : #include <sys/file.h>
104 : #endif
105 :
106 : #if HAVE_SYS_IOCTL_H
107 : #include <sys/ioctl.h>
108 : #endif
109 :
110 : #if HAVE_LINUX_FS_H
111 : #include <linux/fs.h>
112 : #endif
113 :
114 : #if HAVE_LINUX_BTRFS_H
115 : #include <linux/btrfs.h>
116 : #endif
117 :
118 : #if HAVE_LINUX_FIEMAP_H
119 : #include <linux/fiemap.h>
120 : #endif
121 :
122 : #if HAVE_BLKID_BLKID_H
123 : #include <blkid/blkid.h>
124 : #if HAVE_BLKID_DEVNO_TO_DEVNAME && HAVE_BLKID_GET_TAG_VALUE
125 : #define HAVE_BLKID 1
126 : #endif
127 : #endif
128 :
129 : /**
130 : * Includes some standard headers.
131 : */
132 : #include <stdio.h>
133 : #include <stdlib.h> /* On many systems (e.g., Darwin), `stdio.h' is a prerequisite. */
134 : #include <stdarg.h>
135 : #include <string.h>
136 : #include <ctype.h>
137 : #include <fcntl.h>
138 : #include <assert.h>
139 : #include <errno.h>
140 : #include <signal.h>
141 : #include <limits.h>
142 :
143 : #if HAVE_STDINT_H
144 : #include <stdint.h>
145 : #endif
146 :
147 : #if HAVE_INTTYPES_H
148 : #include <inttypes.h>
149 : #endif
150 :
151 : #if HAVE_UNISTD_H
152 : #include <unistd.h>
153 : #endif
154 :
155 : #if TIME_WITH_SYS_TIME
156 : #include <sys/time.h>
157 : #include <time.h>
158 : #else
159 : #if HAVE_SYS_TIME_H
160 : #include <sys/time.h>
161 : #else
162 : #include <time.h>
163 : #endif
164 : #endif
165 :
166 : #if HAVE_MACH_MACH_TIME_H
167 : #include <mach/mach_time.h>
168 : #endif
169 :
170 : #if HAVE_DIRENT_H
171 : #include <dirent.h>
172 : #define NAMLEN(dirent) strlen((dirent)->d_name)
173 : #else
174 : #define dirent direct
175 : #define NAMLEN(dirent) (dirent)->d_namlen
176 : #if HAVE_SYS_NDIR_H
177 : #include <sys/ndir.h>
178 : #endif
179 : #if HAVE_SYS_DIR_H
180 : #include <sys/dir.h>
181 : #endif
182 : #if HAVE_NDIR_H
183 : #include <ndir.h>
184 : #endif
185 : #endif
186 :
187 : #if HAVE_SYS_TYPES_H
188 : #include <sys/types.h>
189 : #endif
190 :
191 : #if HAVE_SYS_MKDEV
192 : #include <sys/mkdev.h>
193 : #endif
194 :
195 : #if HAVE_SYS_SYSMACROS_H
196 : #include <sys/sysmacros.h>
197 : #endif
198 :
199 : #if HAVE_SYS_STAT_H
200 : #include <sys/stat.h>
201 : #endif
202 :
203 : #if HAVE_SYS_WAIT_H
204 : #include <sys/wait.h>
205 : #endif
206 :
207 : #if HAVE_GETOPT_H
208 : #include <getopt.h>
209 : #endif
210 :
211 : #if HAVE_MATH_H
212 : #include <math.h>
213 : #endif
214 :
215 : #if HAVE_EXECINFO_H
216 : #include <execinfo.h>
217 : #endif
218 :
219 : #ifdef __APPLE__
220 : #include <CoreFoundation/CoreFoundation.h>
221 : #include <DiskArbitration/DiskArbitration.h>
222 : #include <mach-o/dyld.h>
223 : #endif
224 :
225 : #if HAVE_IO_H
226 : #include <io.h>
227 : #endif
228 :
229 : #if HAVE_GETOPT_LONG
230 : #define SWITCH_GETOPT_LONG(a, b) a
231 : #else
232 : #define SWITCH_GETOPT_LONG(a, b) b
233 : #endif
234 :
235 : /**
236 : * Enables lock file support.
237 : */
238 : #if HAVE_FLOCK && HAVE_FTRUNCATE
239 : #define HAVE_LOCKFILE 1
240 : #endif
241 :
242 : /**
243 : * Includes specific support for Windows or Linux.
244 : */
245 : #ifdef __MINGW32__
246 : #include "mingw.h"
247 : #else
248 : #include "unix.h"
249 : #endif
250 :
251 : /****************************************************************************/
252 : /* os */
253 :
254 : /**
255 : * Get the os_tick counter value.
256 : *
257 : * Note that the frequency is unspecified, because the time measure
258 : * is meant to be used to compare the ratio between usage times.
259 : */
260 : uint64_t os_tick(void);
261 :
262 : /**
263 : * Get the os_tick counter value in millisecond.
264 : */
265 : uint64_t os_tick_ms(void);
266 :
267 : /**
268 : * Initializes the system.
269 : */
270 : void os_init(int opt);
271 :
272 : /**
273 : * Deinitialize the system.
274 : */
275 : void os_done(void);
276 :
277 : /**
278 : * Abort the process with a stacktrace.
279 : */
280 : void os_abort(void) __noreturn;
281 :
282 : /**
283 : * Clear the screen.
284 : */
285 : void os_clear(void);
286 :
287 : /**
288 : * Global variable to identify if Ctrl+C is pressed.
289 : */
290 : extern volatile int global_interrupt;
291 :
292 : /****************************************************************************/
293 : /* app */
294 :
295 : /**
296 : * Include list support to have tommy_node.
297 : */
298 : #include "tommyds/tommylist.h"
299 :
300 : /**
301 : * Basic block position type.
302 : * With 32 bits and 128k blocks you can address 256 TB.
303 : */
304 : typedef uint32_t block_off_t;
305 :
306 : /**
307 : * Basic data position type.
308 : * It's signed as file size and offset are usually signed.
309 : */
310 : typedef int64_t data_off_t;
311 :
312 : /**
313 : * Another name for link() to avoid confusion with local variables called "link".
314 : */
315 12 : static inline int hardlink(const char* a, const char* b)
316 : {
317 12 : return link(a, b);
318 : }
319 :
320 : /**
321 : * Get the device UUID.
322 : * Return 0 on success.
323 : */
324 : int devuuid(uint64_t device_id, const char* device_path, char* uuid, size_t size);
325 :
326 : /**
327 : * Physical offset not yet read.
328 : */
329 : #define FILEPHY_UNREAD_OFFSET 0
330 :
331 : /**
332 : * Special value returned when the file-system doesn't report any offset for unknown reason.
333 : */
334 : #define FILEPHY_UNREPORTED_OFFSET 1
335 :
336 : /**
337 : * Special value returned when the file doesn't have a real offset.
338 : * For example, because it's stored in the NTFS MFT.
339 : */
340 : #define FILEPHY_WITHOUT_OFFSET 2
341 :
342 : /**
343 : * Value indicating real offsets. All offsets greater or equal at this one are real.
344 : */
345 : #define FILEPHY_REAL_OFFSET 3
346 :
347 : /**
348 : * Get the physical address of the specified file.
349 : * This is expected to be just a hint and not necessarily correct or unique.
350 : * Return 0 on success.
351 : */
352 : int filephy(const char* path, uint64_t size, uint64_t* physical);
353 :
354 : /**
355 : * Check if the underline file-system support persistent inodes.
356 : * Return -1 on error, 0 on success.
357 : */
358 : 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);
359 :
360 : /**
361 : * Get the subvolume directory if the underline filesystem support it
362 : * @param path Full path of the mount point to check. It must end with /
363 : * @param root The full path of the subvolume root that contains the specified path. It will end with /.
364 : */
365 : int fssnapshot(const char* path, char* root, size_t root_size);
366 :
367 : /**
368 : * Creates a snapshot of a subvolume.
369 : * @param source Path to the source subvolume.
370 : * @param parent_dir Directory where the snapshot should be created.
371 : * @param name Name of snapshot.
372 : * @return 0 on success, -1 on failure.
373 : */
374 : int fssnapshot_create(const char* source, const char* parent_dir, const char* name);
375 :
376 : /**
377 : * Deletes a subvolume/snapshot.
378 : * @param parent_dir Directory where the snapshot is.
379 : * @param name Name of snapshot.
380 : * @return 0 on success, -1 on failure.
381 : */
382 : int fssnapshot_delete(const char* parent_dir, const char* name);
383 :
384 : /**
385 : * Renames a subvolume.
386 : * @return 0 on success, -1 on failure.
387 : */
388 : int fssnapshot_rename(const char* parent_dir, const char* old_name, const char* new_name);
389 :
390 : /*
391 : * Log file.
392 : *
393 : * This stream if fully buffered.
394 : *
395 : * If no log file is selected, it's 0.
396 : */
397 : extern FILE* stdlog;
398 :
399 : /**
400 : * Exit codes for testing.
401 : */
402 : extern int exit_success;
403 : extern int exit_failure;
404 : extern int exit_sync_needed;
405 : #undef EXIT_SUCCESS
406 : #undef EXIT_FAILURE
407 : #define EXIT_SUCCESS exit_success
408 : #define EXIT_FAILURE exit_failure
409 : #define EXIT_SYNC_NEEDED exit_sync_needed
410 :
411 : /**
412 : * Fill memory with pseudo-random values.
413 : */
414 : int randomize(void* ptr, size_t size);
415 :
416 : /**
417 : * Standard SMART attributes.
418 : */
419 : #define SMART_REALLOCATED_SECTOR_COUNT 5
420 : #define SMART_POWER_ON_HOURS 9
421 : #define SMART_POWER_CYCLE_COUNT 12
422 : #define SMART_UNCORRECTABLE_ERROR_CNT 187
423 : #define SMART_COMMAND_TIMEOUT 188
424 : #define SMART_CURRENT_PENDING_SECTOR 197
425 : #define SMART_OFFLINE_UNCORRECTABLE 198
426 : #define SMART_START_STOP_COUNT 4
427 : #define SMART_POWER_ON_HOURS 9
428 : #define SMART_AIRFLOW_TEMPERATURE_CELSIUS 190
429 : #define SMART_LOAD_CYCLE_COUNT 193
430 : #define SMART_TEMPERATURE_CELSIUS 194
431 :
432 : /**
433 : * Flags returned by smartctl via exit code
434 : */
435 : #define SMART_FLAGS 256
436 :
437 : /*
438 : * Counts command, transport, or controller-level errors reported by the device.
439 : * These reflect failed I/O operations not directly caused by media defects
440 : * (for example interface, firmware, or power-related errors).
441 : * This counter is cumulative and never resets to zero, even if the underlying
442 : * error condition is resolved.
443 : */
444 : #define SMART_ERROR_PROTOCOL 257
445 :
446 : /*
447 : * Counts media-level errors where data could not be reliably read or written.
448 : * These indicate actual storage surface or flash failures and may imply data loss.
449 : * This counter is cumulative and never resets to zero, even if the underlying
450 : * error condition is resolved.
451 : */
452 : #define SMART_ERROR_MEDIUM 258
453 :
454 : /**
455 : * Unified Wear Level Metric (0-100)
456 : *
457 : * Represents the remaining life of an SSD.
458 : * - 0: Brand new drive (0% wear).
459 : * - 100: Drive has reached or exceeded its manufacturer-rated design life.
460 : */
461 : #define SMART_WEAR_LEVEL 259
462 :
463 : /**
464 : * SMART attributes count.
465 : */
466 : #define SMART_COUNT 260
467 :
468 : /**
469 : * NVME custom SMART attributes
470 : *
471 : * The numbers are just arbitrary to put them in unused space
472 : */
473 : #define SMART_NVME_CRITICAL_WARNING 100
474 : #define SMART_NVME_AVAILABLE_SPARE 101
475 : #define SMART_NVME_DATA_UNITS_READ 102
476 : #define SMART_NVME_DATA_UNITS_WRITTEN 103
477 : #define SMART_NVME_HOST_READ_COMMANDS 104
478 : #define SMART_NVME_HOST_WRITE_COMMANDS 105
479 : #define SMART_NVME_CONTROLLER_BUSY_TIME 106
480 : #define SMART_NVME_UNSAFE_SHUTDOWNS 107
481 : #define SMART_NVME_WARNING_COMP_TEMPERATURE_TIME 108
482 : #define SMART_NVME_CRITICAL_COMP_TEMPERATURE_TIME 109
483 :
484 : /**
485 : * Info attributes.
486 : */
487 : #define INFO_SIZE 0 /**< Size in bytes. */
488 : #define INFO_ROTATION_RATE 1 /**< Rotation speed. 0 for SSD. */
489 :
490 : /**
491 : * Info attributes count.
492 : */
493 : #define INFO_COUNT 2
494 :
495 : /**
496 : * Max number of ignored smart attributes
497 : */
498 : #define SMART_IGNORE_MAX 4
499 :
500 : /**
501 : * Flags returned by smartctl.
502 : */
503 : #define SMARTCTL_FLAG_UNSUPPORTED (1 << 0) /**< Device not recognized, requiring the -d option. */
504 : #define SMARTCTL_FLAG_OPEN (1 << 1) /**< Device open or identification failed. */
505 : #define SMARTCTL_FLAG_COMMAND (1 << 2) /**< Some SMART or ATA commands failed. This is a common error, also happening with full info gathering. */
506 : #define SMARTCTL_FLAG_FAIL (1 << 3) /**< SMART status check returned "DISK FAILING". */
507 : #define SMARTCTL_FLAG_PREFAIL (1 << 4) /**< We found prefail Attributes <= threshold. */
508 : #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. */
509 : #define SMARTCTL_FLAG_ERROR_LOGGED (1 << 6) /**< The device error log contains records of errors. */
510 : #define SMARTCTL_FLAG_SELFERROR_LOGGED (1 << 7) /**< The device self-test log contains records of errors. */
511 :
512 : /**
513 : * SMART max attribute length.
514 : */
515 : #define SMART_MAX 64
516 :
517 : /**
518 : * Value for unassigned SMART attribute.
519 : */
520 : #define SMART_UNASSIGNED 0xFFFFFFFFFFFFFFFFULL
521 :
522 : /**
523 : * SMART Attribute flags
524 : */
525 : #define SMART_ATTR_TYPE_PREFAIL 1
526 : #define SMART_ATTR_TYPE_OLDAGE 2
527 : #define SMART_ATTR_UPDATE_ALWAYS 4
528 : #define SMART_ATTR_UPDATE_OFFLINE 8
529 : #define SMART_ATTR_WHEN_FAILED_NOW 16
530 : #define SMART_ATTR_WHEN_FAILED_PAST 32
531 : #define SMART_ATTR_WHEN_FAILED_NEVER 64
532 :
533 : struct smart_attr {
534 : char name[128]; /**< SMART attribute name. */
535 : uint64_t raw; /**< SMART attributes raw. */
536 : uint64_t norm; /**< SMART attributes normalized. */
537 : uint64_t worst; /**< SMART attributes worst. */
538 : uint64_t thresh; /**< SMART attributes threshold. */
539 : int flags; /**< SMART_ATTR_* flags */
540 : };
541 :
542 : /**
543 : * Power mode
544 : */
545 : #define POWER_STANDBY 0
546 : #define POWER_ACTIVE 1
547 : #define POWER_UNKNOWN -1
548 :
549 : /**
550 : * Device info entry.
551 : */
552 : struct devinfo_struct {
553 : uint64_t device; /**< Device ID. */
554 : char name[PATH_MAX]; /**< Name of the disk combined with the split index if any */
555 : char mount[PATH_MAX]; /**< Mount point or other contained directory. */
556 : char smartctl[PATH_MAX]; /**< Options for smartctl. */
557 : int smartignore[SMART_IGNORE_MAX]; /**< Attribues to ignore */
558 : char file[PATH_MAX]; /**< File device. */
559 : #ifdef _WIN32
560 : char wfile[PATH_MAX]; /**< File device in Windows format. Like \\.\PhysicalDriveX, or \\?\Volume{X}. */
561 : #endif
562 : struct devinfo_struct* parent; /**< Pointer at the parent if any. */
563 : struct devinfo_struct* split; /**< Pointer at first split if this one is not the first. */
564 : struct smart_attr smart[SMART_COUNT]; /**< All smart values. */
565 : uint64_t info[INFO_COUNT]; /**< Informational attributes not related to SMART telemetry. */
566 : uint64_t access_stat; /**< Access stat info. */
567 : char serial[SMART_MAX]; /**< Serial number. */
568 : char family[SMART_MAX]; /**< Family. */
569 : char model[SMART_MAX]; /**< Model. */
570 : char interf[SMART_MAX]; /**< Interface of the device: ata, sata, pata, nvme, usb */
571 : int power; /**< POWER mode. */
572 : #if HAVE_THREAD
573 : thread_id_t thread;
574 : #endif
575 : tommy_node node;
576 : };
577 : typedef struct devinfo_struct devinfo_t;
578 :
579 : void device_name_set(devinfo_t* dev, const char* name, int index);
580 :
581 : #define DEVICE_LIST 0
582 : #define DEVICE_DOWN 1
583 : #define DEVICE_UP 2
584 : #define DEVICE_SMART 3
585 : #define DEVICE_PROBE 4
586 : #define DEVICE_DOWNIFUP 5
587 :
588 : /**
589 : * Query all the "high" level devices with the specified operation,
590 : * and produces a list of "low" level devices to operate on.
591 : *
592 : * The passed "low" device list must be already initialized.
593 : */
594 : int devquery(tommy_list* high, tommy_list* low, int operation);
595 :
596 : /**
597 : * Fill with fake data the device list.
598 : */
599 : int devtest(tommy_list* high, tommy_list* low, int operation);
600 :
601 : /**
602 : * Query all the "low" devices and log their unique identifiers
603 : */
604 : int devmap(void);
605 :
606 : /**
607 : * Get the ambient temperature in degree
608 : *
609 : * Return 0 if not available.
610 : */
611 : int ambient_temperature(void);
612 :
613 : /**
614 : * Size of the spaceholder file for Windows to avoid the message of low disk space
615 : */
616 : #define WINDOWS_SPACEHOLDER_SIZE (256 * 1024 * 1024)
617 :
618 : /**
619 : * Generic errors
620 : */
621 : #define EINTERNAL EFAULT /**< Internal assertion failed. */
622 : #define EDATA EIO /**< Silent data corruption. */
623 : #define ESOFT EINVAL /**< Software error, like permission denied. */
624 : #define EUSER EINVAL /**< Invalid value specified by the user. */
625 : #define EEXTERNAL EINVAL /**< Invalid external interface behaviour. */
626 : #define ECONTENT EINVAL /**< Invalid content file. */
627 : #define EENVIRONMENT EINVAL /**< Invalid physical environment, like temperature too high. */
628 :
629 : #endif
630 :
|