1
/* Copyright (C) 2004 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
#include "parse_output.h"
18
#include <my_global.h>
25
#include "portability.h"
27
/**************************************************************************
28
Private module implementation.
29
**************************************************************************/
31
namespace { /* no-indent */
33
/*************************************************************************/
35
void trim_space(const char **text, uint *word_len)
37
const char *start= *text;
38
while (*start != 0 && *start == ' ')
42
int len= strlen(start);
43
const char *end= start + len - 1;
44
while (end > start && my_isspace(&my_charset_latin1, *end))
46
*word_len= (end - start)+1;
49
/*************************************************************************/
52
@brief A facade to the internal workings of optaining the output from an
53
executed system process.
56
class Mysqld_output_parser
59
Mysqld_output_parser()
62
virtual ~Mysqld_output_parser()
66
bool parse(const char *command,
67
const char *option_name_str,
68
uint option_name_length,
69
char *option_value_buf,
70
size_t option_value_buf_size,
71
enum_option_type option_type);
75
@brief Run a process and attach stdout- and stdin-pipes to it.
77
@param command The path to the process to be executed
80
@retval TRUE An error occurred
81
@retval FALSE Operation was a success
84
virtual bool run_command(const char *command)= 0;
88
@brief Read a sequence of bytes from the executed process' stdout pipe.
90
The sequence is terminated by either '\0', LF or CRLF tokens. The
91
terminating token is excluded from the result.
93
@param line_buffer A pointer to a character buffer
94
@param line_buffer_size The size of the buffer in bytes
97
@retval TRUE An error occured
98
@retval FALSE Operation was a success
101
virtual bool read_line(char *line_buffer,
102
uint line_buffer_size)= 0;
106
@brief Release any resources needed after a execution and parsing.
109
virtual bool cleanup()= 0;
112
/*************************************************************************/
114
bool Mysqld_output_parser::parse(const char *command,
115
const char *option_name_str,
116
uint option_name_length,
117
char *option_value_buf,
118
size_t option_value_buf_size,
119
enum_option_type option_type)
121
/* should be enough to store the string from the output */
122
const int LINE_BUFFER_SIZE= 512;
123
char line_buffer[LINE_BUFFER_SIZE];
125
if (run_command(command))
130
if (read_line(line_buffer, LINE_BUFFER_SIZE))
136
uint found_word_len= 0;
137
char *linep= line_buffer;
139
line_buffer[sizeof(line_buffer) - 1]= '\0'; /* safety */
141
/* Find the word(s) we are looking for in the line. */
143
linep= strstr(linep, option_name_str);
148
linep+= option_name_length;
153
trim_space((const char**) &linep, &found_word_len);
155
if (option_value_buf_size <= found_word_len)
161
strmake(option_value_buf, linep, found_word_len);
166
strmake(option_value_buf, linep, option_value_buf_size - 1);
177
/**************************************************************************
178
Platform-specific implementation: UNIX.
179
**************************************************************************/
183
class Mysqld_output_parser_unix : public Mysqld_output_parser
186
Mysqld_output_parser_unix() :
191
virtual bool run_command(const char *command);
193
virtual bool read_line(char *line_buffer,
194
uint line_buffer_size);
196
virtual bool cleanup();
202
bool Mysqld_output_parser_unix::run_command(const char *command)
204
if (!(m_stdout= popen(command, "r")))
208
We want fully buffered stream. We also want system to allocate
212
setvbuf(m_stdout, NULL, _IOFBF, 0);
217
bool Mysqld_output_parser_unix::read_line(char *line_buffer,
218
uint line_buffer_size)
220
char *retbuff = fgets(line_buffer, line_buffer_size, m_stdout);
221
/* Remove any tailing new line charaters */
222
if (line_buffer[line_buffer_size-1] == LF)
223
line_buffer[line_buffer_size-1]= '\0';
224
return (retbuff == NULL);
227
bool Mysqld_output_parser_unix::cleanup()
237
/**************************************************************************
238
Platform-specific implementation: Windows.
239
**************************************************************************/
241
class Mysqld_output_parser_win : public Mysqld_output_parser
244
Mysqld_output_parser_win() :
245
m_internal_buffer(NULL),
246
m_internal_buffer_offset(0),
247
m_internal_buffer_size(0)
251
virtual bool run_command(const char *command);
252
virtual bool read_line(char *line_buffer,
253
uint line_buffer_size);
254
virtual bool cleanup();
257
HANDLE m_h_child_stdout_wr;
258
HANDLE m_h_child_stdout_rd;
259
uint m_internal_buffer_offset;
260
uint m_internal_buffer_size;
261
char *m_internal_buffer;
264
bool Mysqld_output_parser_win::run_command(const char *command)
268
SECURITY_ATTRIBUTES sa_attr;
269
sa_attr.nLength= sizeof(SECURITY_ATTRIBUTES);
270
sa_attr.bInheritHandle= TRUE;
271
sa_attr.lpSecurityDescriptor= NULL;
273
op_status= CreatePipe(&m_h_child_stdout_rd,
274
&m_h_child_stdout_wr,
276
0 /* Use system-default buffer size. */);
281
SetHandleInformation(m_h_child_stdout_rd, HANDLE_FLAG_INHERIT, 0);
283
STARTUPINFO si_start_info;
284
ZeroMemory(&si_start_info, sizeof(STARTUPINFO));
285
si_start_info.cb= sizeof(STARTUPINFO);
286
si_start_info.hStdError= m_h_child_stdout_wr;
287
si_start_info.hStdOutput= m_h_child_stdout_wr;
288
si_start_info.dwFlags|= STARTF_USESTDHANDLES;
290
PROCESS_INFORMATION pi_proc_info;
292
op_status= CreateProcess(NULL, /* Application name. */
293
(char*)command, /* Command line. */
294
NULL, /* Process security attributes. */
295
NULL, /* Primary thread security attr.*/
296
TRUE, /* Handles are inherited. */
297
0, /* Creation flags. */
298
NULL, /* Use parent's environment. */
299
NULL, /* Use parent's curr. directory. */
300
&si_start_info, /* STARTUPINFO pointer. */
301
&pi_proc_info); /* Rec. PROCESS_INFORMATION. */
305
CloseHandle(m_h_child_stdout_rd);
306
CloseHandle(m_h_child_stdout_wr);
311
/* Close unnessary handles. */
313
CloseHandle(pi_proc_info.hProcess);
314
CloseHandle(pi_proc_info.hThread);
319
bool Mysqld_output_parser_win::read_line(char *line_buffer,
320
uint line_buffer_size)
322
DWORD dw_read_count= m_internal_buffer_size;
323
bzero(line_buffer,line_buffer_size);
324
char *buff_ptr= line_buffer;
327
while ((unsigned)(buff_ptr - line_buffer) < line_buffer_size)
331
ReadFile(m_h_child_stdout_rd, &ch,
332
1, &dw_read_count, NULL);
333
} while ((ch == CR || ch == LF) && buff_ptr == line_buffer);
335
if (dw_read_count == 0)
338
if (ch == CR || ch == LF)
347
bool Mysqld_output_parser_win::cleanup()
349
/* Close all handles. */
351
CloseHandle(m_h_child_stdout_wr);
352
CloseHandle(m_h_child_stdout_rd);
358
/*************************************************************************/
360
} /* End of private module implementation. */
362
/*************************************************************************/
365
@brief Parse output of the given command
367
@param command The command to execute.
368
@param option_name_str Option name.
369
@param option_name_length Length of the option name.
370
@param[out] option_value_buf The buffer to store option value.
371
@param option_value_buf_size Size of the option value buffer.
372
@param option_type Type of the option:
373
- GET_LINE if we want to get all the
374
line after the option name;
375
- GET_VALUE otherwise.
377
Execute the process by running "command". Find the "option name" and
378
return the next word if "option_type" is GET_VALUE. Return the rest of
379
the parsed string otherwise.
381
@note This function has a separate windows implementation.
383
@return The error status.
384
@retval FALSE Ok, the option name has been found.
385
@retval TRUE Error occured or the option name is not found.
388
bool parse_output_and_get_value(const char *command,
389
const char *option_name_str,
390
uint option_name_length,
391
char *option_value_buf,
392
size_t option_value_buf_size,
393
enum_option_type option_type)
396
Mysqld_output_parser_unix parser;
398
Mysqld_output_parser_win parser;
401
return parser.parse(command,
405
option_value_buf_size,