~ubuntu-branches/ubuntu/saucy/openvpn/saucy-proposed

« back to all changes in this revision

Viewing changes to src/openvpn/status.c

  • Committer: Package Import Robot
  • Author(s): Stéphane Graber
  • Date: 2013-05-24 17:42:45 UTC
  • mfrom: (1.1.19) (10.2.22 sid)
  • Revision ID: package-import@ubuntu.com-20130524174245-g9y6wlforycufqy5
Tags: 2.3.1-2ubuntu1
* Merge from Debian unstable. Remaining changes:
  - debian/openvpn.init.d:
    + Do not use start-stop-daemon and </dev/null to avoid blocking boot.
    + Show per-VPN result messages.
    + Add "--script-security 2" by default for backwards compatabliity.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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-2010 OpenVPN Technologies, 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
 
20
 *  along with this program (see the file COPYING included with this
 
21
 *  distribution); if not, write to the Free Software Foundation, Inc.,
 
22
 *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
23
 */
 
24
 
 
25
#ifdef HAVE_CONFIG_H
 
26
#include "config.h"
 
27
#elif defined(_MSC_VER)
 
28
#include "config-msvc.h"
 
29
#endif
 
30
 
 
31
#include "syshead.h"
 
32
 
 
33
#include "status.h"
 
34
#include "perf.h"
 
35
#include "misc.h"
 
36
#include "fdmisc.h"
 
37
 
 
38
#include "memdbg.h"
 
39
 
 
40
/*
 
41
 * printf-style interface for outputting status info
 
42
 */
 
43
 
 
44
static const char *
 
45
print_status_mode (unsigned int flags)
 
46
{
 
47
  switch (flags)
 
48
    {
 
49
    case STATUS_OUTPUT_WRITE:
 
50
      return "WRITE";
 
51
    case STATUS_OUTPUT_READ:
 
52
      return "READ";
 
53
    case STATUS_OUTPUT_READ|STATUS_OUTPUT_WRITE:
 
54
      return "READ/WRITE";
 
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
            {
 
81
            case STATUS_OUTPUT_WRITE:
 
82
              so->fd = platform_open (filename,
 
83
                                     O_CREAT | O_TRUNC | O_WRONLY,
 
84
                                     S_IRUSR | S_IWUSR);
 
85
              break;
 
86
            case STATUS_OUTPUT_READ:
 
87
              so->fd = platform_open (filename,
 
88
                                     O_RDONLY,
 
89
                                     S_IRUSR | S_IWUSR);
 
90
              break;
 
91
            case STATUS_OUTPUT_READ|STATUS_OUTPUT_WRITE:
 
92
              so->fd = platform_open (filename,
 
93
                                     O_CREAT | O_RDWR,
 
94
                                     S_IRUSR | S_IWUSR);
 
95
              break;
 
96
            default:
 
97
              ASSERT (0);
 
98
            }
 
99
          if (so->fd >= 0)
 
100
            {
 
101
              so->filename = string_alloc (filename, NULL);
 
102
             set_cloexec (so->fd);
 
103
 
 
104
              /* allocate read buffer */
 
105
              if (so->flags & STATUS_OUTPUT_READ)
 
106
                so->read_buf = alloc_buf (512);
 
107
            }
 
108
          else
 
109
            {
 
110
              msg (M_WARN, "Note: cannot open %s for %s", filename, print_status_mode (so->flags));
 
111
              so->errors = true;
 
112
            }
 
113
        }
 
114
      else
 
115
        so->flags = STATUS_OUTPUT_WRITE;
 
116
 
 
117
      if ((so->flags & STATUS_OUTPUT_WRITE) && refresh_freq > 0)
 
118
        {
 
119
          event_timeout_init (&so->et, refresh_freq, 0);
 
120
        }
 
121
    }
 
122
  return so;
 
123
}
 
124
 
 
125
bool
 
126
status_trigger (struct status_output *so)
 
127
{
 
128
  if (so)
 
129
    {
 
130
      struct timeval null;
 
131
      CLEAR (null);
 
132
      return event_timeout_trigger (&so->et, &null, ETT_DEFAULT);
 
133
    }
 
134
  else
 
135
    return false;
 
136
}
 
137
 
 
138
bool
 
139
status_trigger_tv (struct status_output *so, struct timeval *tv)
 
140
{
 
141
  if (so)
 
142
    return event_timeout_trigger (&so->et, tv, ETT_DEFAULT);
 
143
  else
 
144
    return false;
 
145
}
 
146
 
 
147
void
 
148
status_reset (struct status_output *so)
 
149
{
 
150
  if (so && so->fd >= 0)
 
151
    lseek (so->fd, (off_t)0, SEEK_SET);
 
152
}
 
153
 
 
154
void
 
155
status_flush (struct status_output *so)
 
