mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 19:01:57 -04:00
Use precise quoting for the shell commands
This commit is contained in:
parent
12b30c198e
commit
840ec7b1c3
5 changed files with 201 additions and 12 deletions
|
|
@ -234,12 +234,14 @@ if HAVE_THREAD_CHECKER
|
|||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) scrub -p full -test-io-cache 128
|
||||
else
|
||||
#### COMMAND LINE ####
|
||||
$(MSG) Help
|
||||
$(MSG) Pre test
|
||||
$(TESTENV) ./snapraid$(EXEEXT) --test-skip-device -H
|
||||
$(TESTENV) ./snapraid$(EXEEXT) --test-skip-device -V
|
||||
$(TESTENV) ./snapraid$(EXEEXT) test
|
||||
$(TESTENV) ./mktest$(EXEEXT)
|
||||
if !HAVE_MEMORY_CHECKER
|
||||
if HAVE_EMULATOR
|
||||
$(MSG) Speed
|
||||
# Run the self test in AVX2
|
||||
$(TESTENV_AVX2) ./snapraid$(EXEEXT) --test-skip-device -c $(CONF) status
|
||||
# Run the speed test in different architectures
|
||||
|
|
|
|||
|
|
@ -89,6 +89,36 @@ void memory(void)
|
|||
msg_progress("Using %u MiB of memory for the FileSystem.\n", (unsigned)(malloc_counter_get() / MEBI));
|
||||
}
|
||||
|
||||
void test(int argc, char* argv[])
|
||||
{
|
||||
int i;
|
||||
char buffer[QUOTE_MAX];
|
||||
|
||||
/* special testing code for quoting */
|
||||
if (argc < 2 || strcmp(argv[1], "test") != 0)
|
||||
return;
|
||||
|
||||
for (i = 2; i < argc; ++i) {
|
||||
printf("argv[%d]\n", i);
|
||||
printf("\t#%s#\n", argv[i]);
|
||||
printf("\t#%s#\n", quote(0, argv[i], buffer));
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
assert(strcmp(quote(0, " ", buffer), "\" \"") == 0);
|
||||
assert(strcmp(quote(0, " \" ", buffer), "\" \"\\\"\" \"") == 0);
|
||||
assert(strcmp(quote(0, "&|()<>^", buffer), "^&^|^(^)^<^>^^") == 0);
|
||||
assert(strcmp(quote(0, "&|()<>^ ", buffer), "\"&|()<>^ \"") == 0);
|
||||
#else
|
||||
assert(strcmp(quote(0, ",._+:@%%/-", buffer), ",._+:@%%/-") == 0);
|
||||
assert(strcmp(quote(0, " ", buffer), "\\ ") == 0);
|
||||
#endif
|
||||
|
||||
printf("Everything OK\n");
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/* log */
|
||||
|
||||
|
|
@ -472,6 +502,8 @@ int main(int argc, char* argv[])
|
|||
struct tm* tm;
|
||||
int i;
|
||||
|
||||
test(argc, argv);
|
||||
|
||||
lock_init();
|
||||
|
||||
/* defaults */
|
||||
|
|
|
|||
|
|
@ -379,11 +379,11 @@ void printp(double v, size_t pad)
|
|||
printl(buf, pad);
|
||||
}
|
||||
|
||||
#define ESCAPE(from,to) \
|
||||
#define ESCAPE(from,escape,to) \
|
||||
case from : \
|
||||
if (p == end) \
|
||||
goto bail; \
|
||||
*p++ = '\\'; \
|
||||
*p++ = escape; \
|
||||
if (p == end) \
|
||||
goto bail; \
|
||||
*p++ = to; \
|
||||
|
|
@ -401,10 +401,10 @@ const char* esc(const char* str, char* buffer)
|
|||
|
||||
switch (c) {
|
||||
|
||||
ESCAPE('\n', 'n');
|
||||
ESCAPE('\r', 'r');
|
||||
ESCAPE(':', 'd');
|
||||
ESCAPE('\\', '\\');
|
||||
ESCAPE('\n', '\\', 'n');
|
||||
ESCAPE('\r', '\\', 'r');
|
||||
ESCAPE(':', '\\', 'd');
|
||||
ESCAPE('\\', '\\', '\\');
|
||||
|
||||
default:
|
||||
if (p == end)
|
||||
|
|
@ -430,6 +430,149 @@ bail:
|
|||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
const char* quote(char prefix, const char* str, char* buffer)
|
||||
{
|
||||
char* begin = buffer;
|
||||
char* end = begin + QUOTE_MAX;
|
||||
char* p = begin;
|
||||
|
||||
#ifdef _WIN32
|
||||
int has_quote = strchr(str, ' ') != 0;
|
||||
|
||||
if (has_quote) {
|
||||
if (p == end)
|
||||
goto bail;
|
||||
*p++ = '"';
|
||||
}
|
||||
#endif
|
||||
|
||||
/* add the prefix char, if any */
|
||||
if (prefix) {
|
||||
if (p == end)
|
||||
goto bail;
|
||||
*p++ = prefix;
|
||||
}
|
||||
|
||||
/* copy string with escaping */
|
||||
while (*str) {
|
||||
char c = *str;
|
||||
|
||||
switch (c) {
|
||||
#ifdef _WIN32
|
||||
/*
|
||||
* Windows shell escape
|
||||
*
|
||||
* The Windows NT Command Shell
|
||||
* https://technet.microsoft.com/en-us/library/cc723564.aspx
|
||||
*/
|
||||
case '"' :
|
||||
/* double quote, it needs to be quoted with \ */
|
||||
if (has_quote) {
|
||||
/* " -> "\"" -> (close quote)(quoted with \ ")(reopen quote) */
|
||||
if (p == end)
|
||||
goto bail;
|
||||
*p++ = '"';
|
||||
if (p == end)
|
||||
goto bail;
|
||||
*p++ = '\\';
|
||||
if (p == end)
|
||||
goto bail;
|
||||
*p++ = '"';
|
||||
if (p == end)
|
||||
goto bail;
|
||||
*p++ = '"';
|
||||
} else {
|
||||
/* " -> \" */
|
||||
if (p == end)
|
||||
goto bail;
|
||||
*p++ = '\\';
|
||||
if (p == end)
|
||||
goto bail;
|
||||
*p++ = '"';
|
||||
}
|
||||
break;
|
||||
case '&' :
|
||||
case '|' :
|
||||
case '(' :
|
||||
case ')' :
|
||||
case '<' :
|
||||
case '>' :
|
||||
case '^' :
|
||||
/* reserved chars, they need to be quoted with ^ */
|
||||
if (has_quote) {
|
||||
if (p == end)
|
||||
goto bail;
|
||||
*p++ = c;
|
||||
} else {
|
||||
if (p == end)
|
||||
goto bail;
|
||||
*p++ = '^';
|
||||
if (p == end)
|
||||
goto bail;
|
||||
*p++ = c;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* unquoted */
|
||||
if (p == end)
|
||||
goto bail;
|
||||
*p++ = c;
|
||||
break;
|
||||
#else
|
||||
case 'a' ... 'z' :
|
||||
case 'A' ... 'Z' :
|
||||
case '0' ... '9' :
|
||||
case ',' :
|
||||
case '.' :
|
||||
case '_' :
|
||||
case '+' :
|
||||
case ':' :
|
||||
case '@' :
|
||||
case '%' :
|
||||
case '/' :
|
||||
case '-' :
|
||||
/* safe chars for all shells, unquoted */
|
||||
if (p == end)
|
||||
goto bail;
|
||||
*p++ = c;
|
||||
break;
|
||||
default:
|
||||
/* all the others are quoted with \ */
|
||||
if (p == end)
|
||||
goto bail;
|
||||
*p++ = '\\';
|
||||
if (p == end)
|
||||
goto bail;
|
||||
*p++ = c;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
++str;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (has_quote) {
|
||||
if (p == end)
|
||||
goto bail;
|
||||
*p++ = '"';
|
||||
}
|
||||
#endif
|
||||
|
||||
/* put final 0 */
|
||||
if (p == end)
|
||||
goto bail;
|
||||
*p = 0;
|
||||
|
||||
return begin;
|
||||
|
||||
bail:
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal("Quote too long\n");
|
||||
exit(EXIT_FAILURE);
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
char* polish(char* s)
|
||||
{
|
||||
char* i = s;
|
||||
|
|
|
|||
|
|
@ -216,7 +216,7 @@ void printp(double v, size_t pad);
|
|||
#define ESC_MAX (PATH_MAX*2+1)
|
||||
|
||||
/**
|
||||
* Escape a string.
|
||||
* Escape a string for the log.
|
||||
*
|
||||
* \param buffer Preallocated buffer of ESC_MAX size.
|
||||
*
|
||||
|
|
@ -224,6 +224,16 @@ void printp(double v, size_t pad);
|
|||
*/
|
||||
const char* esc(const char* str, char* buffer);
|
||||
|
||||
#define QUOTE_MAX (PATH_MAX*2+1)
|
||||
|
||||
/**
|
||||
* Quote a string for the shell.
|
||||
*
|
||||
* \param prefix Char to prefix at the string.
|
||||
* \param buffer Preallocated buffer of QUOTE_MAX size.
|
||||
*/
|
||||
const char* quote(char prefix, const char* str, char* buffer);
|
||||
|
||||
/**
|
||||
* Polish a string.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta
|
|||
unsigned silent_error;
|
||||
unsigned io_error;
|
||||
char esc_buffer[ESC_MAX];
|
||||
char quote_buffer[QUOTE_MAX];
|
||||
|
||||
/* maps the disks to handles */
|
||||
handle = handle_mapping(state, &diskmax);
|
||||
|
|
@ -194,7 +195,7 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta
|
|||
log_tag("error:%u:%s:%s: Open error. %s\n", i, disk->name, esc(file->sub, esc_buffer), strerror(errno));
|
||||
log_fatal("WARNING! Unexpected open error in a data disk, it isn't possible to sync.\n");
|
||||
log_fatal("Ensure that file '%s' can be accessed.\n", handle[j].path);
|
||||
log_fatal("Stopping to allow recovery. Try with 'snapraid check -f %s'\n", file->sub);
|
||||
log_fatal("Stopping to allow recovery. Try with 'snapraid check -f %s'\n", quote('/', file->sub, quote_buffer));
|
||||
++error;
|
||||
goto bail;
|
||||
/* LCOV_EXCL_STOP */
|
||||
|
|
@ -238,7 +239,7 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta
|
|||
log_tag("error:%u:%s:%s: Read error at position %u. %s\n", i, disk->name, esc(file->sub, esc_buffer), file_pos, strerror(errno));
|
||||
log_fatal("WARNING! Unexpected read error in a data disk, it isn't possible to sync.\n");
|
||||
log_fatal("Ensure that file '%s' can be read.\n", handle[j].path);
|
||||
log_fatal("Stopping to allow recovery. Try with 'snapraid check -f %s'\n", file->sub);
|
||||
log_fatal("Stopping to allow recovery. Try with 'snapraid check -f %s'\n", quote('/', file->sub, quote_buffer));
|
||||
++error;
|
||||
goto bail;
|
||||
/* LCOV_EXCL_STOP */
|
||||
|
|
@ -480,6 +481,7 @@ static void sync_data_reader(struct snapraid_worker* worker, struct snapraid_tas
|
|||
unsigned char* buffer = task->buffer;
|
||||
int ret;
|
||||
char esc_buffer[ESC_MAX];
|
||||
char quote_buffer[QUOTE_MAX];
|
||||
|
||||
/* if the disk position is not used */
|
||||
if (!disk) {
|
||||
|
|
@ -570,7 +572,7 @@ static void sync_data_reader(struct snapraid_worker* worker, struct snapraid_tas
|
|||
log_tag("error:%u:%s:%s: Open error. %s\n", blockcur, disk->name, esc(task->file->sub, esc_buffer), strerror(errno));
|
||||
log_fatal("WARNING! Unexpected open error in a data disk, it isn't possible to sync.\n");
|
||||
log_fatal("Ensure that file '%s' can be accessed.\n", handle->path);
|
||||
log_fatal("Stopping to allow recovery. Try with 'snapraid check -f %s'\n", task->file->sub);
|
||||
log_fatal("Stopping to allow recovery. Try with 'snapraid check -f %s'\n", quote('/', task->file->sub, quote_buffer));
|
||||
task->state = TASK_STATE_ERROR;
|
||||
return;
|
||||
/* LCOV_EXCL_STOP */
|
||||
|
|
@ -612,7 +614,7 @@ static void sync_data_reader(struct snapraid_worker* worker, struct snapraid_tas
|
|||
log_tag("error:%u:%s:%s: Read error at position %u. %s\n", blockcur, disk->name, esc(task->file->sub, esc_buffer), task->file_pos, strerror(errno));
|
||||
log_fatal("WARNING! Unexpected read error in a data disk, it isn't possible to sync.\n");
|
||||
log_fatal("Ensure that file '%s' can be read.\n", handle->path);
|
||||
log_fatal("Stopping to allow recovery. Try with 'snapraid check -f %s'\n", task->file->sub);
|
||||
log_fatal("Stopping to allow recovery. Try with 'snapraid check -f %s'\n", quote('/', task->file->sub, quote_buffer));
|
||||
task->state = TASK_STATE_ERROR;
|
||||
return;
|
||||
/* LCOV_EXCL_STOP */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue