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-2023 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 
41 static const char *
42 print_status_mode(unsigned int flags)
43 {
44  switch (flags)
45  {
47  return "WRITE";
48 
49  case STATUS_OUTPUT_READ:
50  return "READ";
51 
53  return "READ/WRITE";
54 
55  default:
56  return "UNDEF";
57  }
58 }
59 
60 struct status_output *
61 status_open(const char *filename,
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  {
70  ALLOC_OBJ_CLEAR(so, struct status_output);
71  so->flags = flags;
72  so->msglevel = msglevel;
73  so->vout = vout;
74  so->fd = -1;
75  buf_reset(&so->read_buf);
76  event_timeout_clear(&so->et);
77  if (filename)
78  {
79  switch (so->flags)
80  {
83  O_CREAT | O_TRUNC | O_WRONLY,
84  S_IRUSR | S_IWUSR);
85  break;
86 
87  case STATUS_OUTPUT_READ:
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 
132 bool
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 
147 void
149 {
150  if (so && so->fd >= 0)
151  {
152  lseek(so->fd, (off_t)0, SEEK_SET);
153  }
154 }
155 
156 void
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 */
187 bool
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 
221 void
222 status_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 
267 bool
268 status_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  {
274  ASSERT(buf_defined(&so->read_buf));
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 
311  buf_null_terminate(buf);
312  }
313 
314  return ret;
315 }
status_open
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
status_trigger
bool status_trigger(struct status_output *so)
Definition: status.c:133
status_output::filename
char * filename
Definition: status.h:54
M_ERRNO
#define M_ERRNO
Definition: error.h:100
buf_reset
static void buf_reset(struct buffer *buf)
Definition: buffer.h:303
status_output::et
struct event_timeout et
Definition: status.h:61
status_output::msglevel
int msglevel
Definition: status.h:56
buf_init
#define buf_init(buf, offset)
Definition: buffer.h:209
buf_null_terminate
void buf_null_terminate(struct buffer *buf)
Definition: buffer.c:577
fdmisc.h
status_output::errors
bool errors
Definition: status.h:63
event_timeout_init
static void event_timeout_init(struct event_timeout *et, interval_t n, const time_t last)
Initialises a timer struct.
Definition: interval.h:174
status_read
bool status_read(struct status_output *so, struct buffer *buf)
Definition: status.c:268
STATUS_OUTPUT_WRITE
#define STATUS_OUTPUT_WRITE
Definition: status.h:51
status_output::flags
unsigned int flags
Definition: status.h:52
status_output::read_buf
struct buffer read_buf
Definition: status.h:59
CLEAR
#define CLEAR(x)
Definition: basic.h:33
string_alloc
char * string_alloc(const char *str, struct gc_arena *gc)
Definition: buffer.c:693
ASSERT
#define ASSERT(x)
Definition: error.h:201
read
@ read
Definition: interactive.c:205
buf_inc_len
static bool buf_inc_len(struct buffer *buf, int inc)
Definition: buffer.h:608
write
@ write
Definition: interactive.c:206
status_reset
void status_reset(struct status_output *so)
Definition: status.c:148
buf_write_u8
static bool buf_write_u8(struct buffer *dest, uint8_t data)
Definition: buffer.h:710
virtual_output::func
void(* func)(void *arg, const unsigned int flags, const char *str)
Definition: status.h:35
misc.h
M_WARN
#define M_WARN
Definition: error.h:97
status_printf
void status_printf(struct status_output *so, const char *format,...)
Definition: status.c:222
status_output
Definition: status.h:48
buffer
Wrapper structure for dynamically allocated memory.
Definition: buffer.h:60
virtual_output
Definition: status.h:32
BCAP
#define BCAP(buf)
Definition: buffer.h:130
STATUS_PRINTF_MAXLEN
#define STATUS_PRINTF_MAXLEN
Definition: status.c:219
status_close
bool status_close(struct status_output *so)
Definition: status.c:188
syshead.h
BPTR
#define BPTR(buf)
Definition: buffer.h:124
virtual_output::arg
void * arg
Definition: status.h:33
status_flush
void status_flush(struct status_output *so)
Definition: status.c:157
perf.h
free_buf
void free_buf(struct buffer *buf)
Definition: buffer.c:183
ETT_DEFAULT
#define ETT_DEFAULT
Definition: interval.h:224
set_cloexec
void set_cloexec(socket_descriptor_t fd)
Definition: fdmisc.c:79
chomp
void chomp(char *str)
Definition: buffer.c:658
event_timeout_trigger
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
print_status_mode
static const char * print_status_mode(unsigned int flags)
Definition: status.c:42
ALLOC_OBJ_CLEAR
#define ALLOC_OBJ_CLEAR(dptr, type)
Definition: buffer.h:1066
status_output::fd
int fd
Definition: status.h:55
config.h
buf_read_u8
static int buf_read_u8(struct buffer *buf)
Definition: buffer.h:808
status_output::vout
const struct virtual_output * vout
Definition: status.h:57
platform_open
int platform_open(const char *path, int flags, int mode)
Definition: platform.c:527
event_timeout_clear
static void event_timeout_clear(struct event_timeout *et)
Clears the timeout and reset all values to 0.
Definition: interval.h:155
virtual_output::flags_default
unsigned int flags_default
Definition: status.h:34
alloc_buf
struct buffer alloc_buf(size_t size)
Definition: buffer.c:62
memdbg.h
msg
#define msg(flags,...)
Definition: error.h:150
STATUS_OUTPUT_READ
#define STATUS_OUTPUT_READ
Definition: status.h:50
buf_defined
static bool buf_defined(const struct buffer *buf)
Definition: buffer.h:228
status.h