diff options
Diffstat (limited to 'server-tools/instance-manager/parse_output.cc')
-rw-r--r-- | server-tools/instance-manager/parse_output.cc | 401 |
1 files changed, 340 insertions, 61 deletions
diff --git a/server-tools/instance-manager/parse_output.cc b/server-tools/instance-manager/parse_output.cc index 36eb5185f6b..4dc67657512 100644 --- a/server-tools/instance-manager/parse_output.cc +++ b/server-tools/instance-manager/parse_output.cc @@ -24,6 +24,13 @@ #include "parse.h" #include "portability.h" +/************************************************************************** + Private module implementation. +**************************************************************************/ + +namespace { /* no-indent */ + +/*************************************************************************/ void trim_space(const char **text, uint *word_len) { @@ -39,90 +46,362 @@ void trim_space(const char **text, uint *word_len) *word_len= (end - start)+1; } -/* - Parse output of the given command +/*************************************************************************/ - SYNOPSIS - parse_output_and_get_value() +/** + @brief A facade to the internal workings of optaining the output from an + executed system process. +*/ - command the command to execue with popen. - word the word to look for (usually an option name) - result the buffer to store the next word (option value) - input_buffer_len self-explanatory - flag this equals to GET_LINE if we want to get all the line after - the matched word and GET_VALUE otherwise. +class Mysqld_output_parser +{ +public: + Mysqld_output_parser() + { } - DESCRIPTION + virtual ~Mysqld_output_parser() + { } - Parse output of the "command". Find the "word" and return the next one - if flag is GET_VALUE. Return the rest of the parsed string otherwise. +public: + bool parse(const char *command, + const char *option_name_str, + uint option_name_length, + char *option_value_buf, + size_t option_value_buf_size, + enum_option_type option_type); - RETURN - 0 - ok, the word has been found - 1 - error occured or the word is not found -*/ +protected: + /** + @brief Run a process and attach stdout- and stdin-pipes to it. -int parse_output_and_get_value(const char *command, const char *word, - char *result, size_t input_buffer_len, - uint flag) -{ - FILE *output; - uint wordlen; - /* should be enough to store the string from the output */ - enum { MAX_LINE_LEN= 512 }; - char linebuf[MAX_LINE_LEN]; - int rc= 1; + @param command The path to the process to be executed - wordlen= strlen(word); + @return Error status. + @retval TRUE An error occurred + @retval FALSE Operation was a success + */ - /* - Successful return of popen does not tell us whether the command has been - executed successfully: if the command was not found, we'll get EOF - when reading the output buffer below. + virtual bool run_command(const char *command)= 0; + + + /** + @brief Read a sequence of bytes from the executed process' stdout pipe. + + The sequence is terminated by either '\0', LF or CRLF tokens. The + terminating token is excluded from the result. + + @param line_buffer A pointer to a character buffer + @param line_buffer_size The size of the buffer in bytes + + @return Error status. + @retval TRUE An error occured + @retval FALSE Operation was a success */ - if (!(output= popen(command, "r"))) - goto err; - /* - We want fully buffered stream. We also want system to - allocate appropriate buffer. + virtual bool read_line(char *line_buffer, + uint line_buffer_size)= 0; + + + /** + @brief Release any resources needed after a execution and parsing. */ - setvbuf(output, NULL, _IOFBF, 0); - while (fgets(linebuf, sizeof(linebuf) - 1, output)) + virtual bool cleanup()= 0; +}; + +/*************************************************************************/ + +bool Mysqld_output_parser::parse(const char *command, + const char *option_name_str, + uint option_name_length, + char *option_value_buf, + size_t option_value_buf_size, + enum_option_type option_type) +{ + /* should be enough to store the string from the output */ + const int LINE_BUFFER_SIZE= 512; + char line_buffer[LINE_BUFFER_SIZE]; + + if (run_command(command)) + return TRUE; + + while (true) { + if (read_line(line_buffer, LINE_BUFFER_SIZE)) + { + cleanup(); + return TRUE; + } + uint found_word_len= 0; - char *linep= linebuf; + char *linep= line_buffer; + + line_buffer[sizeof(line_buffer) - 1]= '\0'; /* safety */ + + /* Find the word(s) we are looking for in the line. */ - linebuf[sizeof(linebuf) - 1]= '\0'; /* safety */ + linep= strstr(linep, option_name_str); - /* - Find the word(s) we are looking for in the line - */ - if ((linep= strstr(linep, word))) + if (!linep) + continue; + + linep+= option_name_length; + + switch (option_type) { - /* - If we have found our word(s), then move linep past the word(s) - */ - linep+= wordlen; - if (flag & GET_VALUE) + case GET_VALUE: + trim_space((const char**) &linep, &found_word_len); + + if (option_value_buf_size <= found_word_len) { - trim_space((const char**) &linep, &found_word_len); - if (input_buffer_len <= found_word_len) - goto err; - strmake(result, linep, found_word_len); + cleanup(); + return TRUE; } - else /* currently there are only two options */ - strmake(result, linep, input_buffer_len - 1); - rc= 0; + + strmake(option_value_buf, linep, found_word_len); + + break; + + case GET_LINE: + strmake(option_value_buf, linep, option_value_buf_size - 1); + break; } + + cleanup(); + + return FALSE; } +} + +/************************************************************************** + Platform-specific implementation: UNIX. +**************************************************************************/ + +#ifndef __WIN__ + +class Mysqld_output_parser_unix : public Mysqld_output_parser +{ +public: + Mysqld_output_parser_unix() : + m_stdout(NULL) + { } + +protected: + virtual bool run_command(const char *command); + + virtual bool read_line(char *line_buffer, + uint line_buffer_size); + + virtual bool cleanup(); + +private: + FILE *m_stdout; +}; + +bool Mysqld_output_parser_unix::run_command(const char *command) +{ + if (!(m_stdout= popen(command, "r"))) + return TRUE; - /* we are not interested in the termination status */ - pclose(output); + /* + We want fully buffered stream. We also want system to allocate + appropriate buffer. + */ -err: - return rc; + setvbuf(m_stdout, NULL, _IOFBF, 0); + + return FALSE; } +bool Mysqld_output_parser_unix::read_line(char *line_buffer, + uint line_buffer_size) +{ + char *retbuff = fgets(line_buffer, line_buffer_size, m_stdout); + /* Remove any tailing new line charaters */ + if (line_buffer[line_buffer_size-1] == LF) + line_buffer[line_buffer_size-1]= '\0'; + return (retbuff == NULL); +} + +bool Mysqld_output_parser_unix::cleanup() +{ + if (m_stdout) + pclose(m_stdout); + + return FALSE; +} + +#else /* Windows */ + +/************************************************************************** + Platform-specific implementation: Windows. +**************************************************************************/ + +class Mysqld_output_parser_win : public Mysqld_output_parser +{ +public: + Mysqld_output_parser_win() : + m_internal_buffer(NULL), + m_internal_buffer_offset(0), + m_internal_buffer_size(0) + { } + +protected: + virtual bool run_command(const char *command); + virtual bool read_line(char *line_buffer, + uint line_buffer_size); + virtual bool cleanup(); + +private: + HANDLE m_h_child_stdout_wr; + HANDLE m_h_child_stdout_rd; + uint m_internal_buffer_offset; + uint m_internal_buffer_size; + char *m_internal_buffer; +}; + +bool Mysqld_output_parser_win::run_command(const char *command) +{ + BOOL op_status; + + SECURITY_ATTRIBUTES sa_attr; + sa_attr.nLength= sizeof(SECURITY_ATTRIBUTES); + sa_attr.bInheritHandle= TRUE; + sa_attr.lpSecurityDescriptor= NULL; + + op_status= CreatePipe(&m_h_child_stdout_rd, + &m_h_child_stdout_wr, + &sa_attr, + 0 /* Use system-default buffer size. */); + + if (!op_status) + return TRUE; + + SetHandleInformation(m_h_child_stdout_rd, HANDLE_FLAG_INHERIT, 0); + + STARTUPINFO si_start_info; + ZeroMemory(&si_start_info, sizeof(STARTUPINFO)); + si_start_info.cb= sizeof(STARTUPINFO); + si_start_info.hStdError= m_h_child_stdout_wr; + si_start_info.hStdOutput= m_h_child_stdout_wr; + si_start_info.dwFlags|= STARTF_USESTDHANDLES; + + PROCESS_INFORMATION pi_proc_info; + + op_status= CreateProcess(NULL, /* Application name. */ + (char*)command, /* Command line. */ + NULL, /* Process security attributes. */ + NULL, /* Primary thread security attr.*/ + TRUE, /* Handles are inherited. */ + 0, /* Creation flags. */ + NULL, /* Use parent's environment. */ + NULL, /* Use parent's curr. directory. */ + &si_start_info, /* STARTUPINFO pointer. */ + &pi_proc_info); /* Rec. PROCESS_INFORMATION. */ + + if (!retval) + { + CloseHandle(m_h_child_stdout_rd); + CloseHandle(m_h_child_stdout_wr); + + return TRUE; + } + + /* Close unnessary handles. */ + + CloseHandle(pi_proc_info.hProcess); + CloseHandle(pi_proc_info.hThread); + + return FALSE; +} + +bool Mysqld_output_parser_win::read_line(char *line_buffer, + uint line_buffer_size) +{ + DWORD dw_read_count= m_internal_buffer_size; + bzero(line_buffer,line_buffer_size); + char *buff_ptr= line_buffer; + char ch; + + while (buff_ptr - line_buffer < line_buffer_size) + { + do + { + ReadFile(m_h_child_stdout_rd, &ch, + 1, &dw_read_count, NULL); + } while ((ch == CR || ch == LF) && buff_ptr == line_buffer); + + if (dw_read_count == 0) + return TRUE; + + if (ch == CR || ch == LF) + break; + + *buff_ptr++ = ch; + } + + return FALSE; +} + +bool Mysqld_output_parser_win::cleanup() +{ + /* Close all handles. */ + + CloseHandle(m_h_child_stdout_wr); + CloseHandle(m_h_child_stdout_rd); + + return FALSE; +} +#endif + +/*************************************************************************/ + +} /* End of private module implementation. */ + +/*************************************************************************/ + +/** + @brief Parse output of the given command + + @param command The command to execute. + @param option_name_str Option name. + @param option_name_length Length of the option name. + @param[out] option_value_buf The buffer to store option value. + @param option_value_buf_size Size of the option value buffer. + @param option_type Type of the option: + - GET_LINE if we want to get all the + line after the option name; + - GET_VALUE otherwise. + + Execute the process by running "command". Find the "option name" and + return the next word if "option_type" is GET_VALUE. Return the rest of + the parsed string otherwise. + + @note This function has a separate windows implementation. + + @return The error status. + @retval FALSE Ok, the option name has been found. + @retval TRUE Error occured or the option name is not found. +*/ + +bool parse_output_and_get_value(const char *command, + const char *option_name_str, + uint option_name_length, + char *option_value_buf, + size_t option_value_buf_size, + enum_option_type option_type) +{ +#ifndef __WIN__ + Mysqld_output_parser_unix parser; +#else /* __WIN__ */ + Mysqld_output_parser_win parser; +#endif + + return parser.parse(command, + option_name_str, + option_name_length, + option_value_buf, + option_value_buf_size, + option_type); +} |