mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 00:03:02 +01:00
fixed AV related with SVC_TRMNTR in services
This commit is contained in:
parent
b2e0ecd141
commit
028ab3c597
@ -105,7 +105,7 @@ static void expand_filename(const TEXT*, TEXT*);
|
||||
#ifndef SERVICE_THREAD
|
||||
static int output_main(Jrd::Service*, const UCHAR*);
|
||||
#endif
|
||||
static int common_main(int, char**, Jrd::pfn_svc_output, Jrd::Service*);
|
||||
static int common_main(int, const char**, Jrd::pfn_svc_output, Jrd::Service*);
|
||||
static void alice_output(const SCHAR*, ...) ATTRIBUTE_FORMAT(1,2);
|
||||
|
||||
|
||||
@ -133,7 +133,7 @@ static int output_svc(Jrd::Service* output_data, const UCHAR * output_buf)
|
||||
THREAD_ENTRY_DECLARE ALICE_main(THREAD_ENTRY_PARAM arg)
|
||||
{
|
||||
Jrd::Service* service = (Jrd::Service*)arg;
|
||||
const int exit_code = common_main(service->svc_argc, service->svc_argv,
|
||||
const int exit_code = common_main(service->svc_argc, service->svc_argv.begin(),
|
||||
SVC_output, service);
|
||||
|
||||
// Mark service thread as finished.
|
||||
@ -155,7 +155,7 @@ THREAD_ENTRY_DECLARE ALICE_main(THREAD_ENTRY_PARAM arg)
|
||||
// Call the 'real' main.
|
||||
//
|
||||
|
||||
int CLIB_ROUTINE main(int argc, char* argv[])
|
||||
int CLIB_ROUTINE main(int argc, const char** argv)
|
||||
{
|
||||
const int exit_code = common_main(argc, argv, output_main, NULL);
|
||||
|
||||
@ -182,8 +182,8 @@ static int output_main(Jrd::Service* output_data, const UCHAR* output_buf)
|
||||
// Parse switches and do work
|
||||
//
|
||||
|
||||
int common_main(int argc,
|
||||
char* argv[],
|
||||
int common_main(int argc,
|
||||
const char* argv[],
|
||||
Jrd::pfn_svc_output output_proc,
|
||||
Jrd::Service* output_data)
|
||||
{
|
||||
@ -464,14 +464,14 @@ int common_main(int argc,
|
||||
if (--argc <= 0) {
|
||||
ALICE_error(13); // msg 13: user name required
|
||||
}
|
||||
tdgbl->ALICE_data.ua_user = reinterpret_cast<UCHAR*>(*argv++);
|
||||
tdgbl->ALICE_data.ua_user = reinterpret_cast<const UCHAR*>(*argv++);
|
||||
}
|
||||
|
||||
if (table->in_sw_value & sw_password) {
|
||||
if (--argc <= 0) {
|
||||
ALICE_error(14); // msg 14: password required
|
||||
}
|
||||
tdgbl->ALICE_data.ua_password = reinterpret_cast<UCHAR*>(*argv++);
|
||||
tdgbl->ALICE_data.ua_password = reinterpret_cast<const UCHAR*>(*argv++);
|
||||
}
|
||||
|
||||
if (table->in_sw_value & sw_disable) {
|
||||
|
@ -186,8 +186,9 @@ THREAD_ENTRY_DECLARE BURP_main(THREAD_ENTRY_PARAM arg)
|
||||
*
|
||||
**************************************/
|
||||
Jrd::Service* service = (Jrd::Service*)arg;
|
||||
const int exit_code = common_main(service->svc_argc, service->svc_argv,
|
||||
SVC_output, service);
|
||||
const int exit_code = common_main(service->svc_argc,
|
||||
const_cast<char**>(service->svc_argv.begin()),
|
||||
SVC_output, service);
|
||||
|
||||
// Mark service thread as finished.
|
||||
// If service is detached, cleanup memory being used by service.
|
||||
|
308
src/jrd/svc.cpp
308
src/jrd/svc.cpp
@ -130,8 +130,9 @@ const TEXT SVC_TRMNTR = '\377';
|
||||
|
||||
namespace Jrd {
|
||||
Service::Service(serv_entry *se, Firebird::MemoryPool& p) :
|
||||
svc_parsed_sw(p),
|
||||
svc_handle(0), svc_status(svc_status_array), svc_input(0), svc_output(0),
|
||||
svc_stdout_head(0), svc_stdout_tail(0), svc_stdout(0), svc_argv(0), svc_argc(0),
|
||||
svc_stdout_head(0), svc_stdout_tail(0), svc_stdout(0), svc_argv(p), svc_argc(0),
|
||||
svc_service(se), svc_resp_buf(0), svc_resp_ptr(0), svc_resp_buf_len(0),
|
||||
svc_resp_len(0), svc_flags(0), svc_user_flag(0), svc_spb_version(0), svc_do_shutdown(false),
|
||||
svc_username(p), svc_enc_password(p), svc_switches(p), svc_perm_sw(p)
|
||||
@ -163,10 +164,6 @@ namespace Jrd {
|
||||
{
|
||||
gds__free(svc_stdout);
|
||||
}
|
||||
if (svc_argv)
|
||||
{
|
||||
gds__free(svc_argv);
|
||||
}
|
||||
#endif //SERVICE_THREAD
|
||||
|
||||
if (svc_resp_buf)
|
||||
@ -178,6 +175,66 @@ namespace Jrd {
|
||||
CloseHandle((HANDLE) svc_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Service::parseSwitches()
|
||||
{
|
||||
svc_parsed_sw = svc_switches;
|
||||
svc_parsed_sw.trim();
|
||||
svc_argc = 2;
|
||||
|
||||
if (svc_parsed_sw.isEmpty())
|
||||
{
|
||||
svc_parsed_sw.c_str();
|
||||
svc_argv.getBuffer(svc_argc + 1)[1] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
bool inStr = false;
|
||||
for (size_t i = 0; i < svc_parsed_sw.length(); ++i)
|
||||
{
|
||||
|
||||
switch (svc_parsed_sw[i])
|
||||
{
|
||||
case SVC_TRMNTR:
|
||||
svc_parsed_sw.erase(i, 1);
|
||||
if (inStr)
|
||||
{
|
||||
if (i < svc_parsed_sw.length() && svc_parsed_sw[i] != SVC_TRMNTR)
|
||||
{
|
||||
inStr = false;
|
||||
--i;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
inStr = true;
|
||||
--i;
|
||||
}
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
if (!inStr)
|
||||
{
|
||||
++svc_argc;
|
||||
svc_parsed_sw[i] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char** argv = svc_argv.getBuffer(svc_argc + 1);
|
||||
argv++; // leave space for argv[0]
|
||||
*argv++ = svc_parsed_sw.c_str();
|
||||
for (const char *p = svc_parsed_sw.begin();
|
||||
p < svc_parsed_sw.end(); ++p)
|
||||
{
|
||||
if (!*p)
|
||||
{
|
||||
*argv++ = p + 1;
|
||||
}
|
||||
}
|
||||
*argv = 0;
|
||||
}
|
||||
} //namespace
|
||||
|
||||
using namespace Jrd;
|
||||
@ -549,7 +606,6 @@ Service* SVC_attach(USHORT service_length,
|
||||
service->svc_stdout_head = 1;
|
||||
service->svc_stdout_tail = SVC_STDOUT_BUFFER_SIZE;
|
||||
service->svc_stdout = NULL;
|
||||
service->svc_argv = NULL;
|
||||
#endif
|
||||
service->svc_spb_version = options.spb_version;
|
||||
service->svc_username = options.spb_user_name;
|
||||
@ -1767,78 +1823,8 @@ void* SVC_start(Service* service, USHORT spb_length, const SCHAR* spb_data)
|
||||
#else
|
||||
|
||||
/* Break up the command line into individual arguments. */
|
||||
if (service->svc_switches.hasData())
|
||||
{
|
||||
USHORT argc;
|
||||
TEXT* p;
|
||||
for (argc = 2, p = service->svc_switches.begin(); *p;) {
|
||||
if (*p == ' ') {
|
||||
argc++;
|
||||
while (*p == ' ')
|
||||
p++;
|
||||
}
|
||||
else {
|
||||
if (*p == SVC_TRMNTR) {
|
||||
while (*p++ && *p != SVC_TRMNTR);
|
||||
fb_assert(*p == SVC_TRMNTR);
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
service->svc_argc = argc;
|
||||
|
||||
TEXT** arg = (TEXT **) gds__alloc((SLONG) ((argc + 1) * sizeof(TEXT *)));
|
||||
/*
|
||||
* the service block can be reused hence free a memory from the
|
||||
* previous usage if any.
|
||||
*/
|
||||
if (service->svc_argv)
|
||||
gds__free(service->svc_argv);
|
||||
service->svc_argv = arg;
|
||||
/* FREE: at SVC_detach() - Possible memory leak if ERR_post() occurs */
|
||||
if (!arg) /* NOMEM: */
|
||||
ERR_post(isc_virmemexh, 0);
|
||||
|
||||
*arg++ = (TEXT *)(serv->serv_thd);
|
||||
const TEXT* q = p = service->svc_switches.begin();
|
||||
|
||||
while (*q == ' ')
|
||||
q++;
|
||||
|
||||
while (*q) {
|
||||
*arg = p;
|
||||
while (*p = *q++) {
|
||||
if (*p == ' ')
|
||||
break;
|
||||
|
||||
if (*p == SVC_TRMNTR) {
|
||||
*arg = ++p; /* skip terminator */
|
||||
while (*p = *q++)
|
||||
/* If *q points to the last argument, then terminate the argument */
|
||||
if ((*q == 0 || *q == ' ') && *p == SVC_TRMNTR) {
|
||||
*p = '\0';
|
||||
break;
|
||||
}
|
||||
else
|
||||
p++;
|
||||
}
|
||||
|
||||
if (*p == '\\' && *q == ' ') {
|
||||
*p = ' ';
|
||||
q++;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
arg++;
|
||||
if (!*p)
|
||||
break;
|
||||
*p++ = '\0';
|
||||
while (*q == ' ')
|
||||
q++;
|
||||
}
|
||||
*arg = NULL;
|
||||
}
|
||||
service->parseSwitches();
|
||||
service->svc_argv[0] = (TEXT *)(serv->serv_thd);
|
||||
|
||||
/*
|
||||
* the service block can be reused hence free a memory from the
|
||||
@ -2191,48 +2177,11 @@ static void service_fork(ThreadEntryPoint* service_executable, Service* service)
|
||||
**************************************/
|
||||
TEXT* p;
|
||||
|
||||
USHORT argc = 2;
|
||||
for (p = service->svc_switches.begin(); *p;)
|
||||
if (*p++ == ' ')
|
||||
argc++;
|
||||
|
||||
service->svc_argc = argc;
|
||||
|
||||
TEXT** arg = (TEXT **) gds__alloc((SLONG) ((argc + 1) * sizeof(TEXT *)));
|
||||
service->svc_argv = arg;
|
||||
/* FREE: at SVC_detach() - Possible memory leak if ERR_post() occurs */
|
||||
if (!arg) /* NOMEM: */
|
||||
ERR_post(isc_virmemexh, 0);
|
||||
|
||||
*arg++ = (TEXT *)(service_executable);
|
||||
|
||||
/* Break up the command line into individual arguments. */
|
||||
|
||||
const TEXT* q = p = service->svc_switches.begin();
|
||||
|
||||
while (*q == ' ')
|
||||
q++;
|
||||
while (*q) {
|
||||
*arg++ = p;
|
||||
while ((*p = *q++) && *p != ' ') {
|
||||
if (*p == '\\' && *q == ' ') {
|
||||
*p = ' ';
|
||||
q++;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
if (!*p)
|
||||
break;
|
||||
*p++ = 0;
|
||||
while (*q == ' ')
|
||||
q++;
|
||||
}
|
||||
*arg = NULL;
|
||||
|
||||
service->svc_stdout = (UCHAR*)gds__alloc((SLONG) SVC_STDOUT_BUFFER_SIZE + 1);
|
||||
/* FREE: at SVC_detach() */
|
||||
if (!service->svc_stdout) /* NOMEM: */
|
||||
ERR_post(isc_virmemexh, 0);
|
||||
service->parseSwitches();
|
||||
|
||||
USHORT argc = service->svc_argc;
|
||||
service->svc_argv[0] = (TEXT *)(service_executable);
|
||||
|
||||
THREAD_EXIT();
|
||||
gds__thread_start(service_executable,
|
||||
@ -2403,104 +2352,10 @@ static void service_fork(TEXT* service_path, Service* service)
|
||||
if (statistics(service_path, &stat_buf) == -1)
|
||||
io_error("stat", errno, service_path, isc_io_access_err);
|
||||
|
||||
/* Make sure we have buffers that are large enough to hold the number
|
||||
and size of the command line arguments. */
|
||||
|
||||
TEXT* p;
|
||||
|
||||
USHORT argc = 2;
|
||||
for (p = service->svc_switches.begin(); *p;)
|
||||
{
|
||||
if (*p == ' ')
|
||||
{
|
||||
argc++;
|
||||
while (*p == ' ')
|
||||
p++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*p == SVC_TRMNTR)
|
||||
{
|
||||
while (*p++ && *p != SVC_TRMNTR);
|
||||
fb_assert (*p == SVC_TRMNTR);
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
// Hardcoded, ISC_STATUS_LEN, platform specific or what????
|
||||
TEXT* argv_buf[20];
|
||||
TEXT** argv;
|
||||
if (argc > FB_NELEM(argv_buf))
|
||||
argv = (TEXT **) gds__alloc((SLONG) (argc * sizeof(TEXT *)));
|
||||
else
|
||||
argv = argv_buf;
|
||||
/* FREE: at procedure return */
|
||||
if (!argv) /* NOMEM: */
|
||||
ERR_post(isc_virmemexh, 0);
|
||||
service->svc_argc = argc;
|
||||
|
||||
TEXT argv_data_buf[512];
|
||||
TEXT* argv_data;
|
||||
const USHORT len = service->svc_switches.length() + 1;
|
||||
if (len > sizeof(argv_data_buf))
|
||||
argv_data = (TEXT *) gds__alloc((SLONG) len);
|
||||
else
|
||||
argv_data = argv_data_buf;
|
||||
/* FREE: at procedure return */
|
||||
if (!argv_data) { /* NOMEM: */
|
||||
if (argv != argv_buf)
|
||||
gds__free(argv);
|
||||
ERR_post(isc_virmemexh, 0);
|
||||
}
|
||||
|
||||
/* Break up the command line into individual arguments. */
|
||||
|
||||
TEXT** arg = argv;
|
||||
*arg++ = service_path;
|
||||
|
||||
p = argv_data;
|
||||
const TEXT* q = service->svc_switches.c_str();
|
||||
|
||||
while (*q == ' ')
|
||||
q++;
|
||||
while (*q)
|
||||
{
|
||||
*arg = p;
|
||||
while (*p = *q++)
|
||||
{
|
||||
if (*p == ' ')
|
||||
break;
|
||||
|
||||
if (*p == SVC_TRMNTR)
|
||||
{
|
||||
*arg = ++p; /* skip terminator */
|
||||
while (*p = *q++)
|
||||
/* If *q points to the last argument, then terminate the argument */
|
||||
if ((*q == 0 || *q == ' ') && *p == SVC_TRMNTR)
|
||||
{
|
||||
*p = '\0';
|
||||
break;
|
||||
}
|
||||
else
|
||||
p++;
|
||||
}
|
||||
|
||||
if (*p == '\\' && *q == ' ')
|
||||
{
|
||||
*p = ' ';
|
||||
q++;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
arg++;
|
||||
if (!*p)
|
||||
break;
|
||||
*p++ = '\0';
|
||||
while (*q == ' ')
|
||||
q++;
|
||||
}
|
||||
*arg = NULL;
|
||||
service->parseSwitches();
|
||||
const char **argv = &service->svc_argv[0];
|
||||
*argv = service_path;
|
||||
|
||||
/* At last we can fork the sub-process. If the fork succeeds, repeat
|
||||
it so that we don't have defunct processes hanging around. */
|
||||
@ -2512,10 +2367,6 @@ static void service_fork(TEXT* service_path, Service* service)
|
||||
switch (pid = vfork()) {
|
||||
case -1:
|
||||
THREAD_ENTER();
|
||||
if (argv != argv_buf)
|
||||
gds__free(argv);
|
||||
if (argv_data != argv_data_buf)
|
||||
gds__free(argv_data);
|
||||
ERR_post(isc_sys_request, isc_arg_string, "vfork", SYS_ERR, errno, 0);
|
||||
break;
|
||||
|
||||
@ -2540,7 +2391,7 @@ static void service_fork(TEXT* service_path, Service* service)
|
||||
#ifdef DEV_BUILD
|
||||
{
|
||||
char buf[2 * MAXPATHLEN];
|
||||
char** s = argv;
|
||||
const char** s = argv;
|
||||
|
||||
strcpy (buf, "service_fork:");
|
||||
while (*s != (char *)0)
|
||||
@ -2552,7 +2403,7 @@ static void service_fork(TEXT* service_path, Service* service)
|
||||
gds__log(buf);
|
||||
}
|
||||
#endif
|
||||
execvp(argv[0], argv);
|
||||
execvp(argv[0], const_cast<char* const*>(argv));
|
||||
_exit(FINI_ERROR);
|
||||
}
|
||||
|
||||
@ -2563,11 +2414,6 @@ static void service_fork(TEXT* service_path, Service* service)
|
||||
|
||||
THREAD_ENTER();
|
||||
|
||||
if (argv != argv_buf)
|
||||
gds__free(argv);
|
||||
if (argv_data != argv_data_buf)
|
||||
gds__free(argv_data);
|
||||
|
||||
if (!(service->svc_input = fdopen(pair1[0], "r")) ||
|
||||
!(service->svc_output = fdopen(pair2[1], "w")))
|
||||
{
|
||||
@ -3136,6 +2982,14 @@ static void get_action_svc_string(const Firebird::ClumpletReader& spb,
|
||||
**************************************/
|
||||
Firebird::string s;
|
||||
spb.getString(s);
|
||||
for (size_t i = 0; i < s.length(); ++i)
|
||||
{
|
||||
if (s[i] == SVC_TRMNTR)
|
||||
{
|
||||
s.insert(i, 1, SVC_TRMNTR);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
switches += SVC_TRMNTR;
|
||||
switches += s;
|
||||
switches += SVC_TRMNTR;
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
#include "../jrd/jrd_blks.h"
|
||||
#include "../include/fb_blk.h"
|
||||
#include "../common/classes/array.h"
|
||||
|
||||
void SVC_STATUS_ARG(ISC_STATUS*& status, USHORT type, const void* value);
|
||||
|
||||
@ -102,6 +103,8 @@ class Service : public pool_alloc<type_svc>
|
||||
{
|
||||
private:
|
||||
ISC_STATUS_ARRAY svc_status_array;
|
||||
Firebird::string svc_parsed_sw; // Here point elements of svc_argv
|
||||
|
||||
public:
|
||||
Service(serv_entry *se, Firebird::MemoryPool& p);
|
||||
~Service();
|
||||
@ -113,7 +116,7 @@ public:
|
||||
ULONG svc_stdout_head;
|
||||
ULONG svc_stdout_tail;
|
||||
UCHAR* svc_stdout;
|
||||
TEXT** svc_argv;
|
||||
Firebird::HalfStaticArray<const char*, 20> svc_argv;
|
||||
ULONG svc_argc;
|
||||
event_t svc_start_event[1]; /* fired once service has started successfully */
|
||||
serv_entry* svc_service;
|
||||
@ -132,6 +135,7 @@ public:
|
||||
// and/or passed using spb_command_line
|
||||
|
||||
void svc_started();
|
||||
void parseSwitches(); // Create svc_argv, svc_argc and svc_parsed_sw
|
||||
};
|
||||
|
||||
/* Bitmask values for the svc_flags variable */
|
||||
|
@ -69,7 +69,7 @@ const int MAXSTUFF = 1000; /* longest interactive command line */
|
||||
class tsec *gdsec;
|
||||
#endif
|
||||
|
||||
static int common_main(int, char**, Jrd::pfn_svc_output, Jrd::Service*);
|
||||
static int common_main(int, const char**, Jrd::pfn_svc_output, Jrd::Service*);
|
||||
static void util_output(const SCHAR*, ...);
|
||||
|
||||
static void data_print(void*, const internal_user_data*, bool);
|
||||
@ -101,7 +101,7 @@ THREAD_ENTRY_DECLARE GSEC_main(THREAD_ENTRY_PARAM arg)
|
||||
* Entrypoint for GSEC via the services manager
|
||||
**********************************************/
|
||||
Jrd::Service* service = (Jrd::Service*)arg;
|
||||
const int exit_code = common_main(service->svc_argc, service->svc_argv,
|
||||
const int exit_code = common_main(service->svc_argc, service->svc_argv.begin(),
|
||||
SVC_output, service);
|
||||
|
||||
/* Mark service thread as finished. */
|
||||
@ -113,7 +113,7 @@ THREAD_ENTRY_DECLARE GSEC_main(THREAD_ENTRY_PARAM arg)
|
||||
|
||||
#else
|
||||
|
||||
int CLIB_ROUTINE main( int argc, char* argv[])
|
||||
int CLIB_ROUTINE main( int argc, const char* argv[])
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -160,7 +160,7 @@ inline void envPick(TEXT* dest, size_t size, const TEXT* var)
|
||||
#endif /* SERVICE_THREAD */
|
||||
|
||||
int common_main(int argc,
|
||||
char* argv[],
|
||||
const char* argv[],
|
||||
Jrd::pfn_svc_output output_proc,
|
||||
Jrd::Service* output_data)
|
||||
{
|
||||
|
@ -337,7 +337,7 @@ int CLIB_ROUTINE main(int argc, char** argv)
|
||||
/* Reinitialize static variables for multi-threading */
|
||||
Jrd::Service* service = (Jrd::Service*)arg;
|
||||
int argc = service->svc_argc;
|
||||
char** argv = service->svc_argv;
|
||||
const char** argv = service->svc_argv.begin();
|
||||
#endif
|
||||
|
||||
ISC_STATUS* status_vector = NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user