Hello David,
+Agree. However, it would nice to update the sentence below if I understand it correctly."+ Comments, whitespace and continuations are handled in the same way as in" pg_hba.conf
In the attached v3, I've tried to clarify comments and doc about tokenization rules relating to comments, strings and continuations.
-- Fabien.
diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml index 5f1eec78fb..5d6412de9b 100644 --- a/doc/src/sgml/client-auth.sgml +++ b/doc/src/sgml/client-auth.sgml @@ -77,13 +77,16 @@ The general format of the <filename>pg_hba.conf</filename> file is a set of records, one per line. Blank lines are ignored, as is any text after the <literal>#</literal> comment character. - Records cannot be continued across lines. + Lines ending with a backslash are logically continued on the next + line, so a record can span several lines. A record is made up of a number of fields which are separated by spaces and/or tabs. Fields can contain white space if the field value is double-quoted. Quoting one of the keywords in a database, user, or address field (e.g., <literal>all</literal> or <literal>replication</literal>) makes the word lose its special meaning, and just match a database, user, or host with that name. + If a continuation occurs within a quoted text or a comment, + the quoted text or comment are continued. </para> <para> @@ -821,7 +824,7 @@ local db1,db2,@demodbs all md5 <synopsis> <replaceable>map-name</replaceable> <replaceable>system-username</replaceable> <replaceable>database-username</replaceable> </synopsis> - Comments and whitespace are handled in the same way as in + Comments, whitespace and continuations are handled in the same way as in <filename>pg_hba.conf</filename>. The <replaceable>map-name</replaceable> is an arbitrary name that will be used to refer to this mapping in <filename>pg_hba.conf</filename>. The other diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c index da5189a4fa..e88758c5aa 100644 --- a/src/backend/libpq/hba.c +++ b/src/backend/libpq/hba.c @@ -166,11 +166,17 @@ pg_isblank(const char c) /* * Grab one token out of the string pointed to by *lineptr. * - * Tokens are strings of non-blank - * characters bounded by blank characters, commas, beginning of line, and - * end of line. Blank means space or tab. Tokens can be delimited by - * double quotes (this allows the inclusion of blanks, but not newlines). - * Comments (started by an unquoted '#') are skipped. + * Tokens are strings of non-blank characters bounded by blank characters, + * commas, beginning of line, and end of line. Blank means space or tab. + * + * Tokens can be delimited by double quotes (this allows the inclusion of + * blanks or '#', but not newlines). If a continuations occured within the + * quoted text, the quoted text is continued on the next line. There is no + * escape mechanism, thus character '"' cannot be part of a token. + * + * Comments (started by an unquoted '#') are skipped, i.e. the remainder + * of the line is ignored. If a line with a comment was backslash-continued, + * the continuated text is part of the comment, thus ignored as well. * * The token, if any, is returned at *buf (a buffer of size bufsz), and * *lineptr is advanced past the token. @@ -486,8 +492,43 @@ tokenize_file(const char *filename, FILE *file, List **tok_lines, int elevel) char *lineptr; List *current_line = NIL; char *err_msg = NULL; + char *cur = rawline; + int len = sizeof(rawline); + int continuations = 0; - if (!fgets(rawline, sizeof(rawline), file)) + /* read input and handle simplistic backslash continuations */ + while ((cur = fgets(cur, len, file)) != NULL) + { + int curlen = strlen(cur); + char *curend = cur + curlen - 1; + + if (curlen == len - 1) + { + /* Line too long! */ + ereport(elevel, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("authentication file line too long"), + errcontext("line %d of configuration file \"%s\"", + line_number + continuations, filename))); + err_msg = "authentication file line too long"; + } + + /* Strip trailing linebreak from rawline */ + while (curend >= cur && (*curend == '\n' || *curend == '\r')) + *curend-- = '\0'; + + /* empty or not a continuation, we are done */ + if (curend < cur || *curend != '\\') + break; + + /* else we have a continuation, just remove it and loop */ + continuations++; + *curend = '\0'; + len -= (curend - cur); + cur = curend; + } + + if (cur == NULL) { int save_errno = errno; @@ -501,21 +542,6 @@ tokenize_file(const char *filename, FILE *file, List **tok_lines, int elevel) filename, strerror(save_errno)); rawline[0] = '\0'; } - if (strlen(rawline) == MAX_LINE - 1) - { - /* Line too long! */ - ereport(elevel, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("authentication file line too long"), - errcontext("line %d of configuration file \"%s\"", - line_number, filename))); - err_msg = "authentication file line too long"; - } - - /* Strip trailing linebreak from rawline */ - lineptr = rawline + strlen(rawline) - 1; - while (lineptr >= rawline && (*lineptr == '\n' || *lineptr == '\r')) - *lineptr-- = '\0'; /* Parse fields */ lineptr = rawline; @@ -543,7 +569,7 @@ tokenize_file(const char *filename, FILE *file, List **tok_lines, int elevel) *tok_lines = lappend(*tok_lines, tok_line); } - line_number++; + line_number += continuations + 1; } MemoryContextSwitchTo(oldcxt);