1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
|
/* VTY I/O for stdout/stderr
*
* Copyright (C) 2010 Chris Hall (GMCH), Highwayman
*
* This file is part of GNU Zebra.
*
* GNU Zebra is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* GNU Zebra is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Zebra; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include "misc.h"
#include "vty_io_std.h"
#include "vty_io.h"
/*==============================================================================
* Here we handle:
*
* * VOUT_STDOUT: stdout and stderr output -- for write only
*
* This is intended for use early in the morning -- in particular, before
* and during the reading of configuration file -- and late at night, once
* everything else has shut down.
*
* See vty_err().
*
* Uses straightforward FILE* I/O.
*
* NB: VOUT_STDOUT may only be a vout_base item.
*
* NB: this is simple-minded BLOCKING stuff. It is assumed:
*
* (a) that stdout and stderr will not block (or not for long)
*
* (b) that these are NOT used in normal running -- so if they do block,
* it is not, in any case, critical.
*
* (c) that multiple threads will not use these -- or if they do, then
* the usual interleaving of output is acceptable.
*
* When output is pushed, will perform a fflush().
*
* Post daemonisation:
*
* * stdout output will be lost unless a stdout file is set (TODO).
*
* * stderr output is redirected to logging (at some priority TODO).
*/
/*------------------------------------------------------------------------------
* Set up VTY on which to write to stdout.
*
* NB: sets up a blocking vio -- so output, and any pushed files and pipes will
* block waiting for I/O to complete (or to time out).
*
* NB: the name is XSTRDUP() into the vio -- so the caller is responsible for
* disposing of its copy, if required.
*/
extern vty
vty_std_write_open(const char* name)
{
vty vty ;
vty_io vio ;
vio_vf vf ;
VTY_LOCK() ;
/* Create the vty and its vio.
*
* NB: VTY_STDOUT type vty is set vio->blocking.
*/
vty = uty_new(VTY_STDOUT, NULL_NODE) ;
vio = vty->vio ;
/* Create the vin_base/vout_base vf
*
* NB: we set this genuinely blocking, because that's what it is !
*/
qassert(vio->blocking) ;
vf = uty_vf_new(vio, name, -1, vfd_none, vfd_io_write | vfd_io_os_blocking) ;
uty_vin_push(vio, vf, VIN_DEV_NULL, NULL, 0) ;
uty_vf_read_stop(vf, vfs_stop_cease) ;
uty_vout_push(vio, vf, VOUT_STDOUT, NULL, std_buffer_size, true /* after */) ;
/* From now on we are running a phantom "start command".
*/
vio->state = vst_cmd_running_executing ;
VTY_UNLOCK() ;
return vty ;
} ;
/*------------------------------------------------------------------------------
* Command output push to a file -- VOUT_STDOUT -- vf_open.
*
* NB: we take absolutely no notice of any errors -- discards contents of
* fifo if fails at all.
*
* NB: uses whatever stdout is set up for, assuming it is simple, blocking I/O.
*
* Returns: CMD_SUCCESS -- done everything possible
*
* This can be called in any thread.
*/
extern cmd_ret_t
uty_std_out_push(vio_vf vf)
{
VTY_ASSERT_LOCKED() ; /* In any thread */
qassert(vf->vout_type == VOUT_STDOUT) ;
/* Do nothing if vf_end. Also traps vst_final.
*/
if (vf->vout_state & vf_end)
return CMD_SUCCESS ;
qassert((vf->vio->state & vst_final) == 0) ;
/* If not vst_cmd_running or vst_cmd_running_executing we are done.
*/
if ((vf->vio->state & (vst_cmd_inner_mask | vst_cancel)) != vst_cmd_running)
return CMD_SUCCESS ; /* nothing more to do ATM */
/* Expect to empty out the buffer in one go !
*/
if (vio_fifo_fwrite(vf->obuf, stdout) < 0)
vio_fifo_clear(vf->obuf) ;
fflush(stdout) ; /* make sure */
/* If is not vst_cmd_executing, then we are at the top command level, and
* now that the buffer is empty, we can go vst_cmd_complete.
*/
if ((vf->vio->state & vst_cmd_executing) == 0)
{
qassert(vio_fifo_is_empty(vf->obuf)) ;
vf->vio->state = (vf->vio->state & ~vst_cmd_mask) | vst_cmd_complete ;
} ;
/* In any event, have done everything that can be done.
*/
return CMD_SUCCESS ;
} ;
/*------------------------------------------------------------------------------
* stderr output.
*
* Before daemonisation, outputs directly to stderr.
*
* Post daemonisation, outputs to logging... TODO
* or to stderr file... TODO
*/
extern void
uty_std_err_vprintf(const char *format, va_list args)
{
vfprintf(stderr, format, args) ;
} ;
/*------------------------------------------------------------------------------
* Output the close reason to VOUT_STDOUT
*
* Before daemonisation, outputs directly to stderr.
*
* Post daemonisation, output to logging... TODO (output vf->vio->close_reason
* or to stderr file... TODO
*/
extern void
uty_std_close_reason(vio_vf vf, qstring wrapped)
{
qassert(vf->vout_type == VOUT_STDOUT) ;
fputs(qs_string(wrapped), stderr) ;
} ;
/*------------------------------------------------------------------------------
* Block waiting to write to VOUT_STDOUT
*
* For blocking vf *only* !
*
* Returns: CMD_SUCCESS -- can write or got something to read or something
*/
extern cmd_ret_t
uty_std_write_block(vio_vf vf)
{
return uty_std_out_push(vf) ;
} ;
/*------------------------------------------------------------------------------
* Write away any pending stuff -- VOUT_STDOUT.
*
* This is a blocking vf -- so any outstanding output will complete here.
*
* TODO -- flush any pending post daemonise stderr !
*/
extern cmd_ret_t
uty_std_write_close(vio_vf vf)
{
VTY_ASSERT_LOCKED() ;
return uty_std_out_push(vf) ;
} ;
/*==============================================================================
* The VIN_DEV_NULL
*/
|