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