1 /*
2 * Copyright (c) 2017 Balabit
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published
6 * by the Free Software Foundation, or (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 *
17 * As an additional exemption you are allowed to compile & link against the
18 * OpenSSL libraries as published by the OpenSSL project. See the file
19 * COPYING for details.
20 *
21 */
22
23 #include "plugin.h"
24 #include "plugin-types.h"
25 #include "template/simple-function.h"
26 #include "messages.h"
27 #include "cfg.h"
28
29 #include "syslog-ng-config.h"
30
31 #include <stdlib.h>
32 #include <math.h>
33
34 static gboolean
_is_leap_year(int year)35 _is_leap_year(int year)
36 {
37 return ((year%4==0) && (year % 100!=0)) || (year%400==0);
38 }
39
40 static time_t
year_in_seconds(int year)41 year_in_seconds(int year)
42 {
43 if (_is_leap_year(year))
44 return 31622400;
45 else
46 return 31536000;
47 }
48
49 typedef struct
50 {
51 TFSimpleFuncState super;
52 int precision;
53 } TFStardateState;
54
55 static guint64 power10[10] = { 1, 10, 100, 1000, 10000,
56 100000, 1000000, 10000000, 100000000, 1000000000
57 };
58
59 gboolean
tf_stardate_prepare(LogTemplateFunction * self,gpointer s,LogTemplate * parent,gint argc,gchar * argv[],GError ** error)60 tf_stardate_prepare(LogTemplateFunction *self, gpointer s, LogTemplate *parent,
61 gint argc, gchar *argv[], GError **error)
62 {
63 TFStardateState *state = (TFStardateState *) s;
64 state->precision = 2;
65
66 GOptionEntry stardate_options[] =
67 {
68 { "digits", 'd', 0, G_OPTION_ARG_INT, &state->precision, "Precision: 0-9. Default: 2.", NULL },
69 { NULL }
70 };
71
72 GOptionContext *ctx = g_option_context_new("stardate");
73 g_option_context_add_main_entries(ctx, stardate_options, NULL);
74
75 if (!g_option_context_parse(ctx, &argc, &argv, error))
76 {
77 g_option_context_free(ctx);
78 return FALSE;
79 }
80 g_option_context_free(ctx);
81
82 if (state->precision < 0 || state->precision > 9)
83 {
84 g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE,
85 "stardate: digits must be between 0-9.\n");
86 return FALSE;
87 }
88
89 if (argc != 2)
90 {
91 g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE,
92 "stardate: format must be: $(stardate [--digits 2] $UNIXTIME)\n");
93 return FALSE;
94 }
95
96 if (!tf_simple_func_prepare(self, state, parent, argc, argv, error))
97 {
98 g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE,
99 "stardate: stardate: prepare failed");
100 return FALSE;
101 }
102
103 return TRUE;
104 }
105
106 static void
tf_stardate_call(LogTemplateFunction * self,gpointer s,const LogTemplateInvokeArgs * args,GString * result)107 tf_stardate_call(LogTemplateFunction *self, gpointer s,
108 const LogTemplateInvokeArgs *args, GString *result)
109 {
110 TFStardateState *state = (TFStardateState *) s;
111
112 char *status;
113 time_t time_to_convert = strtol(args->argv[0]->str, &status, 10);
114 if (*status)
115 {
116 msg_error("stardate: wrong format: expected unixtime like value",
117 evt_tag_str("got:", args->argv[0]->str));
118 return;
119 }
120
121 struct tm tm_time;
122 localtime_r(&time_to_convert, &tm_time );
123
124 struct tm secs_beginning_year = {.tm_year = tm_time.tm_year, .tm_mday = 1};
125 time_t elapsed_seconds = time_to_convert - mktime(&secs_beginning_year);
126
127 double fraction = (double)elapsed_seconds/year_in_seconds(tm_time.tm_year);
128 double truncated = (double) floor(fraction * power10[state->precision]) / power10[state->precision];
129
130 g_string_append_printf(result, "%0.*lf", state->precision, 1900 + tm_time.tm_year + truncated);
131 }
132
133 TEMPLATE_FUNCTION(TFStardateState, tf_stardate, tf_stardate_prepare,
134 tf_simple_func_eval, tf_stardate_call, tf_simple_func_free_state, NULL);
135