diff --git a/HISTORY b/HISTORY index f9d57fc6..9f9d9806 100644 --- a/HISTORY +++ b/HISTORY @@ -19,6 +19,8 @@ SnapRAID HISTORY * In "fix", if a previous fixing attempt was made resulting in a .unrecoverable file, uses this file as starting point for the new attempt. + * In the log file name allow the use of the '>>', %D, %T modifiers + to select append mode, and to insert the date and time in the name. * New source code organization. The RAID engine is now an external component usable also in other projects. diff --git a/Makefile.am b/Makefile.am index f138604b..c6b3a18a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -101,7 +101,7 @@ man_MANS = snapraid.1 clean-local: rm -f valgrind.log callgrind.log cachegrind.log rm -rf test - rm -f test.log output.log + rm -f test*.log output.log rm -f *.gcda *.gcno *.gcov rm -rf cov rm -f lcov.info @@ -144,12 +144,16 @@ check-local: $(TESTENV) ./snapraid$(EXEEXT) --test-skip-device -c $(CONF) status echo --- Run the speed test $(TESTENV) ./snapraid$(EXEEXT) --test-skip-device -T - echo --- As empty, sync and check forcing murmur3 + echo --- Some commands with empty array $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -v -c $(CONF) diff $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -v -c $(CONF) dup $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -v -c $(CONF) list > output.log $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) --test-force-murmur3 sync $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) status + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) status -l ">&1" + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) status -l ">&2" + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) status -l ">>test.log" + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) status -l test-%D-%T.log if HAVE_SYMLINK $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(PAR1) pool endif diff --git a/snapraid.1 b/snapraid.1 index 33fc2758..3014a640 100644 --- a/snapraid.1 +++ b/snapraid.1 @@ -820,6 +820,10 @@ and you\(cqll get only a summary at the end of the operations. When checking and fixing this allows to keep separated the possible huge list of errors from the human readable output. +If the specified FILE path start with \(cq>>\(cq the file is opened +in append mode. Inside the path, occurrences of %D and %T are +replaced with the date and time in the format YYYYMMDD and +HHMMSS. .TP .B \-s, \-\-start BLKSTART Starts the processing from the specified diff --git a/snapraid.c b/snapraid.c index 724dfecb..92dd008c 100644 --- a/snapraid.c +++ b/snapraid.c @@ -86,6 +86,105 @@ void memory(void) printf("Using %u MiB of memory.\n", (unsigned)(malloc_counter() / 1024 / 1024)); } +void log_open(const char* log) +{ + char path[PATH_MAX]; + const char* mode; + char text_T[32]; + char text_D[32]; + time_t t; + struct tm* tm; + + /* if no log file is specified, don't output */ + if (log == 0) { +#ifdef _WIN32 + log = "NUL"; +#else + log = "/dev/null"; +#endif + } + + t = time(0); + tm = localtime(&t); + if (tm) { + strftime(text_T, sizeof(text_T), "%H%M%S", tm); + strftime(text_D, sizeof(text_T), "%Y%m%d", tm); + } else { + strcpy(text_T, "invalid"); + strcpy(text_D, "invalid"); + } + + /* file mode */ + mode = "wt"; + if (*log == '>') { + ++log; + + if (*log == '>') { + mode = "at"; + ++log; + } + + if (log[0] == '&' && log[1] == '1') { + stdlog = stdout; + return; + } + + if (log[0] == '&' && log[1] == '2') { + stdlog = stderr; + return; + } + } + + /* process the path */ + for(*path=0;*log!=0;) { + switch (*log) { + case '%' : + ++log; + switch (*log) { + case '%' : + pathcatc(path, sizeof(path), '%'); + break; + case 'T' : + pathcat(path, sizeof(path), text_T); + break; + case 'D' : + pathcat(path, sizeof(path), text_D); + break; + default: + /* LCOV_EXCL_START */ + fprintf(stderr, "Invalid type specifier '%c' in the log file.\n", *log); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } + break; + default: + pathcatc(path, sizeof(path), *log); + break; + } + ++log; + } + + stdlog = fopen(path, mode); + if (!stdlog) { + /* LCOV_EXCL_START */ + fprintf(stderr, "Error opening the log file '%s'. %s.\n", path, strerror(errno)); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } +} + +void log_close(const char* log) +{ + if (stdlog != stdout && stdlog != stderr) { + if (fclose(stdlog) != 0) { + /* LCOV_EXCL_START */ + fprintf(stderr, "Error closing the log file '%s'. %s.\n", log, strerror(errno)); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } + } +} + #define OPT_TEST_SKIP_SELF 256 #define OPT_TEST_KILL_AFTER_SYNC 257 #define OPT_TEST_EXPECT_UNRECOVERABLE 258 @@ -584,27 +683,8 @@ int main(int argc, char* argv[]) } } - /* if no log file is specified, don't output */ - if (log == 0) { -#ifdef _WIN32 - log = "NUL"; -#else - log = "/dev/null"; -#endif - } - if (strcmp(log, "1") == 0) { - stdlog = stdout; - } else if (strcmp(log, "2") == 0) { - stdlog = stderr; - } else { - stdlog = fopen(log, "wt"); - if (!stdlog) { - /* LCOV_EXCL_START */ - fprintf(stderr, "Error opening the log file '%s'. %s.\n", log, strerror(errno)); - exit(EXIT_FAILURE); - /* LCOV_EXCL_STOP */ - } - } + /* open the log file */ + log_open(log); if (!opt.skip_self) selftest(); @@ -786,14 +866,7 @@ int main(int argc, char* argv[]) } /* close log file */ - if (stdlog != stdout && stdlog != stderr) { - if (fclose(stdlog) != 0) { - /* LCOV_EXCL_START */ - fprintf(stderr, "Error closing the log file '%s'. %s.\n", log, strerror(errno)); - exit(EXIT_FAILURE); - /* LCOV_EXCL_STOP */ - } - } + log_close(log); #if HAVE_LOCKFILE if (!opt.skip_lock) { diff --git a/snapraid.d b/snapraid.d index f90bff55..59a7fd60 100644 --- a/snapraid.d +++ b/snapraid.d @@ -586,6 +586,10 @@ Options When checking and fixing this allows to keep separated the possible huge list of errors from the human readable output. + If the specified path starts with '>>' the file is opened + in append mode. Occurrences of %D and %T in the name are + replaced with the date and time in the format YYYYMMDD and + HHMMSS. -s, --start BLKSTART Starts the processing from the specified diff --git a/snapraid.txt b/snapraid.txt index 31dc3e0a..e109434e 100644 --- a/snapraid.txt +++ b/snapraid.txt @@ -631,6 +631,10 @@ SnapRAID provides the following options: When checking and fixing this allows to keep separated the possible huge list of errors from the human readable output. + If the specified path starts with '>>' the file is opened + in append mode. Occurrences of %D and %T in the name are + replaced with the date and time in the format YYYYMMDD and + HHMMSS. -s, --start BLKSTART Starts the processing from the specified diff --git a/state.c b/state.c index e0dd2013..5587310a 100644 --- a/state.c +++ b/state.c @@ -347,6 +347,8 @@ void state_config(struct snapraid_state* state, const char* path, const char* co unsigned line; tommy_node* i; unsigned l; + time_t t; + struct tm* tm; /* copy the options */ state->opt = *opt; @@ -357,7 +359,16 @@ void state_config(struct snapraid_state* state, const char* path, const char* co state->command = command; + t = time(0); + tm = localtime(&t); + fprintf(stdlog, "version:%s\n", PACKAGE_VERSION); + fprintf(stdlog, "unixtime:%"PRIi64"\n", (int64_t)t); + if (tm) { + char datetime[64]; + strftime(datetime, sizeof(datetime), "%F %T", tm); + fprintf(stdlog, "time:%s\n", datetime); + } fprintf(stdlog, "conf:%s\n", path); fflush(stdlog); diff --git a/util.c b/util.c index 692abb19..e48ff2d7 100644 --- a/util.c +++ b/util.c @@ -1267,6 +1267,21 @@ void pathcat(char* dst, size_t size, const char* src) memcpy(dst + dst_len, src, src_len + 1); } +void pathcatc(char* dst, size_t size, char c) +{ + size_t dst_len = strlen(dst); + + if (dst_len + 2 > size) { + /* LCOV_EXCL_START */ + fprintf(stderr, "Path too long\n"); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } + + dst[dst_len] = c; + dst[dst_len + 1] = 0; +} + void pathimport(char* dst, size_t size, const char* src) { pathcpy(dst, size, src); diff --git a/util.h b/util.h index e528ec63..a6ed2e13 100644 --- a/util.h +++ b/util.h @@ -403,6 +403,12 @@ void pathcpy(char* dst, size_t size, const char* src); */ void pathcat(char* dst, size_t size, const char* src); +/** + * Concatenates a path limiting the size. + * Aborts if too long. + */ +void pathcatc(char* dst, size_t size, char c); + /** * Imports a path limiting the size. * In Windows all the backslash are converted to the C standard of forward slash.