Skip to content

Commit 94de31e

Browse files
authored
Merge pull request #6237 from victormlg/strtotime
CFE-3882: Added strtotime policy function
2 parents 335efb8 + 5eaf186 commit 94de31e

3 files changed

Lines changed: 119 additions & 1 deletion

File tree

libpromises/evalfunction.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7597,6 +7597,83 @@ static FnCallResult FnCallStrftime(ARG_UNUSED EvalContext *ctx,
75977597

75987598
/*********************************************************************/
75997599

7600+
static int ParseDate(const char *input_string, time_t *out)
7601+
{
7602+
char date_path[PATH_MAX];
7603+
strncpy(date_path, GetBinDir(), sizeof(date_path) - 1);
7604+
JoinPaths(date_path, sizeof(date_path), "date");
7605+
7606+
char buffer[CF_BUFSIZE];
7607+
int n = snprintf(buffer, sizeof(buffer), "%s --date '%s' +%%s", date_path, input_string);
7608+
7609+
if (n < 0 || (size_t) n >= sizeof(buffer)) {
7610+
Log(LOG_LEVEL_ERR, "Truncation error: input string '%.10s...' is too long (%d >= %zu)",
7611+
input_string, n, sizeof(buffer));
7612+
return -1;
7613+
}
7614+
7615+
FILE *fd = cf_popen(buffer, "r", true);
7616+
if (fd == NULL)
7617+
{
7618+
Log(LOG_LEVEL_ERR, "Couldn't run command: '%s'", buffer);
7619+
return -1;
7620+
}
7621+
7622+
size_t bytes_read = fread(buffer, 1, sizeof(buffer) - 1 , fd);
7623+
buffer[bytes_read] = '\0';
7624+
7625+
if (bytes_read == 0)
7626+
{
7627+
if (ferror(fd))
7628+
{
7629+
Log(LOG_LEVEL_ERR, "Error reading output for '%s'", input_string);
7630+
}
7631+
else if (feof(fd))
7632+
{
7633+
Log(LOG_LEVEL_DEBUG, "No output read for '%s'", input_string);
7634+
}
7635+
fclose(fd);
7636+
return -1;
7637+
}
7638+
fclose(fd);
7639+
7640+
long time_value;
7641+
int ret = StringToLong(buffer, &time_value);
7642+
if (ret != 0)
7643+
{
7644+
LogStringToLongError(buffer, "ParseDate", ret);
7645+
return -1;
7646+
}
7647+
7648+
*out = (time_t) time_value;
7649+
if ((long) *out != time_value)
7650+
{
7651+
Log(LOG_LEVEL_ERR, "Date value '%ld' does not fit in time_t", time_value);
7652+
return -1;
7653+
}
7654+
7655+
return 0;
7656+
}
7657+
7658+
static FnCallResult FnCallStrToTime(ARG_UNUSED EvalContext *ctx, ARG_UNUSED const Policy *policy, const FnCall *fp, const Rlist *finalargs)
7659+
{
7660+
assert(fp != NULL);
7661+
7662+
const char *input_string = RlistScalarValue(finalargs);
7663+
time_t result;
7664+
int ret = ParseDate(input_string, &result);
7665+
7666+
if (ret != 0)
7667+
{
7668+
Log(LOG_LEVEL_ERR, "'%s': Invalid date '%s'", fp->name, input_string);
7669+
return FnFailure();
7670+
}
7671+
7672+
return FnReturnF("%ld", result);
7673+
}
7674+
7675+
/*********************************************************************/
7676+
76007677
static FnCallResult FnCallEval(EvalContext *ctx, ARG_UNUSED const Policy *policy, const FnCall *fp, const Rlist *finalargs)
76017678
{
76027679
if (finalargs == NULL)
@@ -11427,6 +11504,12 @@ static const FnCallArg STRFTIME_ARGS[] =
1142711504
{NULL, CF_DATA_TYPE_NONE, NULL}
1142811505
};
1142911506

11507+
static const FnCallArg STRTOTIME_ARGS[] =
11508+
{
11509+
{CF_ANYSTRING, CF_DATA_TYPE_STRING, "String to parse"},
11510+
{NULL, CF_DATA_TYPE_NONE, NULL}
11511+
};
11512+
1143011513
static const FnCallArg STRING_REPLACE_ARGS[] =
1143111514
{
1143211515
{CF_ANYSTRING, CF_DATA_TYPE_STRING, "Source string"},
@@ -12003,6 +12086,8 @@ const FnCallType CF_FNCALL_TYPES[] =
1200312086
FNCALL_OPTION_NONE, FNCALL_CATEGORY_DATA, SYNTAX_STATUS_NORMAL, DEFAULT_ARGC),
1200412087
FnCallTypeNew("strftime", CF_DATA_TYPE_STRING, STRFTIME_ARGS, &FnCallStrftime, "Format a date and time string",
1200512088
FNCALL_OPTION_NONE, FNCALL_CATEGORY_DATA, SYNTAX_STATUS_NORMAL, DEFAULT_ARGC),
12089+
FnCallTypeNew("strtotime", CF_DATA_TYPE_INT, STRTOTIME_ARGS, &FnCallStrToTime, "Parse a timestamp from a string",
12090+
FNCALL_OPTION_NONE, FNCALL_CATEGORY_DATA, SYNTAX_STATUS_NORMAL, DEFAULT_ARGC),
1200612091
FnCallTypeNew("sublist", CF_DATA_TYPE_STRING_LIST, SUBLIST_ARGS, &FnCallSublist, "Returns arg3 element from either the head or the tail (according to arg2) of list or array or data container arg1.",
1200712092
FNCALL_OPTION_COLLECTING, FNCALL_CATEGORY_DATA, SYNTAX_STATUS_NORMAL, DEFAULT_ARGC),
1200812093
FnCallTypeNew("sysctlvalue", CF_DATA_TYPE_STRING, SYSCTLVALUE_ARGS, &FnCallSysctlValue, "Returns a value for sysctl key arg1 pair",
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#######################################################
2+
#
3+
# Test strtotime function
4+
#
5+
#######################################################
6+
body common control
7+
{
8+
inputs => { "../../default.sub.cf" };
9+
bundlesequence => { default("$(this.promise_filename)") };
10+
version => "1.0";
11+
}
12+
13+
#######################################################
14+
bundle agent test
15+
{
16+
vars:
17+
"some_date" int => strtotime("2009-09-21T00:00:00Z");
18+
"epoch" int => int(1253491200);
19+
20+
classes:
21+
"ok" expression => strcmp("$(epoch)", "$(some_date)");
22+
23+
reports:
24+
ok::
25+
"$(this.promise_filename) Pass";
26+
27+
!ok::
28+
"$(this.promise_filename) FAIL";
29+
}

tests/acceptance/testall

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ CF_CHECK=${CF_CHECK:-} ; export CF_CHECK
106106
CF_RUNAGENT=${CF_RUNAGENT:-} ; export CF_RUNAGENT
107107
RPMVERCMP=${RPMVERCMP:-} ; export RPMVERCMP
108108
DIFF=${DIFF:-} ; export DIFF
109+
DATE=${DATE:-} ; export DATE
109110
LIBTOOL=${LIBTOOL:-} ; export LIBTOOL
110111
INCLUDE_IN_WORKDIR=${INCLUDE_IN_WORKDIR:-} ; export INCLUDE_IN_WORKDIR
111112

@@ -443,6 +444,7 @@ runtest() {
443444
$LN_CMD "$RPMVERCMP" "$WORKDIR/bin"
444445
fi
445446
$LN_CMD "$DIFF" "$WORKDIR/bin"
447+
$LN_CMD "$DATE" "$WORKDIR/bin"
446448
fi
447449
for inc in $INCLUDE_IN_WORKDIR
448450
do (
@@ -957,7 +959,7 @@ else
957959
NEED_RPMVERCMP="no"
958960
fi
959961

960-
if [ -n "$AGENT" -o -n "$CF_PROMISES" -o -n "$CF_SERVERD" -o -n "$CF_EXECD" -o -n "$CF_KEY" -o -n "$CF_SECRET" -o -n "$CF_NET" -o -n "$CF_CHECK" -o -n "$CF_RUNAGENT" -o \( "$NEED_RPMVERCMP" = "yes" -a -n "$RPMVERCMP" \) -o -n "$DIFF" ]
962+
if [ -n "$AGENT" -o -n "$CF_PROMISES" -o -n "$CF_SERVERD" -o -n "$CF_EXECD" -o -n "$CF_KEY" -o -n "$CF_SECRET" -o -n "$CF_NET" -o -n "$CF_CHECK" -o -n "$CF_RUNAGENT" -o \( "$NEED_RPMVERCMP" = "yes" -a -n "$RPMVERCMP" \) -o -n "$DIFF" -o -n "$DATE" ]
961963
then
962964
if [ -n "$BINDIR" ]
963965
then
@@ -981,6 +983,7 @@ find_default_binary()
981983
[ -x "`pwd`/$2/$2" ] && eval $1=\""`pwd`/$2/$2"\"
982984
[ -n "$BINDIR" -a -x "$BINDIR/$2" ] && eval $1=\""$BINDIR/$2"\"
983985
[ $2 = "diff" ] && eval $1=\""`command -v diff`"\"
986+
[ $2 = "date" -a -z "`eval echo \\$$1`" ] && eval $1=\""`command -v date`"\"
984987
}
985988
find_default_binary DEFAGENT cf-agent
986989
find_default_binary DEFCF_PROMISES cf-promises
@@ -996,6 +999,7 @@ then
996999
find_default_binary DEFRPMVERCMP rpmvercmp
9971000
fi
9981001
find_default_binary DIFF diff
1002+
find_default_binary DATE date
9991003

10001004
[ -x "`pwd`/libtool" ] && DEFLIBTOOL="`pwd`/libtool"
10011005
[ -x "`pwd`/../../libtool" ] && DEFLIBTOOL="`pwd`/../../libtool"

0 commit comments

Comments
 (0)