156
{
 
157
  if (so && so->fd >= 0 && (so->flags & STATUS_OUTPUT_WRITE))
 
158
    {
 
159
#if defined(HAVE_FTRUNCATE)
 
160
      {
 
161
        const off_t off = lseek (so->fd, (off_t)0, SEEK_CUR);
 
162
        if (ftruncate (so->fd, off) != 0) {
 
163
          msg (M_WARN, "Failed to truncate status file: %s", strerror(errno));
 
164
        }
 
165
      }
 
166
#elif defined(HAVE_CHSIZE)
 
167
      {
 
168
        const long off = (long) lseek (so->fd, (off_t)0, SEEK_CUR);
 
169
        chsize (so->fd, off);
 
170
      }
 
171
#else
 
172
#warning both ftruncate and chsize functions appear to be missing from this OS
 
173
#endif
 
174
 
 
175
      /* clear read buffer */
 
176
      if (buf_defined (&so->read_buf))
 
177
        {
 
178
          ASSERT (buf_init (&so->read_buf, 0));
 
179
        }
 
180
    }
 
181
}
 
182
 
 
183
/* return false if error occurred */
 
184
bool
 
185
status_close (struct status_output *so)
 
186
{
 
187
  bool ret = true;
 
188
  if (so)
 
189
    {
 
190
      if (so->errors)
 
191
        ret = false;
 
192
      if (so->fd >= 0)
 
193
        {
 
194
          if (close (so->fd) < 0)
 
195
            ret = false;
 
196
        }
 
197
      if (so->filename)
 
198
        free (so->filename);
 
199
      if (buf_defined (&so->read_buf))
 
200
        free_buf (&so->read_buf);
 
201
      free (so);
 
202
    }
 
203
  else
 
204
    ret = false;
 
205
  return ret;
 
206
}
 
207
 
 
208
#define STATUS_PRINTF_MAXLEN 512
 
209
 
 
210
void
 
211
status_printf (struct status_output *so, const char *format, ...)
 
212
{
 
213
  if (so && (so->flags & STATUS_OUTPUT_WRITE))
 
214
    {
 
215
      char buf[STATUS_PRINTF_MAXLEN+2]; /* leave extra bytes for CR, LF */
 
216
      va_list arglist;
 
217
      int stat;
 
218
 
 
219
      va_start (arglist, format);
 
220
      stat = vsnprintf (buf, STATUS_PRINTF_MAXLEN, format, arglist);
 
221
      va_end (arglist);
 
222
      buf[STATUS_PRINTF_MAXLEN - 1] = 0;
 
223
 
 
224
      if (stat < 0 || stat >= STATUS_PRINTF_MAXLEN)
 
225
        so->errors = true;
 
226
 
 
227
      if (so->msglevel >= 0 && !so->errors)
 
228
        msg (so->msglevel, "%s", buf);
 
229
 
 
230
      if (so->fd >= 0 && !so->errors)
 
231
        {
 
232
          int len;
 
233
          strcat (buf, "\n");
 
234
          len = strlen (buf);
 
235
          if (len > 0)
 
236
            {
 
237
              if (write (so->fd, buf, len) != len)
 
238
                so->errors = true;
 
239
            }
 
240
        }
 
241
 
 
242
      if (so->vout && !so->errors)
 
243
        {
 
244
          chomp (buf);
 
245
          (*so->vout->func) (so->vout->arg, so->vout->flags_default, buf);
 
246
        }
 
247
    }
 
248
}
 
249
 
 
250
bool
 
251
status_read (struct status_output *so, struct buffer *buf)
 
252
{
 
253
  bool ret = false;
 
254
 
 
255
  if (so && so->fd >= 0 && (so->flags & STATUS_OUTPUT_READ))
 
256
    {
 
257
      ASSERT (buf_defined (&so->read_buf));      
 
258
      ASSERT (buf_defined (buf));
 
259
      while (true)
 
260
        {
 
261
          const int c = buf_read_u8 (&so->read_buf);
 
262
 
 
263
          /* read more of file into buffer */
 
264
          if (c == -1)
 
265
            {
 
266
              int len;
 
267
 
 
268
              ASSERT (buf_init (&so->read_buf, 0));
 
269
              len = read (so->fd, BPTR (&so->read_buf), BCAP (&so->read_buf));
 
270
              if (len <= 0)
 
271
                break;
 
272
 
 
273
              ASSERT (buf_inc_len (&so->read_buf, len));
 
274
              continue;
 
275
            }
 
276
 
 
277
          ret = true;
 
278
 
 
279
          if (c == '\r')
 
280
            continue;
 
281
 
 
282
          if (c == '\n')
 
283
            break;
 
284
 
 
285
          buf_write_u8 (buf, c);
 
286
        }
 
287
 
 
288
      buf_null_terminate (buf);
 
289
    }
 
290
 
 
291
  return ret;
 
292
}