mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 10:51:54 -04:00
Adds UUID to check to detect disk misplacement.
This commit is contained in:
parent
8810d7b05d
commit
768113c670
15 changed files with 272 additions and 34 deletions
2
HISTORY
2
HISTORY
|
|
@ -19,6 +19,8 @@ SnapRAID HISTORY
|
|||
exclusion rules.
|
||||
* In 'check' and 'fix', if verbose is enabled, prints the result for each
|
||||
processed file.
|
||||
* Added an UUID check to detect when a disk is replaced, and to prevent
|
||||
unwanted disk swaps.
|
||||
|
||||
2.1 2013/1
|
||||
==========
|
||||
|
|
|
|||
7
TODO
7
TODO
|
|
@ -28,6 +28,13 @@ on the error message. See: https://sourceforge.net/projects/snapraid/forums/foru
|
|||
* In Windows to use FILE_FLAG_BACKUP_SEMANTICS we should also get privileges.
|
||||
See http://www.codeproject.com/Articles/21202/Reparse-Points-in-Vista.
|
||||
Altought it doesn't seem necessary when used in CreateFile to just open directory.
|
||||
Anyway, see this snipset found with google:
|
||||
DWORD access = 0;
|
||||
DWORD share = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||
CreateFile(path1,access,share,NULL,OPEN_EXISTING,
|
||||
(GetFileAttributes(path1)&FILE_ATTRIBUTE_DIRECTORY)?FILE_FLAG_BACKUP_SEMANTICS:0,NULL);
|
||||
It seems to use it *exclusively* for directory.
|
||||
Is it possible that the need of lstat_ex depends on that ?
|
||||
|
||||
* In Windows we must be case insensitive, at least for ASCII<128 comparison. For other UTF-8 chars
|
||||
is too complex.
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ AC_SYS_LARGEFILE
|
|||
AC_CHECK_FUNCS([memset strchr strerror strrchr mkdir gettimeofday strtoul])
|
||||
AC_CHECK_FUNCS([getopt getopt_long snprintf vsnprintf])
|
||||
AC_CHECK_FUNCS([ftruncate fallocate fsync access posix_fallocate posix_fadvise pread pwrite getc_unlocked ferror_unlocked fnmatch])
|
||||
AC_CHECK_FUNCS([futimes futimens futimesat])
|
||||
AC_CHECK_FUNCS([futimes futimens futimesat fstatat])
|
||||
|
||||
dnl Checks for architecture
|
||||
AC_C_BIGENDIAN
|
||||
|
|
|
|||
3
elem.c
3
elem.c
|
|
@ -496,12 +496,13 @@ void disk_free(struct snapraid_disk* disk)
|
|||
free(disk);
|
||||
}
|
||||
|
||||
struct snapraid_map* map_alloc(const char* name, unsigned position)
|
||||
struct snapraid_map* map_alloc(const char* name, unsigned position, const char* uuid)
|
||||
{
|
||||
struct snapraid_map* map;
|
||||
|
||||
map = malloc_nofail(sizeof(struct snapraid_map));
|
||||
pathcpy(map->name, sizeof(map->name), name);
|
||||
pathcpy(map->uuid, sizeof(map->uuid), uuid);
|
||||
map->position = position;
|
||||
|
||||
return map;
|
||||
|
|
|
|||
9
elem.h
9
elem.h
|
|
@ -252,12 +252,18 @@ struct snapraid_disk {
|
|||
tommy_node node;
|
||||
};
|
||||
|
||||
/**
|
||||
* Max UUID length.
|
||||
*/
|
||||
#define UUID_MAX 128
|
||||
|
||||
/**
|
||||
* Disk mapping.
|
||||
*/
|
||||
struct snapraid_map {
|
||||
char name[PATH_MAX]; /**< Name of the disk. */
|
||||
unsigned position; /**< Position of the disk in the parity. */
|
||||
char uuid[UUID_MAX]; /**< UUID of the disk. Empty if unknown. */
|
||||
|
||||
/* nodes for data structures */
|
||||
tommy_node node;
|
||||
|
|
@ -617,8 +623,9 @@ static inline struct snapraid_block* disk_block_get(struct snapraid_disk* disk,
|
|||
|
||||
/**
|
||||
* Allocates a disk mapping.
|
||||
* Uses uuid="" if not available.
|
||||
*/
|
||||
struct snapraid_map* map_alloc(const char* name, unsigned position);
|
||||
struct snapraid_map* map_alloc(const char* name, unsigned position, const char* uuid);
|
||||
|
||||
/**
|
||||
* Deallocates a disk mapping.
|
||||
|
|
|
|||
8
mingw.c
8
mingw.c
|
|
@ -1029,5 +1029,13 @@ int windows_readlink(const char* file, char* buffer, size_t size)
|
|||
return len;
|
||||
}
|
||||
|
||||
int devuuid(uint64_t device, char* uuid, size_t uuid_size)
|
||||
{
|
||||
/* just use the volume serial number returned in the device parameter */
|
||||
|
||||
snprintf(uuid, uuid_size, "%08x", (unsigned)device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -128,6 +128,12 @@ static inline int hardlink(const char* a, const char* b)
|
|||
return link(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the device UUID.
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
int devuuid(uint64_t device, char* uuid, size_t size);
|
||||
|
||||
/**
|
||||
* Initializes the system.
|
||||
*/
|
||||
|
|
|
|||
13
scan.c
13
scan.c
|
|
@ -385,8 +385,10 @@ static void scan_file(struct snapraid_scan* scan, struct snapraid_state* state,
|
|||
/* otherwise it could be a deleted and recreated file */
|
||||
if (strcmp(file->sub, sub) == 0) {
|
||||
if (!state->force_zero) {
|
||||
fprintf(stderr, "The file '%s%s' has now zero size!\n", disk->dir, sub);
|
||||
fprintf(stderr, "If you really want to sync, use 'snapraid --force-zero sync'\n");
|
||||
fprintf(stderr, "The file '%s%s' has unexpected zero size! If this an expected state\n", disk->dir, sub);
|
||||
fprintf(stderr, "you can '%s' anyway usinge 'snapraid --force-zero %s'\n", state->command, state->command);
|
||||
fprintf(stderr, "Instead, it's possible that after a kernel crash this file was lost,\n");
|
||||
fprintf(stderr, "and you can use 'snapraid --filter %s fix' to recover it.\n", sub);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
|
@ -851,8 +853,11 @@ void state_scan(struct snapraid_state* state, int output)
|
|||
}
|
||||
if (has_empty) {
|
||||
fprintf(stderr, " are now missing or rewritten!\n");
|
||||
fprintf(stderr, "This happens with an empty disk or when all the files are recreated after a 'fix' command.\n");
|
||||
fprintf(stderr, "If you really want to sync, use 'snapraid --force-empty sync'.\n");
|
||||
fprintf(stderr, "This happens when deleting all the files from a disk,\n");
|
||||
fprintf(stderr, "or when all the files are recreated after a 'fix' command,\n");
|
||||
fprintf(stderr, "or manually copied. If this is really what you are doing, \n");
|
||||
fprintf(stderr, "you can '%s' anyway, using 'snapraid --force-empty %s'.\n", state->command, state->command);
|
||||
fprintf(stderr, "Instead, it's possible that you have some disks not mounted.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
27
snapraid.1
27
snapraid.1
|
|
@ -18,7 +18,7 @@ snapraid [\(hyc, \(hy\(hyconf CONFIG]
|
|||
.PD 0
|
||||
.PP
|
||||
.PD
|
||||
[\(hyZ, \(hy\(hyforce\(hyzero] [\(hyE, \(hy\(hyforce\(hyempty]
|
||||
[\(hyZ, \(hy\(hyforce\(hyzero] [\(hyE, \(hy\(hyforce\(hyempty] [\(hyU, \(hy\(hyforce\(hyuuid]
|
||||
.PD 0
|
||||
.PP
|
||||
.PD
|
||||
|
|
@ -506,6 +506,16 @@ This allows to easily detect when a data file\(hysystem is not
|
|||
mounted.
|
||||
This option can be used only with the \(a"sync\(a" command.
|
||||
.TP
|
||||
.B \(hyU, \(hy\(hyforce\(hyuuid
|
||||
Forces the insecure operation of syncing, checking and fixing
|
||||
with disks that have changed the UUID.
|
||||
If SnapRAID detects that a disk has changed UUID,
|
||||
it stops proceeding unless you specify this option.
|
||||
This allows to detect when your disks are mounted in the
|
||||
wrong mount points.
|
||||
This option can be used only with the \(a"sync\(a", \(a"check\(a" or
|
||||
\(a"fix\(a" command.
|
||||
.TP
|
||||
.B \(hys, \(hy\(hystart BLKSTART
|
||||
Starts the processing from the specified
|
||||
block number. It could be useful to easy retry to check
|
||||
|
|
@ -919,7 +929,7 @@ disk d1 /mnt/new_spare_disk/
|
|||
Run the fix command, storing the log in an external file with:
|
||||
.PP
|
||||
.RS 4
|
||||
snapraid \(hyd NAME fix 2>fix.log
|
||||
snapraid \(hyd NAME \(hyl fix.log fix
|
||||
.PD 0
|
||||
.PP
|
||||
.PD
|
||||
|
|
@ -929,6 +939,12 @@ Where NAME is the name of the disk, like \(a"d1\(a" as in our previous example.
|
|||
.PP
|
||||
This command will take a long time.
|
||||
.PP
|
||||
If the command doesn\(cqt start complaining that the failed and replaced
|
||||
disk has changed UUID, just add the \(cq\(hyU\(cq option.
|
||||
But ensure that the failed disk is the only one with the UUID changed.
|
||||
.PP
|
||||
You can also add the \(cq\(hyv\(cq option to see on the console the fixed files.
|
||||
.PP
|
||||
Take care that you need also few gigabytes free to store the fix.log file.
|
||||
Run it from a disk with some free space.
|
||||
.PP
|
||||
|
|
@ -946,8 +962,8 @@ If you are satisfied of the recovering, you can now proceed further,
|
|||
but take care that after synching you will no more able to retry the
|
||||
\(a"fix\(a" command!
|
||||
.SS STEP 3 \(hy> Check
|
||||
As paranoid check, you can now run a whole \(a"check\(a" command to ensure that
|
||||
everything is OK.
|
||||
As paranoid but recommended check, you can now run a \(a"check\(a" command to ensure
|
||||
that everything is OK on the disk.
|
||||
.PP
|
||||
.RS 4
|
||||
snapraid \(hyd NAME \(hya check
|
||||
|
|
@ -994,8 +1010,9 @@ defined in the configuration file.
|
|||
.SS checksum CHECKSUM
|
||||
Defines the checksum kind used. It can be only \(a"murmur3\(a".
|
||||
From SnapRAID 2.0 the old \(a"md5\(a" checksum is not supported anymore.
|
||||
.SS map NAME INDEX
|
||||
.SS map NAME INDEX [UUID]
|
||||
Defines the position INDEX of the disk NAME in the parity computation.
|
||||
The disk UUID is also present if supported for the platform.
|
||||
.SS sign SIGN
|
||||
Signature checksum of the content file to ensure that it doesn\(cqt get
|
||||
corrupted. If you want to modify the content file manually, you have
|
||||
|
|
|
|||
13
snapraid.c
13
snapraid.c
|
|
@ -66,6 +66,7 @@ void usage(void)
|
|||
printf(" " SWITCH_GETOPT_LONG("-N, --find-by-name ", "-N") " Find the files by name instead than by inode\n");
|
||||
printf(" " SWITCH_GETOPT_LONG("-Z, --force-zero ", "-Z") " Force synching of files that get zero size\n");
|
||||
printf(" " SWITCH_GETOPT_LONG("-E, --force-empty ", "-E") " Force synching of disks that get empty\n");
|
||||
printf(" " SWITCH_GETOPT_LONG("-U, --force-uuid ", "-U") " Force commands on disks with uuid changed\n");
|
||||
printf(" " SWITCH_GETOPT_LONG("-s, --start BLKSTART ", "-s") " Start from the specified block number\n");
|
||||
printf(" " SWITCH_GETOPT_LONG("-t, --count BLKCOUNT ", "-t") " Count of block to process\n");
|
||||
printf(" " SWITCH_GETOPT_LONG("-v, --verbose ", "-v") " Verbose\n");
|
||||
|
|
@ -94,6 +95,7 @@ struct option long_options[] = {
|
|||
{ "log", 1, 0, 'l' },
|
||||
{ "force-zero", 0, 0, 'Z' },
|
||||
{ "force-empty", 0, 0, 'E' },
|
||||
{ "force-uuid", 0, 0, 'U' },
|
||||
{ "find-by-name", 0, 0, 'N' },
|
||||
{ "audit-only", 0, 0, 'a' },
|
||||
{ "speed-test", 0, 0, 'T' },
|
||||
|
|
@ -101,7 +103,7 @@ struct option long_options[] = {
|
|||
{ "gui", 0, 0, 'G' }, /* undocumented GUI interface command */
|
||||
{ "help", 0, 0, 'h' },
|
||||
{ "version", 0, 0, 'V' },
|
||||
|
||||
|
||||
/* The following are test specific options, DO NOT USE! */
|
||||
|
||||
/* After syncing, do not write the new content file */
|
||||
|
|
@ -128,7 +130,7 @@ struct option long_options[] = {
|
|||
};
|
||||
#endif
|
||||
|
||||
#define OPTIONS "c:f:d:ms:t:i:l:ZENaTvhVG"
|
||||
#define OPTIONS "c:f:d:ms:t:i:l:ZEUNaTvhVG"
|
||||
|
||||
volatile int global_interrupt = 0;
|
||||
|
||||
|
|
@ -156,6 +158,7 @@ int main(int argc, char* argv[])
|
|||
int gui;
|
||||
int force_zero;
|
||||
int force_empty;
|
||||
int force_uuid;
|
||||
int find_by_name;
|
||||
int audit_only;
|
||||
int test_kill_after_sync;
|
||||
|
|
@ -187,6 +190,7 @@ int main(int argc, char* argv[])
|
|||
gui = 0;
|
||||
force_zero = 0;
|
||||
force_empty = 0;
|
||||
force_uuid = 0;
|
||||
find_by_name = 0;
|
||||
audit_only = 0;
|
||||
test_kill_after_sync = 0;
|
||||
|
|
@ -269,6 +273,9 @@ int main(int argc, char* argv[])
|
|||
case 'E' :
|
||||
force_empty = 1;
|
||||
break;
|
||||
case 'U' :
|
||||
force_uuid = 1;
|
||||
break;
|
||||
case 'N' :
|
||||
find_by_name = 1;
|
||||
break;
|
||||
|
|
@ -402,7 +409,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
state_init(&state);
|
||||
|
||||
state_config(&state, conf, verbose, gui, force_zero, force_empty, find_by_name, test_expect_unrecoverable, test_expect_recoverable, test_skip_sign, test_skip_fallocate, test_skip_device);
|
||||
state_config(&state, conf, command, verbose, gui, force_zero, force_empty, force_uuid, find_by_name, test_expect_unrecoverable, test_expect_recoverable, test_skip_sign, test_skip_fallocate, test_skip_device);
|
||||
|
||||
if (import != 0) {
|
||||
printf("%s\n", import);
|
||||
|
|
|
|||
27
snapraid.d
27
snapraid.d
|
|
@ -6,7 +6,7 @@ Synopsis
|
|||
: [-f, --filter PATTERN] [-d, --filter-disk NAME] [-m, --filter-missing]
|
||||
: [-a, --audit-only] [-i, --import DIR]
|
||||
: [-N, --find-by-name]
|
||||
: [-Z, --force-zero] [-E, --force-empty]
|
||||
: [-Z, --force-zero] [-E, --force-empty] [-U, --force-uuid]
|
||||
: [-s, --start BLKSTART] [-t, --count BLKCOUNT]
|
||||
: [-v, --verbose] [-l, --log FILE]
|
||||
: sync|pool|diff|dup|check|fix
|
||||
|
|
@ -363,6 +363,16 @@ Options
|
|||
mounted.
|
||||
This option can be used only with the "sync" command.
|
||||
|
||||
-U, --force-uuid
|
||||
Forces the insecure operation of syncing, checking and fixing
|
||||
with disks that have changed the UUID.
|
||||
If SnapRAID detects that a disk has changed UUID,
|
||||
it stops proceeding unless you specify this option.
|
||||
This allows to detect when your disks are mounted in the
|
||||
wrong mount points.
|
||||
This option can be used only with the "sync", "check" or
|
||||
"fix" command.
|
||||
|
||||
-s, --start BLKSTART
|
||||
Starts the processing from the specified
|
||||
block number. It could be useful to easy retry to check
|
||||
|
|
@ -645,12 +655,18 @@ Recovering
|
|||
STEP 2 -> Fix
|
||||
Run the fix command, storing the log in an external file with:
|
||||
|
||||
:snapraid -d NAME fix 2>fix.log
|
||||
:snapraid -d NAME -l fix.log fix
|
||||
|
||||
Where NAME is the name of the disk, like "d1" as in our previous example.
|
||||
|
||||
This command will take a long time.
|
||||
|
||||
If the command doesn't start complaining that the failed and replaced
|
||||
disk has changed UUID, just add the '-U' option.
|
||||
But ensure that the failed disk is the only one with the UUID changed.
|
||||
|
||||
You can also add the '-v' option to see on the console the fixed files.
|
||||
|
||||
Take care that you need also few gigabytes free to store the fix.log file.
|
||||
Run it from a disk with some free space.
|
||||
|
||||
|
|
@ -669,8 +685,8 @@ Recovering
|
|||
"fix" command!
|
||||
|
||||
STEP 3 -> Check
|
||||
As paranoid check, you can now run a whole "check" command to ensure that
|
||||
everything is OK.
|
||||
As paranoid but recommended check, you can now run a "check" command to ensure
|
||||
that everything is OK on the disk.
|
||||
|
||||
:snapraid -d NAME -a check
|
||||
|
||||
|
|
@ -712,8 +728,9 @@ Content
|
|||
Defines the checksum kind used. It can be only "murmur3".
|
||||
From SnapRAID 2.0 the old "md5" checksum is not supported anymore.
|
||||
|
||||
map NAME INDEX
|
||||
map NAME INDEX [UUID]
|
||||
Defines the position INDEX of the disk NAME in the parity computation.
|
||||
The disk UUID is also present if supported for the platform.
|
||||
|
||||
sign SIGN
|
||||
Signature checksum of the content file to ensure that it doesn't get
|
||||
|
|
|
|||
29
snapraid.txt
29
snapraid.txt
|
|
@ -10,7 +10,7 @@ snapraid [-c, --conf CONFIG]
|
|||
[-f, --filter PATTERN] [-d, --filter-disk NAME] [-m, --filter-missing]
|
||||
[-a, --audit-only] [-i, --import DIR]
|
||||
[-N, --find-by-name]
|
||||
[-Z, --force-zero] [-E, --force-empty]
|
||||
[-Z, --force-zero] [-E, --force-empty] [-U, --force-uuid]
|
||||
[-s, --start BLKSTART] [-t, --count BLKCOUNT]
|
||||
[-v, --verbose] [-l, --log FILE]
|
||||
sync|pool|diff|dup|check|fix
|
||||
|
|
@ -398,6 +398,16 @@ SnapRAID provides the following options:
|
|||
mounted.
|
||||
This option can be used only with the "sync" command.
|
||||
|
||||
-U, --force-uuid
|
||||
Forces the insecure operation of syncing, checking and fixing
|
||||
with disks that have changed the UUID.
|
||||
If SnapRAID detects that a disk has changed UUID,
|
||||
it stops proceeding unless you specify this option.
|
||||
This allows to detect when your disks are mounted in the
|
||||
wrong mount points.
|
||||
This option can be used only with the "sync", "check" or
|
||||
"fix" command.
|
||||
|
||||
-s, --start BLKSTART
|
||||
Starts the processing from the specified
|
||||
block number. It could be useful to easy retry to check
|
||||
|
|
@ -709,12 +719,18 @@ to:
|
|||
|
||||
Run the fix command, storing the log in an external file with:
|
||||
|
||||
snapraid -d NAME fix 2>fix.log
|
||||
snapraid -d NAME -l fix.log fix
|
||||
|
||||
Where NAME is the name of the disk, like "d1" as in our previous example.
|
||||
|
||||
This command will take a long time.
|
||||
|
||||
If the command doesn't start complaining that the failed and replaced
|
||||
disk has changed UUID, just add the '-U' option.
|
||||
But ensure that the failed disk is the only one with the UUID changed.
|
||||
|
||||
You can also add the '-v' option to see on the console the fixed files.
|
||||
|
||||
Take care that you need also few gigabytes free to store the fix.log file.
|
||||
Run it from a disk with some free space.
|
||||
|
||||
|
|
@ -735,8 +751,8 @@ but take care that after synching you will no more able to retry the
|
|||
9.3 STEP 3 -> Check
|
||||
-------------------
|
||||
|
||||
As paranoid check, you can now run a whole "check" command to ensure that
|
||||
everything is OK.
|
||||
As paranoid but recommended check, you can now run a "check" command to ensure
|
||||
that everything is OK on the disk.
|
||||
|
||||
snapraid -d NAME -a check
|
||||
|
||||
|
|
@ -787,10 +803,11 @@ defined in the configuration file.
|
|||
Defines the checksum kind used. It can be only "murmur3".
|
||||
From SnapRAID 2.0 the old "md5" checksum is not supported anymore.
|
||||
|
||||
10.3 map NAME INDEX
|
||||
-------------------
|
||||
10.3 map NAME INDEX [UUID]
|
||||
--------------------------
|
||||
|
||||
Defines the position INDEX of the disk NAME in the parity computation.
|
||||
The disk UUID is also present if supported for the platform.
|
||||
|
||||
10.4 sign SIGN
|
||||
--------------
|
||||
|
|
|
|||
86
state.c
86
state.c
|
|
@ -217,10 +217,9 @@ static void state_config_check(struct snapraid_state* state, const char* path, i
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void state_config(struct snapraid_state* state, const char* path, int verbose, int gui, int force_zero, int force_empty, int find_by_name, int expect_unrecoverable, int expect_recoverable, int skip_sign, int skip_fallocate, int skip_device)
|
||||
void state_config(struct snapraid_state* state, const char* path, const char* command, int verbose, int gui, int force_zero, int force_empty, int force_uuid, int find_by_name, int expect_unrecoverable, int expect_recoverable, int skip_sign, int skip_fallocate, int skip_device)
|
||||
{
|
||||
STREAM* f;
|
||||
unsigned line;
|
||||
|
|
@ -229,12 +228,14 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i
|
|||
state->gui = gui;
|
||||
state->force_zero = force_zero;
|
||||
state->force_empty = force_empty;
|
||||
state->force_uuid = force_uuid;
|
||||
state->filter_hidden = 0;
|
||||
state->find_by_name = find_by_name;
|
||||
state->expect_unrecoverable = expect_unrecoverable;
|
||||
state->expect_recoverable = expect_recoverable;
|
||||
state->skip_sign = skip_sign;
|
||||
state->skip_fallocate = skip_fallocate;
|
||||
state->command = command;
|
||||
|
||||
if (state->gui) {
|
||||
fprintf(stdlog, "version:%s\n", PACKAGE_VERSION);
|
||||
|
|
@ -611,6 +612,7 @@ static void state_map(struct snapraid_state* state)
|
|||
{
|
||||
unsigned hole;
|
||||
tommy_node* i;
|
||||
unsigned uuid_mismatch;
|
||||
|
||||
/* removes all the mapping without a disk */
|
||||
/* this happens when a disk is removed from the configuration file */
|
||||
|
|
@ -675,10 +677,64 @@ static void state_map(struct snapraid_state* state)
|
|||
}
|
||||
|
||||
/* insert the new mapping */
|
||||
map = map_alloc(disk->name, hole);
|
||||
map = map_alloc(disk->name, hole, "");
|
||||
|
||||
tommy_list_insert_tail(&state->maplist, &map->node, map);
|
||||
}
|
||||
|
||||
/* checks if mapping match the disk uuid */
|
||||
uuid_mismatch = 0;
|
||||
for(i=state->maplist;i!=0;i=i->next) {
|
||||
struct snapraid_map* map = i->data;
|
||||
struct snapraid_disk* disk;
|
||||
tommy_node* j;
|
||||
char uuid[UUID_MAX];
|
||||
int ret;
|
||||
|
||||
for(j=state->disklist;j!=0;j=j->next) {
|
||||
disk = j->data;
|
||||
if (strcmp(disk->name, map->name) == 0) {
|
||||
/* disk found */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j==0) {
|
||||
fprintf(stderr, "Internal incosistency for mapping '%s'\n", map->name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ret = devuuid(disk->device, uuid, sizeof(uuid));
|
||||
if (ret != 0) {
|
||||
/* uuid not available, just ignore */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (map->uuid[0] != 0) {
|
||||
if (strcmp(uuid, map->uuid) != 0) {
|
||||
++uuid_mismatch;
|
||||
fprintf(stderr, "UUID change for disk '%s' from '%s' to '%s'\n", disk->name, map->uuid, uuid);
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(uuid, map->uuid) != 0) {
|
||||
/* rewrite if the uuid changes */
|
||||
state->need_write = 1;
|
||||
}
|
||||
|
||||
/* update the uuid in the mapping, */
|
||||
/* even if it's already present because it may be changed */
|
||||
pathcpy(map->uuid, sizeof(map->uuid), uuid);
|
||||
}
|
||||
|
||||
if (!state->force_uuid && uuid_mismatch > 0) {
|
||||
fprintf(stderr, "Some disks have UUID changed from the latest 'sync'.\n");
|
||||
fprintf(stderr, "If this happens because you really replaced them,\n");
|
||||
fprintf(stderr, "you can '%s' anyway, using 'snapraid --force-uuid %s'.\n", state->command, state->command);
|
||||
fprintf(stderr, "Instead, it's possible that you messed up the disk mount points,\n");
|
||||
fprintf(stderr, "and you have to restore the mount points at the state of the latest sync.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1356,6 +1412,7 @@ void state_read(struct snapraid_state* state)
|
|||
}
|
||||
} else if (strcmp(tag, "map") == 0) {
|
||||
struct snapraid_map* map;
|
||||
char uuid[UUID_MAX];
|
||||
uint32_t v_pos;
|
||||
|
||||
hash = oathash8(hash, 'm');
|
||||
|
|
@ -1380,7 +1437,21 @@ void state_read(struct snapraid_state* state)
|
|||
}
|
||||
hash = oathash32(hash, v_pos);
|
||||
|
||||
map = map_alloc(buffer, v_pos);
|
||||
c = sgetc(f);
|
||||
if (c != ' ') {
|
||||
sungetc(c, f);
|
||||
uuid[0] = 0;
|
||||
} else {
|
||||
/* read the uuid */
|
||||
ret = sgettok(f, uuid, sizeof(uuid));
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Invalid 'map' specification in '%s' at line %u\n", path, line);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
hash = oathashs(hash, uuid);
|
||||
}
|
||||
|
||||
map = map_alloc(buffer, v_pos, uuid);
|
||||
|
||||
tommy_list_insert_tail(&state->maplist, &map->node, map);
|
||||
} else if (strcmp(tag, "sign") == 0) {
|
||||
|
|
@ -1553,6 +1624,13 @@ void state_write(struct snapraid_state* state)
|
|||
sputc(' ', f);
|
||||
sputu32(map->position, f);
|
||||
hash = oathash32(hash, map->position);
|
||||
|
||||
/* if there is an uuid, print it */
|
||||
if (map->uuid[0]) {
|
||||
sputc(' ', f);
|
||||
sputs(map->uuid, f);
|
||||
hash = oathashs(hash, map->uuid);
|
||||
}
|
||||
sputeol(f);
|
||||
if (serror(f)) {
|
||||
fprintf(stderr, "Error writing the content file '%s'. %s.\n", serrorfile(f), strerror(errno));
|
||||
|
|
|
|||
8
state.h
8
state.h
|
|
@ -29,8 +29,9 @@ extern volatile int global_interrupt;
|
|||
struct snapraid_state {
|
||||
int verbose; /**< Verbose output. */
|
||||
int gui; /**< Gui output. */
|
||||
int force_zero; /**< Forced dangerous operations of synching file now with zero size. */
|
||||
int force_empty; /**< Forced dangerous operations of synching disk now empty. */
|
||||
int force_zero; /**< Forced dangerous operations of synching files now with zero size. */
|
||||
int force_empty; /**< Forced dangerous operations of synching disks now empty. */
|
||||
int force_uuid; /**< Forced dangerous operations of synching disks with uuid changed. */
|
||||
int filter_hidden; /**< Filter out hidden files. */
|
||||
int find_by_name; /**< Forced dangerous operations of synching a rewritten disk. */
|
||||
uint64_t autosave; /**< Autosave after the specified amount of data. 0 to disable. */
|
||||
|
|
@ -48,6 +49,7 @@ struct snapraid_state {
|
|||
uint64_t pool_device; /**< Device identifier of the pool. */
|
||||
unsigned level; /**< Number of parity levels. 1 for RAID5, 2 for RAID6. */
|
||||
unsigned hash; /**< Hash kind used. */
|
||||
const char* command; /**< Command running. */
|
||||
tommy_list contentlist; /**< List of content files. */
|
||||
tommy_list disklist; /**< List of all the disks. */
|
||||
tommy_list maplist; /**< List of all the disk mappings. */
|
||||
|
|
@ -74,7 +76,7 @@ void state_done(struct snapraid_state* state);
|
|||
/**
|
||||
* Reads the configuration file.
|
||||
*/
|
||||
void state_config(struct snapraid_state* state, const char* path, int verbose, int gui, int force_zero, int force_empty, int find_by_name, int expect_unrecoverable, int expect_recoverable, int skip_sign, int skip_fallocate, int skip_device);
|
||||
void state_config(struct snapraid_state* state, const char* path, const char* command, int verbose, int gui, int force_zero, int force_empty, int force_uuid, int find_by_name, int expect_unrecoverable, int expect_recoverable, int skip_sign, int skip_fallocate, int skip_device);
|
||||
|
||||
/**
|
||||
* Reads the state.
|
||||
|
|
|
|||
66
unix.c
66
unix.c
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Andrea Mazzoleni
|
||||
* Copyright (C) 2013 Andrea Mazzoleni
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -59,6 +59,70 @@ const char* stat_desc(struct stat* st)
|
|||
return "unknown";
|
||||
}
|
||||
|
||||
#if HAVE_FSTATAT
|
||||
/**
|
||||
* This function get the UUID using the /dev/disk/by-uuid/ links.
|
||||
* Comparing with the libblkid library, it works also from not root processes.
|
||||
*/
|
||||
int devuuid(uint64_t device, char* uuid, size_t uuid_size)
|
||||
{
|
||||
int ret;
|
||||
DIR* d;
|
||||
struct stat st;
|
||||
|
||||
/* scan the UUID directory searching for the device */
|
||||
d = opendir("/dev/disk/by-uuid");
|
||||
if (!d) {
|
||||
/* directory missing?, likely we are not in Linux */
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
struct dirent* dd;
|
||||
|
||||
dd = readdir(d);
|
||||
if (dd == 0) {
|
||||
/* not found or generic error */
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* skip "." and ".." files, UUIDs never start with '.' */
|
||||
if (dd->d_name[0] == '.') {
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = fstatat(dirfd(d), dd->d_name, &st, 0);
|
||||
if (ret != 0) {
|
||||
/* generic error, ignore and continue the search */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if it matches, we have the uuid */
|
||||
if (S_ISBLK(st.st_mode) && st.st_rdev == device) {
|
||||
snprintf(uuid, uuid_size, "%s", dd->d_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
closedir(d);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
int devuuid(uint64_t device, char* uuid, size_t uuid_size)
|
||||
{
|
||||
(void)device;
|
||||
(void)uuid;
|
||||
(void)uuid_size;
|
||||
|
||||
/* not supported */
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
void os_init(void)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue