[DRBD-cvs] svn commit by lars - r2969 - branches/drbd-8.0/user -
fixes mainly for parsing a meta-data dump file on resto
drbd-cvs at lists.linbit.com
drbd-cvs at lists.linbit.com
Sat Jul 14 22:56:42 CEST 2007
Author: lars
Date: 2007-07-14 22:56:41 +0200 (Sat, 14 Jul 2007)
New Revision: 2969
Modified:
branches/drbd-8.0/user/Makefile
branches/drbd-8.0/user/drbdmeta.c
branches/drbd-8.0/user/drbdmeta_parser.h
branches/drbd-8.0/user/drbdmeta_scanner.fl
Log:
fixes mainly for parsing a meta-data dump file on restore-md
* added new verify-dump command,
which does the same parsing as restore-md,
without actually touching the on-disk meta-data
* improved the scanner to explicitly match all possible input,
introduced TK_INVALID, TK_INVALID_CHAR
* let flex count the input lines for us
* be more tolerant: include "\r" in ignored whitespace
* be less tolerant: strings may only be 20 characters long
and must not include [\r\n]; (there is currently only the version tag,
which is currently only three chars long)
* improve on the on the scanner and parser error messages:
up to now we had the embarrasing "Parse error: expected $something.",
which is not useful at all. now we get the line number, and the unexpected
or invalid token reportet as well.
* add fflush(stdout) and indent the SIGSEGV/BUS handler.
CAUTION:
I did not actually restore any meta data yet,
only tested various valid and invalid inputs
with the new verify-dump command.
Will do real-life tests early next week again...
So it is possible, while unlikely,
that this broke the restore-md functionality further,
due to me being stupid somewhere...
Modified: branches/drbd-8.0/user/Makefile
===================================================================
--- branches/drbd-8.0/user/Makefile 2007-07-12 15:45:09 UTC (rev 2968)
+++ branches/drbd-8.0/user/Makefile 2007-07-14 20:56:41 UTC (rev 2969)
@@ -45,14 +45,15 @@
drbdadm: $(drbdadm-obj)
$(CC) -o $@ $^
+# for debugging:
+# LANG=C LC_ALL=C flex -d -b -s -odrbdadm_scanner.c drbdadm_scanner.fl
+
drbdadm_scanner.c: drbdadm_scanner.fl drbdadm_parser.h
flex -s -odrbdadm_scanner.c drbdadm_scanner.fl
drbdmeta_scanner.c: drbdmeta_scanner.fl drbdmeta_parser.h
- flex -odrbdmeta_scanner.c drbdmeta_scanner.fl
+ flex -s -odrbdmeta_scanner.c drbdmeta_scanner.fl
-# for debug: flex -d -s -odrbdadm_scanner.c drbdadm_scanner.fl
-
drbdsetup: $(drbdsetup-obj)
$(CC) -o $@ $^
Modified: branches/drbd-8.0/user/drbdmeta.c
===================================================================
--- branches/drbd-8.0/user/drbdmeta.c 2007-07-12 15:45:09 UTC (rev 2968)
+++ branches/drbd-8.0/user/drbdmeta.c 2007-07-14 20:56:41 UTC (rev 2969)
@@ -777,6 +777,7 @@
int meta_show_gi(struct format *cfg, char **argv, int argc);
int meta_dump_md(struct format *cfg, char **argv, int argc);
int meta_restore_md(struct format *cfg, char **argv, int argc);
+int meta_verify_dump_file(struct format *cfg, char **argv, int argc);
int meta_create_md(struct format *cfg, char **argv, int argc);
int meta_wipe_md(struct format *cfg, char **argv, int argc);
int meta_outdate(struct format *cfg, char **argv, int argc);
@@ -791,6 +792,7 @@
{"show-gi", 0, meta_show_gi, 1},
{"dump-md", 0, meta_dump_md, 1},
{"restore-md", "file", meta_restore_md, 1},
+ {"verify-dump", "file", meta_verify_dump_file, 1},
{"create-md", 0, meta_create_md, 1},
{"wipe-md", 0, meta_wipe_md, 1},
{"outdate", 0, meta_outdate, 1},
@@ -1772,15 +1774,90 @@
return cfg->ops->close(cfg);
}
-void md_parse_error(const char *etext)
+void md_parse_error(int expected_token, int seen_token,const char *etext)
{
- fprintf(stderr,"Parse error '%s' expected.",etext);
+ if (!etext) {
+ switch(expected_token) {
+ /* leading space indicates to strip off "expected" below */
+ default : etext = " invalid/unexpected token!"; break;
+ case 0 : etext = "end of file"; break;
+ case ';': etext = "semicolon (;)"; break;
+ case '{': etext = "opening brace ({)"; break;
+ case '}': etext = "closing brace (})"; break;
+ case TK_BM:
+ etext = "keyword 'bm'"; break;
+ case TK_BM_BYTE_PER_BIT:
+ etext = "keyword 'bm-byte-per-bit'"; break;
+ case TK_DEVICE_UUID:
+ etext = "keyword 'device-uuid'"; break;
+ case TK_FLAGS:
+ etext = "keyword 'flags'"; break;
+ case TK_GC:
+ etext = "keyword 'gc'"; break;
+ case TK_LA_SIZE:
+ etext = "keyword 'la-size-sect'"; break;
+ case TK_TIMES:
+ etext = "keyword 'times'"; break;
+ case TK_UUID:
+ etext = "keyword 'uuid'"; break;
+ case TK_VERSION:
+ etext = "keyword 'version'"; break;
+ case TK_NUM:
+ etext = "number ([0-9], up to 20 digits)"; break;
+ case TK_STRING:
+ etext = "short quoted string "
+ "(\"..up to 20 characters, no newline..\")";
+ break;
+ case TK_U32:
+ etext = "an 8-digit hex number"; break;
+ case TK_U64:
+ etext = "a 16-digit hex number"; break;
+ }
+ }
+ fflush(stdout);
+ fprintf(stderr,"Parse error in line %u: %s%s",
+ yylineno, etext,
+ (etext[0] == ' ' ? ":" : " expected")
+ );
+
+ switch(seen_token) {
+ case 0:
+ fprintf(stderr, ", but end of file encountered\n"); break;
+
+ case 1 ... 58: /* ord(';') == 58 */
+ case 60 ... 122: /* ord('{') == 123 */
+ case 124: /* ord('}') == 125 */
+ case 126 ... 257:
+ /* oopsie. these should never be returned! */
+ fprintf(stderr, "; got token value %u (this should never happen!)\n", seen_token); break;
+ break;
+
+ case TK_INVALID_CHAR:
+ fprintf(stderr,"; got invalid input character '\\x%02x' [%c]\n",
+ (unsigned char)yylval.txt[0], yylval.txt[0]);
+ break;
+ case ';': case '{': case '}':
+ fprintf(stderr, ", not '%c'\n", seen_token); break;
+ case TK_NUM:
+ case TK_U32:
+ case TK_U64:
+ fprintf(stderr, ", not some number\n"); break;
+ case TK_INVALID:
+ /* already reported by scanner */
+ fprintf(stderr,"\n"); break;
+ default:
+ fprintf(stderr, ", not '%s'\n", yylval.txt);
+ }
exit(10);
}
-#define EXP(TOKEN) if(yylex() != TOKEN) md_parse_error( #TOKEN );
+static void EXP(int expected_token) {
+ int tok = yylex();
+ if (tok != expected_token)
+ md_parse_error(expected_token, tok, NULL);
+}
-int meta_restore_md(struct format *cfg, char **argv, int argc)
+int verify_dumpfile_or_restore(struct format *cfg, char **argv, int argc, int parse_only)
{
int i,times;
int err;
@@ -1794,7 +1871,7 @@
}
}
- if (!cfg->ops->open(cfg)) {
+ if (!parse_only && !cfg->ops->open(cfg)) {
if (!confirmed("Valid meta-data in place, overwrite?"))
return -1;
}
@@ -1837,29 +1914,49 @@
bm = (le_u64 *)cfg->on_disk.bm;
i = 0;
while(1) {
- switch(yylex()) {
+ int tok = yylex();
+ switch(tok) {
case TK_U64:
+ EXP(';');
+ /* NOTE:
+ * even though this EXP(';'); already advanced
+ * to the next token, yylval will *not* be updated
+ * for * ';', so it is still valid.
+ *
+ * This seemed to be the least ugly way to implement a
+ * "parse_only" functionality without ugly if-branches
+ * or the maintenance nightmare of code duplication */
+ if (parse_only) break;
bm[i].le = cpu_to_le64(yylval.u64);
i++;
- EXP(';');
break;
case TK_NUM:
EXP(TK_TIMES);
times = yylval.u64;
EXP(TK_U64);
+ EXP(';');
+ if (parse_only) break;
value.le = cpu_to_le64(yylval.u64);
- EXP(';');
while(times--) bm[i++] = value;
break;
case '}':
goto break_loop;
default:
- md_parse_error("TK_U64, TK_NUM or }");
+ md_parse_error(0 /* ignored, since etext is set */,
+ tok, "repeat count, 16-digit hex number, or closing brace (})");
goto break_loop;
}
}
break_loop:
+ /* there should be no trailing garbage in the input file */
+ EXP(0);
+
+ if (parse_only) {
+ printf("input file parsed ok\n");
+ return 0;
+ }
+
err = cfg->ops->md_cpu_to_disk(cfg);
err = cfg->ops->close(cfg) || err;
if (err) {
@@ -1872,8 +1969,16 @@
return 0;
}
-#undef EXP
+int meta_restore_md(struct format *cfg, char **argv, int argc)
+{
+ return verify_dumpfile_or_restore(cfg,argv,argc,0);
+}
+int meta_verify_dump_file(struct format *cfg, char **argv, int argc)
+{
+ return verify_dumpfile_or_restore(cfg,argv,argc,1);
+}
+
int md_convert_07_to_08(struct format *cfg)
{
int i,j=1;
@@ -2446,15 +2551,16 @@
struct sigaction sa;
static void signal_handler(int signo)
{
- fprintf(stderr,"%s\nThis feels like a bug.\n",
- (signo == SIGBUS)
- ? "SIGBUS: out of band access to the mmaped area!"
- : "SIGSEGV!");
- fprintf(stderr,"debug hint: last memset: %s:%u: @%p %llu\n"
- "Sorry.\n",
- last_memset_func, last_memset_line,
- last_memset_target, (unsigned long long)last_memset_n);
- exit(128 | signo);
+ fflush(stdout);
+ fprintf(stderr,"%s\nThis feels like a bug.\n",
+ (signo == SIGBUS)
+ ? "SIGBUS: out of band access to the mmaped area!"
+ : "SIGSEGV!");
+ fprintf(stderr,"debug hint: last memset: %s:%u: @%p %llu\n"
+ "Sorry.\n",
+ last_memset_func, last_memset_line,
+ last_memset_target, (unsigned long long)last_memset_n);
+ exit(128 | signo);
}
int main(int argc, char **argv)
Modified: branches/drbd-8.0/user/drbdmeta_parser.h
===================================================================
--- branches/drbd-8.0/user/drbdmeta_parser.h 2007-07-12 15:45:09 UTC (rev 2968)
+++ branches/drbd-8.0/user/drbdmeta_parser.h 2007-07-14 20:56:41 UTC (rev 2969)
@@ -8,6 +8,7 @@
#define YY_NO_UNPUT 1
extern YYSTYPE yylval;
+extern int yylineno;
enum yytokentype {
TK_STRING = 258,
@@ -23,6 +24,8 @@
TK_DEVICE_UUID,
TK_TIMES,
TK_FLAGS,
+ TK_INVALID,
+ TK_INVALID_CHAR,
};
/* avoid compiler warnings about implicit declaration */
Modified: branches/drbd-8.0/user/drbdmeta_scanner.fl
===================================================================
--- branches/drbd-8.0/user/drbdmeta_scanner.fl 2007-07-12 15:45:09 UTC (rev 2968)
+++ branches/drbd-8.0/user/drbdmeta_scanner.fl 2007-07-14 20:56:41 UTC (rev 2969)
@@ -4,45 +4,74 @@
#include "drbdmeta_parser.h"
static void unescape(void);
+static void bad_token(char*);
//#define DP printf("%s ",yytext);
#define DP
+#define CP yylval.txt=yytext
#define YY_NO_UNPUT 1
static void yyunput (int c, register char * yy_bp ) __attribute((unused));
%}
%option noyywrap
+%option yylineno
-WS [ \t\n]
+/* remember to avoid backing up.
+ * tell user about bad/unexpected tokens. */
+
+OP [{};]
+WS [ \r\t\n]
COMMENT \#[^\n]*
-NUM [0-9]{1,10}
+
+NUM [0-9]{1,20}
+NUM_TOO_LONG {NUM}[0-9]
+
U64 0x[0-9A-Fa-f]{16}
U32 0x[0-9A-Fa-f]{8}
-OP [{};]
-STRING \"[^\"]*\"
+INVALID_HEX 0x[0-9A-Fa-f]{0,17}
+STRING \"[^\"\r\n]{1,20}\"
+EMPTY_STRING \"\"?
+INVALID_STRING \"[^\"\r\n]{1,20}
+
+INVALID_TOKEN [-_a-zA-Z0-9]{1,100}
+INVALID_CHAR [^-_a-zA-Z0-9 \t\r\n\";{}]
+
%%
-{WS}
-{COMMENT}
+{WS} /* skip silently */
+{COMMENT} /* skip silently */
{OP} DP; return yytext[0];
-{STRING} unescape(); yylval.txt=yytext; DP; return TK_STRING;
+{STRING} unescape(); DP; CP; return TK_STRING;
{U64} yylval.u64 = strto_u64(yytext, NULL, 16); DP; return TK_U64;
{U32} yylval.u64 = strto_u64(yytext, NULL, 16); DP; return TK_U32;
{NUM} yylval.u64 = strto_u64(yytext, NULL, 10); DP; return TK_NUM;
-gc DP; return TK_GC;
-bm DP; return TK_BM;
-uuid DP; return TK_UUID;
-version DP; return TK_VERSION;
-la-size-sect DP; return TK_LA_SIZE;
-bm-byte-per-bit DP; return TK_BM_BYTE_PER_BIT;
-device-uuid DP; return TK_DEVICE_UUID;
-times DP; return TK_TIMES;
-flags DP; return TK_FLAGS;
+gc DP; CP; return TK_GC;
+bm DP; CP; return TK_BM;
+uuid DP; CP; return TK_UUID;
+version DP; CP; return TK_VERSION;
+la-size-sect DP; CP; return TK_LA_SIZE;
+bm-byte-per-bit DP; CP; return TK_BM_BYTE_PER_BIT;
+device-uuid DP; CP; return TK_DEVICE_UUID;
+times DP; CP; return TK_TIMES;
+flags DP; CP; return TK_FLAGS;
+{INVALID_STRING} CP; bad_token("invalid string"); return TK_INVALID;
+{EMPTY_STRING} CP; bad_token("invalid string"); return TK_INVALID;
+{INVALID_HEX} CP; bad_token("invalid hex number (only 8 or 16 hex digits accepted)"); return TK_INVALID;
+{NUM_TOO_LONG} CP; bad_token("number too big"); return TK_INVALID;
+{INVALID_TOKEN} CP; bad_token("unknown token"); return TK_INVALID;
+{INVALID_CHAR} CP; return TK_INVALID_CHAR;
+
%%
+static void bad_token(char *msg)
+{
+ fflush(stdout);
+ fprintf(stderr,"line %u: %s: %s ...\n", yylineno, msg, yytext);
+}
+
static void unescape(void)
{
/* backslash escapes from string */
More information about the drbd-cvs
mailing list