]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
added count argument to %file.tail(). and use it in tests
authorAlan T. DeKok <aland@freeradius.org>
Mon, 16 Oct 2023 16:49:49 +0000 (12:49 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Mon, 16 Oct 2023 16:49:49 +0000 (12:49 -0400)
doc/antora/modules/reference/pages/xlat/file.adoc
src/lib/unlang/xlat_builtin.c
src/tests/modules/linelog/linelog-escapes.unlang
src/tests/xlat/file.txt

index 000a7d8f34dfc20a136db00fd5851b42c3f2a2d4..23471256cdbb893b584fb2b0e4e1eaf40dea3858 100644 (file)
@@ -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)
 ----
 ====
 
index fc058d8b681638a7ca79ca4022b98082bb92a55a..cc044bc0f6bdfa4fa899de91a3d8399397d51e32 100644 (file)
@@ -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);
index 2ce3be0d00d538e7996f489f9db57b89fe2a5a29..c9946e0ff7b10162dbe5145ea37a77daf2ce9c72 100644 (file)
@@ -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') {
index 0bbad01122f130665c7e5e289c37645958277e35..9bbd91945c01a9e3ddc5a54e068bffc43a6764ee 100644 (file)
@@ -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}