From: Alan T. DeKok Date: Mon, 16 Oct 2023 16:49:49 +0000 (-0400) Subject: added count argument to %file.tail(). and use it in tests X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bce776901aef9c0aea098806827433ebd599bcec;p=thirdparty%2Ffreeradius-server.git added count argument to %file.tail(). and use it in tests --- diff --git a/doc/antora/modules/reference/pages/xlat/file.adoc b/doc/antora/modules/reference/pages/xlat/file.adoc index 000a7d8f34d..23471256cdb 100644 --- a/doc/antora/modules/reference/pages/xlat/file.adoc +++ b/doc/antora/modules/reference/pages/xlat/file.adoc @@ -69,12 +69,14 @@ if (%file.size("/var/log/radius.log") > (((uint64)1) << 20)) { } ---- -== %file.tail(_string_) +== %file.tail(_string_, [ _uint32_ ]) .Return: _string_ This function returns the last line of the file. If the file does not exist, or if the line is more than 256 characters in length, it fails and nothing is returned. +The function takes an optional second argument, which is the number of lines which should be returned. The maximum number of lines which will be returned is limited to 15. + .Returning the first line of a file ==== [source,unlang] @@ -82,6 +84,8 @@ This function returns the last line of the file. If the file does not exist, or string line &line := %file.tail("/var/log/radius.log") + +&line := %file.tail("/var/log/radius.log", 2) ---- ==== diff --git a/src/lib/unlang/xlat_builtin.c b/src/lib/unlang/xlat_builtin.c index fc058d8b681..cc044bc0f6b 100644 --- a/src/lib/unlang/xlat_builtin.c +++ b/src/lib/unlang/xlat_builtin.c @@ -432,11 +432,18 @@ static const char *xlat_file_name(fr_value_box_t *vb) return fr_sbuff_start(path); } -static xlat_arg_parser_t const xlat_func_file_exists_args[] = { +static xlat_arg_parser_t const xlat_func_file_name_args[] = { { .required = true, .type = FR_TYPE_STRING }, XLAT_ARG_PARSER_TERMINATOR }; +static xlat_arg_parser_t const xlat_func_file_name_count_args[] = { + { .required = true, .type = FR_TYPE_STRING }, + { .required = false, .type = FR_TYPE_UINT32 }, + XLAT_ARG_PARSER_TERMINATOR +}; + + static xlat_action_t xlat_func_file_exists(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *args) @@ -546,16 +553,16 @@ static xlat_action_t xlat_func_file_tail(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in) { - fr_value_box_t *dst, *vb; + fr_value_box_t *dst, *vb, *num = NULL; char const *filename; ssize_t len; size_t count = 0; off_t offset; int fd; - int n, r; + int n, r, stop = 2; char *p, *end, *found, buffer[256]; - XLAT_ARGS(in, &vb); + XLAT_ARGS(in, &vb, &num); filename = xlat_file_name(vb); if (!filename) return XLAT_ACTION_FAIL; @@ -597,26 +604,51 @@ static xlat_action_t xlat_func_file_tail(TALLOC_CTX *ctx, fr_dcursor_t *out, n = r = 0; /* be agnostic over CR / LF */ - end = buffer + len; + /* + * Clamp number of lines to a reasonable value. They + * still all have to fit into 256 characters, though. + * + * @todo - have a large thread-local temporary buffer for this stuff. + */ + if (num) { + fr_assert(num->type == FR_TYPE_GROUP); + fr_assert(fr_value_box_list_num_elements(&num->vb_group) == 1); + + num = fr_value_box_list_head(&num->vb_group); + fr_assert(num->type == FR_TYPE_UINT32); + + if (!num->vb_uint32) { + stop = 2; + } else if (num->vb_uint32 < 15) { + stop = num->vb_uint64 + 1; + } else { + stop = 16; + } + } else { + stop = 2; + } + + end = NULL; found = NULL; /* * Nuke any trailing CR/LF */ - p = end - 1; + p = buffer + len - 1; while (p >= buffer) { if (*p == '\r') { r++; - if (r == 2) break; + if (r == stop) break; - end = p; + if (!end) end = p; } else if (*p == '\n') { n++; - if (n == 2) break; - end = p; + if (n == stop) break; + + if (!end) end = p; } else { if (!r) r++; /* if we didn't get a CR/LF at EOF, pretend we did */ @@ -628,6 +660,8 @@ static xlat_action_t xlat_func_file_tail(TALLOC_CTX *ctx, fr_dcursor_t *out, p--; } + if (!end) end = buffer + len; + /* * The buffer was only one line of CR/LF. */ @@ -3658,11 +3692,11 @@ do { \ XLAT_REGISTER_ARGS("cast", xlat_func_cast, FR_TYPE_VOID, xlat_func_cast_args); XLAT_REGISTER_ARGS("concat", xlat_func_concat, FR_TYPE_STRING, xlat_func_concat_args); XLAT_REGISTER_ARGS("explode", xlat_func_explode, FR_TYPE_STRING, xlat_func_explode_args); - XLAT_REGISTER_ARGS("file.exists", xlat_func_file_exists, FR_TYPE_BOOL, xlat_func_file_exists_args); - XLAT_REGISTER_ARGS("file.head", xlat_func_file_head, FR_TYPE_STRING, xlat_func_file_exists_args); - XLAT_REGISTER_ARGS("file.rm", xlat_func_file_rm, FR_TYPE_BOOL, xlat_func_file_exists_args); - XLAT_REGISTER_ARGS("file.size", xlat_func_file_size, FR_TYPE_UINT64, xlat_func_file_exists_args); - XLAT_REGISTER_ARGS("file.tail", xlat_func_file_tail, FR_TYPE_STRING, xlat_func_file_exists_args); + XLAT_REGISTER_ARGS("file.exists", xlat_func_file_exists, FR_TYPE_BOOL, xlat_func_file_name_args); + XLAT_REGISTER_ARGS("file.head", xlat_func_file_head, FR_TYPE_STRING, xlat_func_file_name_args); + XLAT_REGISTER_ARGS("file.rm", xlat_func_file_rm, FR_TYPE_BOOL, xlat_func_file_name_args); + XLAT_REGISTER_ARGS("file.size", xlat_func_file_size, FR_TYPE_UINT64, xlat_func_file_name_args); + XLAT_REGISTER_ARGS("file.tail", xlat_func_file_tail, FR_TYPE_STRING, xlat_func_file_name_count_args); XLAT_REGISTER_ARGS("hmacmd5", xlat_func_hmac_md5, FR_TYPE_OCTETS, xlat_hmac_args); XLAT_REGISTER_ARGS("hmacsha1", xlat_func_hmac_sha1, FR_TYPE_OCTETS, xlat_hmac_args); XLAT_REGISTER_ARGS("integer", xlat_func_integer, FR_TYPE_VOID, xlat_func_integer_args); diff --git a/src/tests/modules/linelog/linelog-escapes.unlang b/src/tests/modules/linelog/linelog-escapes.unlang index 2ce3be0d00d..c9946e0ff7b 100644 --- a/src/tests/modules/linelog/linelog-escapes.unlang +++ b/src/tests/modules/linelog/linelog-escapes.unlang @@ -43,7 +43,7 @@ else { &control.Tmp-String-1 := "foo\nbar" linelog_escapes -&Tmp-String-0 := `/bin/sh -c "tail -n2 $ENV{MODULE_TEST_DIR}/test_escapes.log"` +&Tmp-String-0 := %file.tail("$ENV{MODULE_TEST_DIR}/test_escapes.log", 2) &Tmp-String-1 := "%hex(%{Tmp-String-0})" if (&Tmp-String-1 == '666f6f0a626172') { diff --git a/src/tests/xlat/file.txt b/src/tests/xlat/file.txt index 0bbad01122f..9bbd91945c0 100644 --- a/src/tests/xlat/file.txt +++ b/src/tests/xlat/file.txt @@ -19,5 +19,11 @@ match {baz is good} xlat_expr %file.tail('src/tests/xlat/file/three') match {but it was good} +xlat_expr %file.tail('src/tests/xlat/file/three', 1) +match {but it was good} + +xlat_expr %file.tail('src/tests/xlat/file/three', 2) +match {who was very baaad\012but it was good} + xlat_expr %file.size('src/tests/xlat/file/three') match {64}