From 028ab3c597de8117a6e13d8b6bca9ed5c34a14c0 Mon Sep 17 00:00:00 2001 From: alexpeshkoff Date: Thu, 27 Jul 2006 14:24:09 +0000 Subject: [PATCH] fixed AV related with SVC_TRMNTR in services --- src/alice/alice.cpp | 14 +- src/burp/burp.cpp | 5 +- src/jrd/svc.cpp | 308 ++++++++++-------------------------- src/jrd/svc.h | 6 +- src/utilities/gsec/gsec.cpp | 8 +- src/utilities/gstat/dba.epp | 2 +- 6 files changed, 101 insertions(+), 242 deletions(-) diff --git a/src/alice/alice.cpp b/src/alice/alice.cpp index 5b85df9720..ab740ee16a 100644 --- a/src/alice/alice.cpp +++ b/src/alice/alice.cpp @@ -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(*argv++); + tdgbl->ALICE_data.ua_user = reinterpret_cast(*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(*argv++); + tdgbl->ALICE_data.ua_password = reinterpret_cast(*argv++); } if (table->in_sw_value & sw_disable) { diff --git a/src/burp/burp.cpp b/src/burp/burp.cpp index b1645178f3..f3163c63e9 100644 --- a/src/burp/burp.cpp +++ b/src/burp/burp.cpp @@ -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(service->svc_argv.begin()), + SVC_output, service); // Mark service thread as finished. // If service is detached, cleanup memory being used by service. diff --git a/src/jrd/svc.cpp b/src/jrd/svc.cpp index dbf40c652e..dcbfce47aa 100644 --- a/src/jrd/svc.cpp +++ b/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(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; diff --git a/src/jrd/svc.h b/src/jrd/svc.h index 597f7c5094..dc03a35a5e 100644 --- a/src/jrd/svc.h +++ b/src/jrd/svc.h @@ -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 { 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 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 */ diff --git a/src/utilities/gsec/gsec.cpp b/src/utilities/gsec/gsec.cpp index 86bbeb1c39..a4722ec0a7 100644 --- a/src/utilities/gsec/gsec.cpp +++ b/src/utilities/gsec/gsec.cpp @@ -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) { diff --git a/src/utilities/gstat/dba.epp b/src/utilities/gstat/dba.epp index ccacaf9aba..044ab8acd5 100644 --- a/src/utilities/gstat/dba.epp +++ b/src/utilities/gstat/dba.epp @@ -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;