OpenVPN
status.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2002-2024 OpenVPN Inc <sales@openvpn.net>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include "syshead.h"
29
30#include "status.h"
31#include "perf.h"
32#include "misc.h"
33#include "fdmisc.h"
34
35#include "memdbg.h"
36
37/*
38 * printf-style interface for outputting status info
39 */
40
41static const char *
42print_status_mode(unsigned int flags)
43{
44 switch (flags)
45 {
47 return "WRITE";
48
50 return "READ";
51
53 return "READ/WRITE";
54
55 default:
56 return "UNDEF";
57 }
58}
59
60struct status_output *
62 const int refresh_freq,
63 const int msglevel,
64 const struct virtual_output *vout,
65 const unsigned int flags)
66{
67 struct status_output *so = NULL;
68 if (filename || msglevel >= 0 || vout)
69 {
71 so->flags = flags;
72 so->msglevel = msglevel;
73 so->vout = vout;
74 so->fd = -1;
75 buf_reset(&so->read_buf);
77 if (filename)
78 {
79 switch (so->flags)
80 {
83 O_CREAT | O_TRUNC | O_WRONLY,
84 S_IRUSR | S_IWUSR);
85 break;
86
89 O_RDONLY,
90 S_IRUSR | S_IWUSR);
91 break;
92
95 O_CREAT | O_RDWR,
96 S_IRUSR | S_IWUSR);
97 break;
98
99 default:
100 ASSERT(0);
101 }
102 if (so->fd >= 0)
103 {
104 so->filename = string_alloc(filename, NULL);
105 set_cloexec(so->fd);
106
107 /* allocate read buffer */
108 if (so->flags & STATUS_OUTPUT_READ)
109 {
110 so->read_buf = alloc_buf(512);
111 }
112 }
113 else
114 {
115 msg(M_WARN, "Note: cannot open %s for %s", filename, print_status_mode(so->flags));
116 so->errors = true;
117 }
118 }
119 else
120 {
122 }
123
124 if ((so->flags & STATUS_OUTPUT_WRITE) && refresh_freq > 0)
125 {
126 event_timeout_init(&so->et, refresh_freq, 0);
127 }
128 }
129 return so;
130}
131
132bool
134{
135 if (so)
136 {
137 struct timeval null;
138 CLEAR(null);
139 return event_timeout_trigger(&so->et, &null, ETT_DEFAULT);
140 }
141 else
142 {
143 return false;
144 }
145}
146
147void
149{
150 if (so && so->fd >= 0)
151 {
152 lseek(so->fd, (off_t)0, SEEK_SET);
153 }
154}
155
156void
158{
159 if (so && so->fd >= 0 && (so->flags & STATUS_OUTPUT_WRITE))
160 {
161#if defined(HAVE_FTRUNCATE)
162 {
163 const off_t off = lseek(so->fd, (off_t)0, SEEK_CUR);
164 if (ftruncate(so->fd, off) != 0)
165 {
166 msg(M_WARN | M_ERRNO, "Failed to truncate status file");
167 }
168 }
169#elif defined(HAVE_CHSIZE)
170 {
171 const long off = (long) lseek(so->fd, (off_t)0, SEEK_CUR);
172 chsize(so->fd, off);
173 }
174#else /* if defined(HAVE_FTRUNCATE) */
175#warning both ftruncate and chsize functions appear to be missing from this OS
176#endif
177
178 /* clear read buffer */
179 if (buf_defined(&so->read_buf))
180 {
181 ASSERT(buf_init(&so->read_buf, 0));
182 }
183 }
184}
185
186/* return false if error occurred */
187bool
189{
190 bool ret = true;
191 if (so)
192 {
193 if (so->errors)
194 {
195 ret = false;
196 }
197 if (so->fd >= 0)
198 {
199 if (close(so->fd) < 0)
200 {
201 ret = false;
202 }
203 }
204 free(so->filename);
205
206 if (buf_defined(&so->read_buf))
207 {
208 free_buf(&so->read_buf);
209 }
210 free(so);
211 }
212 else
213 {
214 ret = false;
215 }
216 return ret;
217}
218
219#define STATUS_PRINTF_MAXLEN 512
220
221void
222status_printf(struct status_output *so, const char *format, ...)
223{
224 if (so && (so->flags & STATUS_OUTPUT_WRITE))
225 {
226 char buf[STATUS_PRINTF_MAXLEN+2]; /* leave extra bytes for CR, LF */
227 va_list arglist;
228 int stat;
229
230 va_start(arglist, format);
231 stat = vsnprintf(buf, STATUS_PRINTF_MAXLEN, format, arglist);
232 va_end(arglist);
233 buf[STATUS_PRINTF_MAXLEN - 1] = 0;
234
235 if (stat < 0 || stat >= STATUS_PRINTF_MAXLEN)
236 {
237 so->errors = true;
238 }
239
240 if (so->msglevel >= 0 && !so->errors)
241 {
242 msg(so->msglevel, "%s", buf);
243 }
244
245 if (so->fd >= 0 && !so->errors)
246 {
247 int len;
248 strcat(buf, "\n");
249 len = strlen(buf);
250 if (len > 0)
251 {
252 if (write(so->fd, buf, len) != len)
253 {
254 so->errors = true;
255 }
256 }
257 }
258
259 if (so->vout && !so->errors)
260 {
261 chomp(buf);
262 (*so->vout->func)(so->vout->arg, so->vout->flags_default, buf);
263 }
264 }
265}
266
267bool
268status_read(struct status_output *so, struct buffer *buf)
269{
270 bool ret = false;
271
272 if (so && so->fd >= 0 && (so->flags & STATUS_OUTPUT_READ))
273 {
275 ASSERT(buf_defined(buf));
276 while (true)
277 {
278 const int c = buf_read_u8(&so->read_buf);
279
280 /* read more of file into buffer */
281 if (c == -1)
282 {
283 int len;
284
285 ASSERT(buf_init(&so->read_buf, 0));
286 len = read(so->fd, BPTR(&so->read_buf), BCAP(&so->read_buf));
287 if (len <= 0)
288 {
289 break;
290 }
291
292 ASSERT(buf_inc_len(&so->read_buf, len));
293 continue;
294 }
295
296 ret = true;
297
298 if (c == '\r')
299 {
300 continue;
301 }
302
303 if (c == '\n')
304 {
305 break;
306 }
307
308 buf_write_u8(buf, c);
309 }
310
312 }
313
314 return ret;
315}
void free_buf(struct buffer *buf)
Definition buffer.c:183
void buf_null_terminate(struct buffer *buf)
Definition buffer.c:533
void chomp(char *str)
Definition buffer.c:614
struct buffer alloc_buf(size_t size)
Definition buffer.c:62
char * string_alloc(const char *str, struct gc_arena *gc)
Definition buffer.c:649
#define BPTR(buf)
Definition buffer.h:124
static bool buf_inc_len(struct buffer *buf, int inc)
Definition buffer.h:590
static void buf_reset(struct buffer *buf)
Definition buffer.h:303
static bool buf_write_u8(struct buffer *dest, uint8_t data)
Definition buffer.h:692
static int buf_read_u8(struct buffer *buf)
Definition buffer.h:790
#define BCAP(buf)
Definition buffer.h:130
#define ALLOC_OBJ_CLEAR(dptr, type)
Definition buffer.h:1060
static bool buf_defined(const struct buffer *buf)
Definition buffer.h:228
#define buf_init(buf, offset)
Definition buffer.h:209
void set_cloexec(socket_descriptor_t fd)
Definition fdmisc.c:79
@ write
@ read
bool event_timeout_trigger(struct event_timeout *et, struct timeval *tv, const int et_const_retry)
This is the principal function for testing and triggering recurring timers.
Definition interval.c:43
#define ETT_DEFAULT
Definition interval.h:224
static void event_timeout_init(struct event_timeout *et, interval_t n, const time_t last)
Initialises a timer struct.
Definition interval.h:174
static void event_timeout_clear(struct event_timeout *et)
Clears the timeout and reset all values to 0.
Definition interval.h:155
#define CLEAR(x)
Definition basic.h:33
#define msg(flags,...)
Definition error.h:144
#define ASSERT(x)
Definition error.h:195
#define M_WARN
Definition error.h:91
#define M_ERRNO
Definition error.h:94
int platform_open(const char *path, int flags, int mode)
Definition platform.c:514
#define STATUS_PRINTF_MAXLEN
Definition status.c:219
bool status_trigger(struct status_output *so)
Definition status.c:133
static const char * print_status_mode(unsigned int flags)
Definition status.c:42
void status_printf(struct status_output *so, const char *format,...)
Definition status.c:222
bool status_read(struct status_output *so, struct buffer *buf)
Definition status.c:268
struct status_output * status_open(const char *filename, const int refresh_freq, const int msglevel, const struct virtual_output *vout, const unsigned int flags)
Definition status.c:61
void status_flush(struct status_output *so)
Definition status.c:157
void status_reset(struct status_output *so)
Definition status.c:148
bool status_close(struct status_output *so)
Definition status.c:188
#define STATUS_OUTPUT_WRITE
Definition status.h:51
#define STATUS_OUTPUT_READ
Definition status.h:50
Wrapper structure for dynamically allocated memory.
Definition buffer.h:61
struct buffer read_buf
Definition status.h:59
const struct virtual_output * vout
Definition status.h:57
bool errors
Definition status.h:63
struct event_timeout et
Definition status.h:61
int msglevel
Definition status.h:56
unsigned int flags
Definition status.h:52
char * filename
Definition status.h:54
unsigned int flags_default
Definition status.h:34
void * arg
Definition status.h:33
void(* func)(void *arg, const unsigned int flags, const char *str)
Definition status.h:35