@@ -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+
76007677static 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+
1143011513static 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" ,
0 commit comments