8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-24 00:03:03 +01:00

New feature 2524 : Command line utility to work with Trace Service

Source code
This commit is contained in:
hvlad 2009-06-24 13:05:51 +00:00
parent ba4e9a8736
commit 9ba34ee2cc
4 changed files with 422 additions and 23 deletions

View File

@ -30,8 +30,8 @@
#include "iberror.h"
#include "../../common/classes/fb_string.h"
#include "../../common/StatusArg.h"
#include "../../common/utils_proto.h"
#include "../../common/UtilSvc.h"
#include "../../jrd/ThreadData.h"
#include "../../jrd/trace/TraceService.h"
@ -49,33 +49,39 @@ static void usage(UtilSvc* uSvc, const char* message, ...)
(Arg::Gds(isc_random) << msg).raise();
fprintf(stderr, "ERROR: %s.\n\n", msg.c_str());
fprintf(stderr,
"Firebird Trace utility.\n"
"Usage: fbtrace <action> [<parameters>]\n"
"Usage: fbtracemgr <action> [<parameters>]\n"
"\n"
"Actions: \n"
" -STA[RT] Start trace session\n"
" -STO[P] Stop trace session\n"
" -S[USPEND] Suspend trace session\n"
" -R[ESUME] Resume trace session\n"
" -L[IST] List existing trace sessions\n\n"
"Parameters: \n"
" -N[AME] <string> Session name\n"
" -I[D] <number> Session ID\n"
" -C[ONFIG] <string> Trace configuration file name\n"
" -O[UTPUT] <string> Output file name\n"
"\n"
"Action parameters: \n"
" -N[AME] <string> Session name\n"
" -I[D] <number> Session ID\n"
" -C[ONFIG] <string> Trace configuration file name\n"
"\n"
"Connection parameters: \n"
" -SE[RVICE] <string> Service name\n"
" -U[SER] <string> User name\n"
" -P[ASSWORD] <string> Password\n"
" -FE[TCH] <string> Fetch password from file\n"
" -SE[RVICE] <string> Service name\n\n"
"Examples: \n"
" fbtrace -START -NAME my_trace -CONFIG my_cfg.txt\n"
" fbtrace -START -CONFIG my_cfg.txt -OUTPUT log.txt\n"
" fbtrace -STOP -ID 12"
" fbtrace -LIST -OUTPUT stdout"
" -T[RUSTED] <string> Force trusted authentication\n"
"\n"
"Examples: \n"
" fbtracemgr -LIST\n"
" fbtracemgr -START -NAME my_trace -CONFIG my_cfg.txt\n"
" fbtracemgr -SUSPEND -ID 2\n"
" fbtracemgr -RESUME -ID 2\n"
" fbtracemgr -STOP -ID 4\n"
"\n"
"Notes:\n"
" Press CTRL+C to stop interactive trace session"
" Press CTRL+C to stop interactive trace session\n"
);
exit(FINI_ERROR);
}
@ -131,7 +137,8 @@ static const in_sw_tab_t* findSwitch(const in_sw_tab_t* table, string sw)
for (const in_sw_tab_t* in_sw_tab = table; in_sw_tab->in_sw_name; in_sw_tab++)
{
if (switchMatch(sw, in_sw_tab->in_sw_name))
if ((sw.length() >= in_sw_tab->in_sw_min_length) &&
switchMatch(sw, in_sw_tab->in_sw_name))
{
return in_sw_tab;
}
@ -147,8 +154,10 @@ const char TRACE_ERR_PARAM_VAL_MISS[] = "value for switch \"%s\" is missing";
const char TRACE_ERR_PARAM_INVALID[] = "invalid value (\"%s\") for switch \"%s\"";
const char TRACE_ERR_SWITCH_UNKNOWN[] = "unknown switch \"%s\" encountered";
const char TRACE_ERR_SWITCH_SVC_ONLY[] = "switch \"%s\" can be used by service only";
const char TRACE_ERR_SWITCH_USER_ONLY[] = "switch \"%s\" can be used by user only";
const char TRACE_ERR_SWITCH_PARAM_MISS[] = "mandatory parameter \"%s\" for switch \"%s\" is missing";
const char TRACE_ERR_PARAM_ACT_NOTCOMPAT[] = "parameter \"%s\" is incompatible with action \"%s\"";
const char TRACE_ERR_MANDATORY_SWITCH_MISS[]= "mandatory switch \"%s\" is missing";
void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc)
@ -301,6 +310,47 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc)
usage(uSvc, TRACE_ERR_PARAM_VAL_MISS, sw->in_sw_name);
break;
case IN_SW_TRACE_FETCH_PWD:
if (uSvc->isService())
usage(uSvc, TRACE_ERR_SWITCH_USER_ONLY, sw->in_sw_name);
if (!pwd.empty())
usage(uSvc, TRACE_ERR_SWITCH_ONCE, sw->in_sw_name);
argv++;
if (argv < end)
{
const PathName fileName(*argv);
const char *s = NULL;
switch (fb_utils::fetchPassword(fileName, s))
{
case fb_utils::FETCH_PASS_OK:
pwd = s;
break;
case fb_utils::FETCH_PASS_FILE_OPEN_ERROR:
(Arg::Gds(isc_io_error) << Arg::Str("open") << Arg::Str(fileName) <<
Arg::Gds(isc_io_open_err) << Arg::OsError()).raise();
break;
case fb_utils::FETCH_PASS_FILE_READ_ERROR:
case fb_utils::FETCH_PASS_FILE_EMPTY:
(Arg::Gds(isc_io_error) << Arg::Str("read") << Arg::Str(fileName) <<
Arg::Gds(isc_io_read_err) << Arg::OsError()).raise();
break;
}
}
else
usage(uSvc, TRACE_ERR_PARAM_VAL_MISS, sw->in_sw_name);
break;
case IN_SW_TRACE_TRUSTED_AUTH:
if (uSvc->isService())
usage(uSvc, TRACE_ERR_SWITCH_USER_ONLY, sw->in_sw_name);
adminRole = true;
break;
case IN_SW_TRACE_TRUSTED_USER:
if (!uSvc->isService())
usage(uSvc, TRACE_ERR_SWITCH_SVC_ONLY, sw->in_sw_name);
@ -334,6 +384,7 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc)
svc_name = *argv;
else
usage(uSvc, TRACE_ERR_PARAM_VAL_MISS, sw->in_sw_name);
break;
default:
fb_assert(false);
@ -341,6 +392,10 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc)
}
// validate missed action's parameters and perform action
if (!uSvc->isService() && svc_name.isEmpty()) {
usage(uSvc, TRACE_ERR_MANDATORY_SWITCH_MISS, "SERVICE");
}
if (!session.ses_id)
{
switch (action_sw->in_sw)

View File

@ -34,7 +34,6 @@
#include "../../common/config/config.h"
#include "../../common/StatusArg.h"
#include "../../common/thd.h"
#include "../../jrd/ThreadData.h"
#include "../../jrd/svc.h"
#include "../../jrd/os/guid.h"
#include "../../jrd/trace/TraceLog.h"
@ -63,9 +62,9 @@ public:
virtual void stopSession(ULONG id);
virtual void setActive(ULONG id, bool active);
virtual void listSessions();
virtual void readSession(TraceSession& session);
private:
void readSession(TraceSession& session);
bool changeFlags(ULONG id, int setFlags, int clearFlags);
bool checkAliveAndFlags(ULONG sesId, int& flags);

View File

@ -54,16 +54,18 @@ const int IN_SW_TRACE_PASSWORD = 10;
const int IN_SW_TRACE_TRUSTED_USER = 11;
const int IN_SW_TRACE_TRUSTED_ROLE = 12;
const int IN_SW_TRACE_SERVICE_NAME = 13;
const int IN_SW_TRACE_FETCH_PWD = 14;
const int IN_SW_TRACE_TRUSTED_AUTH = 15;
// list of possible actions (services) for use with trace services
static const struct in_sw_tab_t trace_action_in_sw_table [] =
{
{IN_SW_TRACE_LIST, isc_action_svc_trace_list, "LIST", 0, 0, 0, false, 0, 1, NULL},
{IN_SW_TRACE_RESUME, isc_action_svc_trace_resume, "RESUME", 0, 0, 0, false, 0, 1, NULL},
{IN_SW_TRACE_STOP, isc_action_svc_trace_stop, "STOP", 0, 0, 0, false, 0, 3, NULL},
{IN_SW_TRACE_START, isc_action_svc_trace_start, "START", 0, 0, 0, false, 0, 3, NULL},
{IN_SW_TRACE_SUSPEND, isc_action_svc_trace_suspend,"SUSPEND", 0, 0, 0, false, 0, 1, NULL},
{IN_SW_TRACE_LIST, isc_action_svc_trace_list, "LIST", 0, 0, 0, false, 0, 1, NULL},
{IN_SW_TRACE_RESUME, isc_action_svc_trace_resume, "RESUME", 0, 0, 0, false, 0, 1, NULL},
{IN_SW_TRACE_STOP, isc_action_svc_trace_stop, "STOP", 0, 0, 0, false, 0, 3, NULL},
{IN_SW_TRACE_START, isc_action_svc_trace_start, "START", 0, 0, 0, false, 0, 3, NULL},
{IN_SW_TRACE_SUSPEND, isc_action_svc_trace_suspend, "SUSPEND", 0, 0, 0, false, 0, 1, NULL},
{0, 0, NULL, 0, 0, 0, false, 0, 0, NULL} // End of List
};
@ -80,8 +82,10 @@ static const struct in_sw_tab_t trace_option_in_sw_table [] =
// authentication switches, common for all utils (services)
static const struct in_sw_tab_t trace_auth_in_sw_table [] =
{
{IN_SW_TRACE_FETCH_PWD, 0, "FETCH_PASSWORD", 0, 0, 0, false, 0, 2, NULL},
{IN_SW_TRACE_PASSWORD, 0, PASSWORD_SWITCH, 0, 0, 0, false, 0, 1, NULL},
{IN_SW_TRACE_SERVICE_NAME, 0, "SERVICE", 0, 0, 0, false, 0, 2, NULL},
{IN_SW_TRACE_TRUSTED_AUTH, 0, "TRUSTED", 0, 0, 0, false, 0, 1, NULL},
{IN_SW_TRACE_TRUSTED_USER, 0, TRUSTED_USER_SWITCH, 0, 0, 0, false, 0, 9, NULL},
{IN_SW_TRACE_TRUSTED_ROLE, 0, TRUSTED_ROLE_SWITCH, 0, 0, 0, false, 0, 9, NULL},
{IN_SW_TRACE_USERNAME, 0, USERNAME_SWITCH, 0, 0, 0, false, 0, 1, NULL},
@ -100,7 +104,6 @@ public:
virtual void stopSession(ULONG id) = 0;
virtual void setActive(ULONG id, bool active) = 0;
virtual void listSessions() = 0;
virtual void readSession(TraceSession& ) = 0;
virtual ~TraceSvcIntf() { }
};

View File

@ -0,0 +1,342 @@
/*
* PROGRAM: Firebird utilities
* MODULE: traceMgrMain.cpp
* DESCRIPTION: Trace Manager utility
*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Vladyslav Khorsun
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2009 Vladyslav Khorsun <hvlad@users.sourceforge.net>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*
*/
#include "firebird.h"
#include <signal.h>
#include "../../common/classes/auto.h"
#include "../../common/classes/ClumpletWriter.h"
#include "../../common/utils_proto.h"
#include "../../jrd/trace/TraceService.h"
#include "../../jrd/ibase.h"
namespace Firebird {
class TraceSvcUtil : public TraceSvcIntf
{
public:
TraceSvcUtil();
virtual ~TraceSvcUtil();
virtual void setAttachInfo(const string& service_name, const string& user,
const string& pwd, bool isAdmin);
virtual void startSession(TraceSession& session, bool interactive);
virtual void stopSession(ULONG id);
virtual void setActive(ULONG id, bool active);
virtual void listSessions();
static void stopRead();
private:
void runService(size_t spbSize, const UCHAR* spb);
isc_svc_handle m_svcHandle;
static bool m_stop;
};
const int MAXBUF = 16384;
bool TraceSvcUtil::m_stop = true;
TraceSvcUtil::TraceSvcUtil()
{
m_svcHandle = 0;
}
TraceSvcUtil::~TraceSvcUtil()
{
if (m_svcHandle)
{
ISC_STATUS_ARRAY status = {0};
isc_service_detach(status, &m_svcHandle);
}
}
void TraceSvcUtil::setAttachInfo(const string& service_name, const string& user,
const string& pwd, bool isAdmin)
{
ISC_STATUS_ARRAY status = {0};
ClumpletWriter spb(ClumpletWriter::SpbAttach, MAXBUF, isc_spb_current_version);
if (user.isEmpty() && !isAdmin)
{
string isc_user;
if (fb_utils::readenv(ISC_USER, isc_user)) {
spb.insertString(isc_spb_user_name, isc_user);
}
}
else if (user.hasData()) {
spb.insertString(isc_spb_user_name, user);
}
if (pwd.isEmpty() && !isAdmin)
{
string isc_pwd;
if (fb_utils::readenv(ISC_PASSWORD, isc_pwd)) {
spb.insertString(isc_spb_password, isc_pwd);
}
}
else if (pwd.hasData()) {
spb.insertString(isc_spb_password, pwd);
}
if (isAdmin) {
spb.insertTag(isc_spb_trusted_auth);
}
if (isc_service_attach(status, 0, service_name.c_str(), &m_svcHandle,
static_cast<USHORT>(spb.getBufferLength()),
reinterpret_cast<const char*>(spb.getBuffer())))
{
status_exception::raise(status);
}
}
void TraceSvcUtil::startSession(TraceSession& session, bool /*interactive*/)
{
m_stop = false;
HalfStaticArray<UCHAR, 1024> buff(*getDefaultMemoryPool());
UCHAR* p = NULL;
long len = 0;
FILE* file = NULL;
try
{
const char* fileName = session.ses_config.c_str();
file = fopen(fileName, "rb");
if (!file) {
(Arg::Gds(isc_io_error) << Arg::Str("fopen") << Arg::Str(fileName) <<
Arg::Gds(isc_io_open_err) << Arg::OsError()).raise();
}
fseek(file, 0, SEEK_END);
len = ftell(file);
if (len == 0) {
(Arg::Gds(isc_io_error) << Arg::Str("fread") << Arg::Str(fileName) <<
Arg::Gds(isc_io_read_err) << Arg::OsError()).raise();
}
fseek(file, 0, SEEK_SET);
p = buff.getBuffer(len);
if (fread(p, 1, len, file) != len) {
(Arg::Gds(isc_io_error) << Arg::Str("fread") << Arg::Str(fileName) <<
Arg::Gds(isc_io_read_err) << Arg::OsError()).raise();
}
fclose(file);
}
catch (const Exception&)
{
if (file)
fclose(file);
throw;
}
ClumpletWriter spb(ClumpletWriter::SpbStart, MAXBUF);
spb.insertTag(isc_action_svc_trace_start);
spb.insertBytes(isc_spb_trc_cfg, p, len);
if (session.ses_name.hasData())
{
spb.insertBytes(isc_spb_trc_name,
reinterpret_cast<const UCHAR*> (session.ses_name.c_str()),
session.ses_name.length());
}
runService(spb.getBufferLength(), spb.getBuffer());
}
void TraceSvcUtil::stopSession(ULONG id)
{
ClumpletWriter spb(ClumpletWriter::SpbStart, MAXBUF);
spb.insertTag(isc_action_svc_trace_stop);
spb.insertInt(isc_spb_trc_id, id);
runService(spb.getBufferLength(), spb.getBuffer());
}
void TraceSvcUtil::setActive(ULONG id, bool active)
{
ClumpletWriter spb(ClumpletWriter::SpbStart, MAXBUF);
spb.insertTag(active ? isc_action_svc_trace_resume : isc_action_svc_trace_suspend);
spb.insertInt(isc_spb_trc_id, id);
runService(spb.getBufferLength(), spb.getBuffer());
}
void TraceSvcUtil::listSessions()
{
ClumpletWriter spb(ClumpletWriter::SpbStart, MAXBUF);
spb.insertTag(isc_action_svc_trace_list);
runService(spb.getBufferLength(), spb.getBuffer());
}
void TraceSvcUtil::stopRead()
{
m_stop = true;
}
void TraceSvcUtil::runService(size_t spbSize, const UCHAR* spb)
{
ISC_STATUS_ARRAY status;
if (isc_service_start(status, &m_svcHandle, 0,
static_cast<USHORT>(spbSize),
reinterpret_cast<const char*>(spb)))
{
status_exception::raise(status);
}
const char query[] = {isc_info_svc_to_eof, isc_info_end};
const char send[] = {isc_info_svc_timeout, 2, 0, 1, 0, 0, 0, isc_info_end};
char results[MAXBUF];
do
{
if (isc_service_query(status, &m_svcHandle, 0, sizeof(send), send,
sizeof(query), query,
sizeof(results) - 1, results))
{
status_exception::raise(status);
}
char *p = results;
bool ignoreTruncation = false;
while (*p != isc_info_end)
{
const char item = *p++;
switch (item)
{
case isc_info_svc_to_eof:
ignoreTruncation = true;
case isc_info_svc_line:
{
unsigned short l = isc_vax_integer (p, sizeof(l));
p += sizeof(l);
if (l)
{
char ch = p[l];
p[l] = 0;
fprintf(stdout, "%s", p);
p[l] = ch;
p += l;
}
else
m_stop = true;
}
break;
case isc_info_truncated:
if (!ignoreTruncation)
{
//printf("%s\n", getMessage(18).c_str());
return;
}
break;
case isc_info_svc_timeout:
m_stop = false;
break;
default:
status_exception::raise(Arg::Gds(isc_fbsvcmgr_query_err) <<
Arg::Num(static_cast<unsigned char>(p[-1])));
}
}
} while (!m_stop);
}
} // namespace Firebird
using namespace Firebird;
typedef void (*SignalHandlerPointer)(int);
static SignalHandlerPointer prevCtrlCHandler = NULL;
static bool terminated = false;
static void ctrl_c_handler(int signal)
{
if (signal == SIGINT)
TraceSvcUtil::stopRead();
if (prevCtrlCHandler)
prevCtrlCHandler(signal);
}
int CLIB_ROUTINE main(int argc, char* argv[])
{
/**************************************
*
* m a i n
*
**************************************
*
* Functional description
* Invoke real nbackup main function
*
**************************************/
prevCtrlCHandler = signal(SIGINT, ctrl_c_handler);
AutoPtr<UtilSvc> uSvc(UtilSvc::createStandalone(argc, argv));
try
{
TraceSvcUtil traceUtil;
fbtrace(uSvc, &traceUtil);
}
catch (const Firebird::Exception& ex)
{
ISC_STATUS_ARRAY temp;
ex.stuff_exception(temp);
isc_print_status(temp);
return FINI_ERROR;
}
return FINI_OK;
}