2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: JRD Access Method
|
2003-10-29 11:53:47 +01:00
|
|
|
* MODULE: svc.cpp
|
2001-05-23 15:26:42 +02:00
|
|
|
* DESCRIPTION: Service manager functions
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Interbase 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.Inprise.com/IPL.html
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an
|
|
|
|
* "AS IS" basis, 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 Inprise Corporation
|
|
|
|
* and its predecessors. Portions created by Inprise Corporation are
|
|
|
|
* Copyright (C) Inprise Corporation.
|
|
|
|
*
|
|
|
|
* All Rights Reserved.
|
|
|
|
* Contributor(s): ______________________________________.
|
2002-02-16 03:21:35 +01:00
|
|
|
*
|
|
|
|
* 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "EPSON" define
|
2002-02-16 04:27:33 +01:00
|
|
|
* 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "IMP" port
|
2002-02-16 03:21:35 +01:00
|
|
|
*
|
2002-10-28 04:47:47 +01:00
|
|
|
* 2002.10.27 Sean Leyne - Completed removal of obsolete "DELTA" port
|
2002-10-28 04:52:09 +01:00
|
|
|
* 2002.10.27 Sean Leyne - Completed removal of obsolete "IMP" port
|
2002-10-28 04:47:47 +01:00
|
|
|
*
|
2002-10-30 07:40:58 +01:00
|
|
|
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
|
|
|
|
*
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
|
2001-07-29 19:42:23 +02:00
|
|
|
#include "firebird.h"
|
2004-04-29 00:43:34 +02:00
|
|
|
#include <stdio.h>
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <string.h>
|
2006-02-03 09:39:36 +01:00
|
|
|
//#include "../common/classes/timestamp.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/common.h"
|
2004-06-08 15:41:08 +02:00
|
|
|
#include "../jrd/thd.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/file_params.h"
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include "../jrd/jrd.h"
|
|
|
|
#include "../jrd/svc.h"
|
2003-02-13 23:38:04 +01:00
|
|
|
#include "../jrd/jrd_pwd.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../alice/aliceswi.h"
|
|
|
|
#include "../burp/burpswi.h"
|
|
|
|
#include "../jrd/ibase.h"
|
2003-11-11 13:19:20 +01:00
|
|
|
#include "gen/iberror.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/license.h"
|
|
|
|
#include "../jrd/err_proto.h"
|
|
|
|
#include "../jrd/gds_proto.h"
|
|
|
|
#include "../jrd/inf_proto.h"
|
|
|
|
#include "../jrd/isc_proto.h"
|
|
|
|
#include "../jrd/jrd_proto.h"
|
|
|
|
#include "../jrd/mov_proto.h"
|
|
|
|
#include "../jrd/sch_proto.h"
|
|
|
|
#include "../jrd/svc_proto.h"
|
2004-05-18 00:30:09 +02:00
|
|
|
#include "../jrd/thread_proto.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/why_proto.h"
|
|
|
|
#include "../jrd/utl_proto.h"
|
|
|
|
#include "../jrd/jrd_proto.h"
|
|
|
|
#include "../jrd/enc_proto.h"
|
2003-07-15 04:43:36 +02:00
|
|
|
#include "../utilities/gsec/gsecswi.h"
|
|
|
|
#include "../utilities/gstat/dbaswi.h"
|
2003-01-16 18:47:10 +01:00
|
|
|
#include "../common/classes/alloc.h"
|
2005-11-27 21:53:09 +01:00
|
|
|
#include "../common/classes/ClumpletWriter.h"
|
|
|
|
#include "../jrd/ibase.h"
|
2006-03-25 08:08:00 +01:00
|
|
|
#include "../common/utils_proto.h"
|
2007-03-02 10:04:30 +01:00
|
|
|
#include "../jrd/scl.h"
|
2005-11-27 21:53:09 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef SERVER_SHUTDOWN
|
|
|
|
#include "../jrd/jrd_proto.h"
|
|
|
|
#endif
|
|
|
|
|
2001-07-12 07:46:06 +02:00
|
|
|
#ifdef HAVE_SYS_TYPES_H
|
|
|
|
#include <sys/types.h>
|
|
|
|
#endif
|
|
|
|
|
2004-05-13 21:47:30 +02:00
|
|
|
#ifdef HAVE_SYS_WAIT_H
|
2002-09-18 14:50:13 +02:00
|
|
|
# include <sys/wait.h>
|
|
|
|
#endif
|
2001-07-12 07:46:06 +02:00
|
|
|
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2002-09-11 13:30:50 +02:00
|
|
|
#ifdef HAVE_VFORK_H
|
|
|
|
#include <vfork.h>
|
|
|
|
#endif
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef SOLARIS
|
|
|
|
#include <fcntl.h>
|
|
|
|
#endif
|
2002-02-16 03:21:35 +01:00
|
|
|
|
|
|
|
#ifdef SCO_UNIX
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <fcntl.h>
|
|
|
|
#endif
|
|
|
|
|
2004-05-03 23:43:56 +02:00
|
|
|
const int SVC_user_dba = 2;
|
|
|
|
const int SVC_user_any = 1;
|
|
|
|
const int SVC_user_none = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#if !defined(WIN_NT)
|
|
|
|
# include <signal.h>
|
|
|
|
# ifndef VMS
|
|
|
|
# include <sys/param.h>
|
|
|
|
# include <sys/stat.h>
|
|
|
|
# else
|
|
|
|
# include <stat.h>
|
|
|
|
# endif
|
|
|
|
# include <errno.h>
|
2003-11-16 13:23:24 +01:00
|
|
|
#else
|
2001-05-23 15:26:42 +02:00
|
|
|
# include <windows.h>
|
2003-11-16 13:23:24 +01:00
|
|
|
# include <io.h> // _open, _get_osfhandle
|
2001-05-23 15:26:42 +02:00
|
|
|
# include <stdlib.h>
|
|
|
|
# include <fcntl.h>
|
|
|
|
# include <sys/stat.h>
|
|
|
|
#endif
|
|
|
|
|
2002-10-28 04:52:09 +01:00
|
|
|
#ifdef VMS
|
2004-11-24 10:22:07 +01:00
|
|
|
#define waitpid(x, y, z) wait (y)
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#define statistics stat
|
|
|
|
|
2004-05-03 23:43:56 +02:00
|
|
|
const int GET_LINE = 1;
|
|
|
|
const int GET_EOF = 2;
|
|
|
|
const int GET_BINARY = 4;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-06 02:18:09 +02:00
|
|
|
const TEXT SVC_TRMNTR = '\377';
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-12-02 17:54:04 +01:00
|
|
|
namespace Jrd {
|
2005-12-02 23:19:57 +01:00
|
|
|
Service::Service(serv_entry *se, Firebird::MemoryPool& p) :
|
2006-07-27 16:24:09 +02:00
|
|
|
svc_parsed_sw(p),
|
2005-12-02 17:54:04 +01:00
|
|
|
svc_handle(0), svc_status(svc_status_array), svc_input(0), svc_output(0),
|
2006-07-27 16:24:09 +02:00
|
|
|
svc_stdout_head(0), svc_stdout_tail(0), svc_stdout(0), svc_argv(p), svc_argc(0),
|
2005-12-02 17:54:04 +01:00
|
|
|
svc_service(se), svc_resp_buf(0), svc_resp_ptr(0), svc_resp_buf_len(0),
|
2005-12-02 23:19:57 +01:00
|
|
|
svc_resp_len(0), svc_flags(0), svc_user_flag(0), svc_spb_version(0), svc_do_shutdown(false),
|
2006-12-08 19:38:15 +01:00
|
|
|
svc_username(p), svc_enc_password(p),
|
2007-04-07 10:47:58 +02:00
|
|
|
#ifdef TRUSTED_SERVICES
|
2006-12-08 19:38:15 +01:00
|
|
|
svc_trusted_login(p),
|
|
|
|
#endif
|
|
|
|
svc_switches(p), svc_perm_sw(p)
|
2005-12-02 23:19:57 +01:00
|
|
|
|
2005-12-02 17:54:04 +01:00
|
|
|
{
|
2005-12-09 06:00:32 +01:00
|
|
|
memset(svc_status_array, 0, sizeof svc_status_array);
|
2005-12-02 17:54:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Service::~Service()
|
|
|
|
{
|
|
|
|
// If we forked an executable, close down it's pipes
|
|
|
|
#ifndef SERVICE_THREAD
|
|
|
|
if (svc_flags & SVC_forked)
|
|
|
|
{
|
|
|
|
#ifndef WIN_NT
|
|
|
|
if (svc_input)
|
|
|
|
{
|
|
|
|
fclose(svc_input);
|
|
|
|
}
|
|
|
|
if (svc_output)
|
|
|
|
{
|
|
|
|
fclose(svc_output);
|
|
|
|
}
|
|
|
|
#endif //WIN_NT
|
|
|
|
}
|
|
|
|
#else //SERVICE_THREAD
|
|
|
|
if (svc_stdout)
|
|
|
|
{
|
|
|
|
gds__free(svc_stdout);
|
|
|
|
}
|
|
|
|
#endif //SERVICE_THREAD
|
|
|
|
|
|
|
|
if (svc_resp_buf)
|
|
|
|
{
|
|
|
|
gds__free(svc_resp_buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef WIN_NT
|
|
|
|
CloseHandle((HANDLE) svc_handle);
|
|
|
|
#endif
|
|
|
|
}
|
2006-07-27 16:24:09 +02:00
|
|
|
|
|
|
|
void Service::parseSwitches()
|
|
|
|
{
|
|
|
|
svc_parsed_sw = svc_switches;
|
|
|
|
svc_parsed_sw.trim();
|
|
|
|
svc_argc = 2;
|
|
|
|
|
|
|
|
if (svc_parsed_sw.isEmpty())
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2005-12-02 17:54:04 +01:00
|
|
|
} //namespace
|
|
|
|
|
2004-03-20 15:57:40 +01:00
|
|
|
using namespace Jrd;
|
|
|
|
|
2007-06-05 09:14:01 +02:00
|
|
|
#ifdef SERVICE_THREAD
|
|
|
|
|
|
|
|
void Service::svc_started()
|
|
|
|
{
|
|
|
|
if (!(svc_flags & SVC_evnt_fired)) {
|
|
|
|
svc_flags |= SVC_evnt_fired;
|
|
|
|
svcStart.release();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* SERVICE_THREAD */
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
/* This checks if the service has forked a process. If not,
|
|
|
|
it will post the isc_svcnoexe error. */
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
static inline void is_service_running(const Service* service)
|
2003-09-18 23:58:58 +02:00
|
|
|
{
|
|
|
|
if (!(service->svc_flags & SVC_forked)) {
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2003-09-18 23:58:58 +02:00
|
|
|
ERR_post (isc_svcnoexe, isc_arg_string,
|
2003-09-25 13:49:12 +02:00
|
|
|
service->svc_service->serv_name, 0);
|
2003-09-18 23:58:58 +02:00
|
|
|
}
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
static inline void need_admin_privs(ISC_STATUS** status, const char* message)
|
2003-09-18 23:58:58 +02:00
|
|
|
{
|
2003-09-25 13:49:12 +02:00
|
|
|
ISC_STATUS* stat = *status;
|
2003-09-19 05:37:24 +02:00
|
|
|
*stat++ = isc_insufficient_svc_privileges;
|
|
|
|
*stat++ = isc_arg_string;
|
2004-02-20 07:43:27 +01:00
|
|
|
*stat++ = (ISC_STATUS)(U_IPTR) ERR_string(message, strlen(message));
|
2003-09-19 05:37:24 +02:00
|
|
|
*stat++ = isc_arg_end;
|
|
|
|
*status = stat;
|
2003-09-18 23:58:58 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-10-29 11:53:47 +01:00
|
|
|
bool ck_space_for_numeric(char*& info, const char* const end)
|
|
|
|
{
|
|
|
|
if ((info + 1 + sizeof (ULONG)) > end)
|
|
|
|
{
|
|
|
|
if (info < end)
|
|
|
|
*info++ = isc_info_truncated;
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2003-10-29 11:53:47 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
/* Option block for service parameter block */
|
2004-02-20 07:43:27 +01:00
|
|
|
// What's the point of defining spb if a char* var will have the same name, Borland???
|
|
|
|
// It was easier to rename this struct.
|
|
|
|
|
|
|
|
struct Serv_param_block {
|
2005-11-27 21:53:09 +01:00
|
|
|
Firebird::string spb_sys_user_name;
|
|
|
|
Firebird::string spb_user_name;
|
|
|
|
Firebird::string spb_password;
|
|
|
|
Firebird::string spb_password_enc;
|
|
|
|
Firebird::string spb_command_line;
|
|
|
|
Firebird::string spb_network_protocol;
|
|
|
|
Firebird::string spb_remote_address;
|
2007-04-07 10:47:58 +02:00
|
|
|
#ifdef TRUSTED_SERVICES
|
2006-12-08 19:38:15 +01:00
|
|
|
Firebird::string spb_trusted_login;
|
|
|
|
#endif
|
2005-11-27 21:53:09 +01:00
|
|
|
USHORT spb_version;
|
|
|
|
|
|
|
|
Serv_param_block() : spb_version(0) { }
|
2004-02-20 07:43:27 +01:00
|
|
|
};
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-12-02 17:54:04 +01:00
|
|
|
|
2006-02-23 06:08:26 +01:00
|
|
|
static const TEXT* error_string(const TEXT* data, USHORT length);
|
|
|
|
static const TEXT* error_string(const Firebird::string& s);
|
2005-12-02 17:54:04 +01:00
|
|
|
static void conv_switches(Firebird::ClumpletReader&, Firebird::string&);
|
2003-12-31 06:36:12 +01:00
|
|
|
static const TEXT* find_switch(int, const in_sw_tab_t*);
|
2005-11-30 18:32:11 +01:00
|
|
|
static bool process_switches(Firebird::ClumpletReader&, Firebird::string&);
|
2005-11-27 21:53:09 +01:00
|
|
|
static void get_options(Firebird::ClumpletReader&, Serv_param_block*);
|
2005-11-30 18:32:11 +01:00
|
|
|
static bool get_action_svc_bitmask(const Firebird::ClumpletReader&,
|
|
|
|
const in_sw_tab_t*, Firebird::string&);
|
|
|
|
static void get_action_svc_string(const Firebird::ClumpletReader&,
|
|
|
|
Firebird::string&);
|
|
|
|
static void get_action_svc_data(const Firebird::ClumpletReader&,
|
|
|
|
Firebird::string&);
|
|
|
|
static bool get_action_svc_parameter(UCHAR tag, const in_sw_tab_t*,
|
|
|
|
Firebird::string&);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-08-10 16:47:42 +02:00
|
|
|
#ifdef SERVICE_THREAD
|
2004-03-18 06:56:06 +01:00
|
|
|
static UCHAR service_dequeue_byte(Service*);
|
|
|
|
static void service_enqueue_byte(UCHAR, Service*);
|
2001-05-23 15:26:42 +02:00
|
|
|
static USHORT service_add_one(USHORT i);
|
2004-03-18 06:56:06 +01:00
|
|
|
static USHORT service_empty(Service* service);
|
|
|
|
static USHORT service_full(Service* service);
|
2004-07-02 12:47:03 +02:00
|
|
|
static void service_fork(ThreadEntryPoint*, Service*);
|
2001-05-23 15:26:42 +02:00
|
|
|
#else
|
2005-10-22 14:35:04 +02:00
|
|
|
#ifndef WIN_NT
|
|
|
|
static void timeout_handler(void* service);
|
|
|
|
#endif
|
2006-02-23 06:08:26 +01:00
|
|
|
static void cleanup(Service* service);
|
2004-03-18 06:56:06 +01:00
|
|
|
static void service_fork(TEXT*, Service*);
|
2005-10-22 14:35:04 +02:00
|
|
|
static void io_error(const TEXT*, SLONG, const TEXT*, ISC_STATUS);
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
2004-03-18 06:56:06 +01:00
|
|
|
static void service_get(Service*, SCHAR *, USHORT, USHORT, USHORT, USHORT *);
|
|
|
|
static void service_put(Service*, const SCHAR*, USHORT);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
2004-06-08 15:41:08 +02:00
|
|
|
THREAD_ENTRY_DECLARE test_thread(THREAD_ENTRY_PARAM);
|
2001-05-23 15:26:42 +02:00
|
|
|
void test_cmd(USHORT, SCHAR *, TEXT **);
|
|
|
|
#define TEST_THREAD test_thread
|
|
|
|
#define TEST_CMD test_cmd
|
|
|
|
#else
|
|
|
|
#define TEST_THREAD NULL
|
|
|
|
#define TEST_CMD NULL
|
|
|
|
#endif
|
|
|
|
|
2003-01-20 14:51:35 +01:00
|
|
|
#ifdef SERVER_SHUTDOWN
|
2001-05-23 15:26:42 +02:00
|
|
|
static shutdown_fct_t shutdown_fct = 0;
|
|
|
|
static ULONG shutdown_param = 0L;
|
2003-01-20 14:51:35 +01:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
const char* const SPB_SEC_USERNAME = "isc_spb_sec_username";
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-06-06 14:37:24 +02:00
|
|
|
static Firebird::Mutex svc_mutex, thd_mutex;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Service Functions */
|
2005-08-18 14:33:48 +02:00
|
|
|
#if defined(SERVICE_THREAD) && !defined(BOOT_BUILD)
|
2003-09-15 15:13:45 +02:00
|
|
|
#include "../burp/burp_proto.h"
|
|
|
|
#include "../alice/alice_proto.h"
|
2003-10-03 03:53:34 +02:00
|
|
|
int main_lock_print();
|
2004-06-08 15:41:08 +02:00
|
|
|
THREAD_ENTRY_DECLARE main_gstat(THREAD_ENTRY_PARAM arg);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-15 15:13:45 +02:00
|
|
|
#define MAIN_GBAK BURP_main
|
|
|
|
#define MAIN_GFIX ALICE_main
|
2001-05-23 15:26:42 +02:00
|
|
|
#define MAIN_LOCK_PRINT main_lock_print
|
|
|
|
#define MAIN_GSTAT main_gstat
|
|
|
|
#else
|
|
|
|
#define MAIN_GBAK NULL
|
|
|
|
#define MAIN_GFIX NULL
|
|
|
|
#define MAIN_LOCK_PRINT NULL
|
|
|
|
#define MAIN_GSTAT NULL
|
|
|
|
#define MAIN_GSEC NULL
|
|
|
|
#endif
|
|
|
|
|
2005-08-18 14:33:48 +02:00
|
|
|
#if defined(SERVICE_THREAD) && !defined(EMBEDDED) && !defined(BOOT_BUILD)
|
2005-06-23 00:26:59 +02:00
|
|
|
#include "../utilities/gsec/gsec_proto.h"
|
|
|
|
#define MAIN_GSEC GSEC_main
|
|
|
|
#else
|
|
|
|
#define MAIN_GSEC NULL
|
|
|
|
#endif
|
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
|
2007-03-28 06:20:36 +02:00
|
|
|
void SVC_STATUS_ARG(ISC_STATUS*& status, const MsgFormat::safe_cell& value)
|
2003-02-16 01:20:30 +01:00
|
|
|
{
|
2007-03-28 06:20:36 +02:00
|
|
|
using MsgFormat::safe_cell;
|
|
|
|
|
|
|
|
switch (value.type)
|
2003-02-16 01:20:30 +01:00
|
|
|
{
|
2007-03-28 06:20:36 +02:00
|
|
|
case safe_cell::at_int64:
|
|
|
|
case safe_cell::at_uint64:
|
|
|
|
*status++ = isc_arg_number;
|
|
|
|
*status++ = static_cast<SLONG>(value.i_value); // May truncate number!
|
|
|
|
break;
|
|
|
|
case safe_cell::at_str:
|
2003-02-16 01:20:30 +01:00
|
|
|
{
|
2007-03-28 06:20:36 +02:00
|
|
|
*status++ = isc_arg_string;
|
|
|
|
const char* s = value.st_value.s_string;
|
|
|
|
*status++ = (ISC_STATUS) error_string(s, s ? strlen(s) : 0);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case safe_cell::at_counted_str:
|
|
|
|
{
|
|
|
|
*status++ = isc_arg_string;
|
|
|
|
const char* s = value.st_value.s_string;
|
|
|
|
*status++ = (ISC_STATUS) error_string(s, value.st_value.s_len);
|
2003-02-16 01:20:30 +01:00
|
|
|
}
|
2007-03-28 06:20:36 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
2003-02-16 01:20:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-28 06:20:36 +02:00
|
|
|
|
|
|
|
void SVC_STATUS_ARG(ISC_STATUS*& status, const char* value)
|
|
|
|
{
|
|
|
|
*status++ = isc_arg_string;
|
|
|
|
*status++ = (ISC_STATUS) error_string(value, value ? strlen(value) : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
/* Entries which have a NULL serv_executable field will not fork
|
|
|
|
a process on the server, but will establish a valid connection
|
|
|
|
which can be used for isc_info_svc calls.
|
|
|
|
|
|
|
|
The format of the structure is:
|
|
|
|
|
|
|
|
isc_action_svc call,
|
|
|
|
old service name (for compatibility),
|
|
|
|
old cmd-line switches (for compatibility),
|
|
|
|
executable to fork (for compatibility),
|
|
|
|
thread to execute,
|
|
|
|
in use flag (for compatibility)
|
|
|
|
*/
|
2004-02-20 07:43:27 +01:00
|
|
|
// And the code modifies this flag in this global array???
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
static serv_entry services[] =
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-04-13 21:52:38 +02:00
|
|
|
|
2002-10-29 14:46:48 +01:00
|
|
|
{ isc_action_max, "print_cache", "-svc", "bin/fb_cache_print", NULL, 0 },
|
|
|
|
{ isc_action_max, "print_locks", "-svc", "bin/fb_lock_print", NULL, 0 },
|
|
|
|
{ isc_action_max, "start_cache", "-svc", "bin/fb_cache_manager", NULL, 0 },
|
2001-12-24 03:51:06 +01:00
|
|
|
{ isc_action_max, "analyze_database", "-svc", "bin/gstat", NULL, 0 },
|
2003-09-15 15:13:45 +02:00
|
|
|
{ isc_action_max, "backup", "-svc -b", "bin/gbak", MAIN_GBAK, 0 },
|
|
|
|
{ isc_action_max, "create", "-svc -c", "bin/gbak", MAIN_GBAK, 0 },
|
|
|
|
{ isc_action_max, "restore", "-svc -r", "bin/gbak", MAIN_GBAK, 0 },
|
2001-12-24 03:51:06 +01:00
|
|
|
{ isc_action_max, "gdef", "-svc", "bin/gdef", NULL, 0 },
|
|
|
|
{ isc_action_max, "gsec", "-svc", "bin/gsec", NULL, 0 },
|
|
|
|
{ isc_action_max, "disable_journal", "-svc -disable", "bin/gjrn", NULL, 0 },
|
|
|
|
{ isc_action_max, "dump_journal", "-svc -online_dump", "bin/gjrn", NULL, 0 },
|
|
|
|
{ isc_action_max, "enable_journal", "-svc -enable", "bin/gjrn", NULL, 0 },
|
|
|
|
{ isc_action_max, "monitor_journal", "-svc -console", "bin/gjrn", NULL, 0 },
|
|
|
|
{ isc_action_max, "query_server", NULL, NULL, NULL, 0 },
|
|
|
|
{ isc_action_max, "start_journal", "-svc -server", "bin/gjrn", NULL, 0 },
|
|
|
|
{ isc_action_max, "stop_cache", "-svc -shut -cache", "bin/gfix", NULL, 0 },
|
|
|
|
{ isc_action_max, "stop_journal", "-svc -console", "bin/gjrn", NULL, 0 },
|
|
|
|
{ isc_action_max, "anonymous", NULL, NULL, NULL, 0 },
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* NEW VERSION 2 calls, the name field MUST be different from those names above
|
|
|
|
*/
|
2001-12-24 03:51:06 +01:00
|
|
|
{ isc_action_max, "service_mgr", NULL, NULL, NULL, 0 },
|
2003-09-15 15:13:45 +02:00
|
|
|
{ isc_action_svc_backup, "Backup Database", NULL, "bin/gbak", MAIN_GBAK, 0 },
|
|
|
|
{ isc_action_svc_restore, "Restore Database", NULL, "bin/gbak", MAIN_GBAK, 0 },
|
|
|
|
{ isc_action_svc_repair, "Repair Database", NULL, "bin/gfix", MAIN_GFIX, 0 },
|
|
|
|
{ isc_action_svc_add_user, "Add User", NULL, "bin/gsec", MAIN_GSEC, 0 },
|
|
|
|
{ isc_action_svc_delete_user, "Delete User", NULL, "bin/gsec", MAIN_GSEC, 0 },
|
|
|
|
{ isc_action_svc_modify_user, "Modify User", NULL, "bin/gsec", MAIN_GSEC, 0 },
|
|
|
|
{ isc_action_svc_display_user, "Display User", NULL, "bin/gsec", MAIN_GSEC, 0 },
|
|
|
|
{ isc_action_svc_properties, "Database Properties", NULL, "bin/gfix", MAIN_GFIX, 0 },
|
|
|
|
{ isc_action_svc_lock_stats, "Lock Stats", NULL, "bin/fb_lock_print", TEST_THREAD, 0 },
|
|
|
|
{ isc_action_svc_db_stats, "Database Stats", NULL, "bin/gstat", MAIN_GSTAT, 0 },
|
2006-02-23 06:08:26 +01:00
|
|
|
{ isc_action_svc_get_fb_log, "Get Log File", NULL, NULL, SVC_read_fb_log, 0 },
|
2001-05-23 15:26:42 +02:00
|
|
|
/* actions with no names are undocumented */
|
2003-09-15 15:13:45 +02:00
|
|
|
{ isc_action_svc_set_config, NULL, NULL, NULL, TEST_THREAD, 0 },
|
|
|
|
{ isc_action_svc_default_config, NULL, NULL, NULL, TEST_THREAD, 0 },
|
|
|
|
{ isc_action_svc_set_env, NULL, NULL, NULL, TEST_THREAD, 0 },
|
|
|
|
{ isc_action_svc_set_env_lock, NULL, NULL, NULL, TEST_THREAD, 0 },
|
|
|
|
{ isc_action_svc_set_env_msg, NULL, NULL, NULL, TEST_THREAD, 0 },
|
2001-12-24 03:51:06 +01:00
|
|
|
{ 0, NULL, NULL, NULL, NULL, 0 }
|
2001-05-23 15:26:42 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/* The SERVER_CAPABILITIES_FLAG is used to mark architectural
|
|
|
|
** differences across servers. This allows applications like server
|
2002-02-16 04:27:33 +01:00
|
|
|
** manager to disable features as necessary.
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef SUPERSERVER
|
2004-05-06 02:18:09 +02:00
|
|
|
const ULONG SERVER_CAPABILITIES = REMOTE_HOP_SUPPORT | MULTI_CLIENT_SUPPORT | SERVER_CONFIG_SUPPORT;
|
2001-05-23 15:26:42 +02:00
|
|
|
# ifdef WIN_NT
|
2004-05-06 02:18:09 +02:00
|
|
|
const ULONG SERVER_CAPABILITIES_FLAG = SERVER_CAPABILITIES | QUOTED_FILENAME_SUPPORT;
|
2001-05-23 15:26:42 +02:00
|
|
|
# else
|
2004-05-06 02:18:09 +02:00
|
|
|
const ULONG SERVER_CAPABILITIES_FLAG = SERVER_CAPABILITIES | NO_SERVER_SHUTDOWN_SUPPORT;
|
|
|
|
# endif // WIN_NT
|
|
|
|
#else // SUPERSERVER
|
|
|
|
const ULONG SERVER_CAPABILITIES_FLAG = REMOTE_HOP_SUPPORT | NO_SERVER_SHUTDOWN_SUPPORT;
|
|
|
|
#endif // SERVER_CAPABILITIES
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
Service* SVC_attach(USHORT service_length,
|
2003-12-03 09:19:24 +01:00
|
|
|
const TEXT* service_name,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT spb_length,
|
2005-11-27 21:53:09 +01:00
|
|
|
const SCHAR* spb_data)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* S V C _ a t t a c h
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2003-03-29 16:49:38 +01:00
|
|
|
* Connect to a Firebird service.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
/* If the service name begins with a slash, ignore it. */
|
2004-05-22 16:28:54 +02:00
|
|
|
thread_db* tdbb = JRD_get_thread_data();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (*service_name == '/' || *service_name == '\\') {
|
|
|
|
service_name++;
|
|
|
|
if (service_length)
|
|
|
|
service_length--;
|
|
|
|
}
|
2003-12-31 06:36:12 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Find the service by looking for an exact match. */
|
2007-08-26 11:53:08 +02:00
|
|
|
const Firebird::string misc_buf(service_name,
|
2005-11-27 21:53:09 +01:00
|
|
|
service_length ? service_length : strlen(service_name));
|
2004-02-20 07:43:27 +01:00
|
|
|
serv_entry* serv;
|
|
|
|
for (serv = services; serv->serv_name; serv++) {
|
2005-11-27 21:53:09 +01:00
|
|
|
if (misc_buf == serv->serv_name)
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
2003-12-03 09:19:24 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!serv->serv_name)
|
2003-03-09 22:08:33 +01:00
|
|
|
#ifdef NOT_USED_OR_REPLACED
|
2001-05-23 15:26:42 +02:00
|
|
|
ERR_post(isc_service_att_err, isc_arg_gds, isc_service_not_supported,
|
|
|
|
0);
|
|
|
|
#else
|
|
|
|
ERR_post(isc_service_att_err, isc_arg_gds, isc_svcnotdef,
|
2006-02-23 06:08:26 +01:00
|
|
|
isc_arg_string, error_string(misc_buf),
|
2001-05-23 15:26:42 +02:00
|
|
|
0);
|
|
|
|
#endif
|
|
|
|
|
2004-05-22 16:28:54 +02:00
|
|
|
JRD_get_thread_data();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* If anything goes wrong, we want to be able to free any memory
|
|
|
|
that may have been allocated. */
|
2004-03-18 06:56:06 +01:00
|
|
|
Service* service = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
try {
|
2005-11-27 21:53:09 +01:00
|
|
|
Firebird::ClumpletWriter spb(Firebird::ClumpletReader::SpbAttach, MAX_DPB_SIZE,
|
|
|
|
reinterpret_cast<const UCHAR*>(spb_data), spb_length, isc_spb_current_version);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-11-23 12:39:43 +01:00
|
|
|
/* Insert internal switch SERVICE_THD_PARAM in the service parameter block. */
|
|
|
|
/* dimitr: it looks that we shouldn't execute the below code
|
|
|
|
if the first switch of the command line is "-svc_re",
|
|
|
|
but I couldn't find where such a switch is specified
|
|
|
|
by any of the client tools, so it seems that in fact
|
|
|
|
it's not used at all. Hence I ignore this situation. */
|
2005-11-27 21:53:09 +01:00
|
|
|
if (spb.find(isc_spb_command_line)) {
|
|
|
|
Firebird::string cl;
|
|
|
|
spb.getString(cl);
|
|
|
|
if (cl.substr(0, 5) == "-svc ")
|
|
|
|
cl.erase(0, 5);
|
|
|
|
else if (cl.substr(0, 9) == "-svc_thd ")
|
|
|
|
cl.erase(0, 9);
|
|
|
|
cl.insert(0, ' ');
|
|
|
|
cl.insert(0, SERVICE_THD_PARAM);
|
|
|
|
spb.deleteClumplet();
|
|
|
|
spb.insertString(isc_spb_command_line, cl);
|
2002-11-23 12:39:43 +01:00
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
/* Process the service parameter block. */
|
2004-02-20 07:43:27 +01:00
|
|
|
Serv_param_block options;
|
2005-11-27 21:53:09 +01:00
|
|
|
get_options(spb, &options);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Perhaps checkout the user in the security database. */
|
2003-12-03 09:19:24 +01:00
|
|
|
USHORT user_flag;
|
2005-11-30 18:32:11 +01:00
|
|
|
if (!strcmp(serv->serv_name, "anonymous")) {
|
2001-05-23 15:26:42 +02:00
|
|
|
user_flag = SVC_user_none;
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
|
|
|
else {
|
2007-04-07 10:47:58 +02:00
|
|
|
#ifdef TRUSTED_SERVICES
|
2006-12-08 19:38:15 +01:00
|
|
|
if (options.spb_trusted_login.hasData())
|
|
|
|
{
|
|
|
|
options.spb_user_name = options.spb_trusted_login;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2006-12-10 14:43:31 +01:00
|
|
|
if (!options.spb_user_name.hasData())
|
|
|
|
{
|
|
|
|
// user name and password are required while
|
|
|
|
// attaching to the services manager
|
|
|
|
ERR_post(isc_service_att_err, isc_arg_gds, isc_svcnouser, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TEXT name[129]; // unused after retrieved
|
|
|
|
int id, group, node_id;
|
|
|
|
|
2007-08-26 11:53:08 +02:00
|
|
|
const Firebird::string remote = options.spb_network_protocol +
|
2006-12-10 14:43:31 +01:00
|
|
|
(options.spb_network_protocol.isEmpty() ||
|
|
|
|
options.spb_remote_address.isEmpty() ? "" : "/") +
|
|
|
|
options.spb_remote_address;
|
2005-11-27 21:53:09 +01:00
|
|
|
|
2006-12-10 14:43:31 +01:00
|
|
|
SecurityDatabase::verifyUser(name, options.spb_user_name.nullStr(),
|
|
|
|
options.spb_password.nullStr(),
|
|
|
|
options.spb_password_enc.nullStr(),
|
|
|
|
&id, &group, &node_id, remote);
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Check that the validated user has the authority to access this service */
|
2006-03-25 08:08:00 +01:00
|
|
|
if (fb_utils::stricmp(options.spb_user_name.c_str(), SYSDBA_USER_NAME))
|
2002-08-28 08:50:33 +02:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
user_flag = SVC_user_any;
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
|
|
|
else {
|
2001-05-23 15:26:42 +02:00
|
|
|
user_flag = SVC_user_dba | SVC_user_any;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
/* move service switches in */
|
|
|
|
Firebird::string switches;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (serv->serv_std_switches)
|
2005-11-27 21:53:09 +01:00
|
|
|
switches = serv->serv_std_switches;
|
|
|
|
if (options.spb_command_line.hasData() && serv->serv_std_switches)
|
|
|
|
switches += " ";
|
|
|
|
switches += options.spb_command_line;
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
/* Services operate outside of the context of databases. Therefore
|
|
|
|
we cannot use the JRD allocator. */
|
2005-12-02 23:19:57 +01:00
|
|
|
service = FB_NEW(*getDefaultMemoryPool()) Service(serv, *getDefaultMemoryPool());
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-03-01 18:53:56 +01:00
|
|
|
service->svc_flags =
|
2005-11-27 21:53:09 +01:00
|
|
|
(serv->serv_executable ? SVC_forked : 0) | (switches.hasData() ? SVC_cmd_line : 0);
|
2005-12-02 17:54:04 +01:00
|
|
|
service->svc_perm_sw = switches;
|
2001-05-23 15:26:42 +02:00
|
|
|
service->svc_user_flag = user_flag;
|
2005-12-02 17:54:04 +01:00
|
|
|
|
2005-08-10 16:47:42 +02:00
|
|
|
#ifdef SERVICE_THREAD
|
2001-05-23 15:26:42 +02:00
|
|
|
service->svc_stdout_head = 1;
|
|
|
|
service->svc_stdout_tail = SVC_STDOUT_BUFFER_SIZE;
|
|
|
|
service->svc_stdout = NULL;
|
|
|
|
#endif
|
|
|
|
service->svc_spb_version = options.spb_version;
|
2005-12-02 17:54:04 +01:00
|
|
|
service->svc_username = options.spb_user_name;
|
2007-04-07 10:47:58 +02:00
|
|
|
#ifdef TRUSTED_SERVICES
|
2006-12-08 19:38:15 +01:00
|
|
|
service->svc_trusted_login = options.spb_trusted_login;
|
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-02-16 04:27:33 +01:00
|
|
|
/* The password will be issued to the service threads on NT since
|
|
|
|
* there is no OS authentication. If the password is not yet
|
2001-05-23 15:26:42 +02:00
|
|
|
* encrypted, then encrypt it before saving it (since there is no
|
|
|
|
* decrypt function).
|
|
|
|
*/
|
2005-12-02 17:54:04 +01:00
|
|
|
if (options.spb_password_enc.hasData())
|
2005-11-27 21:53:09 +01:00
|
|
|
{
|
2005-12-02 17:54:04 +01:00
|
|
|
service->svc_enc_password = options.spb_password_enc;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2005-12-02 17:54:04 +01:00
|
|
|
else if (options.spb_password.hasData())
|
2005-11-27 21:53:09 +01:00
|
|
|
{
|
2005-12-02 17:54:04 +01:00
|
|
|
service->svc_enc_password.resize(MAX_PASSWORD_LENGTH + 2);
|
|
|
|
ENC_crypt(service->svc_enc_password.begin(), service->svc_enc_password.length(),
|
|
|
|
options.spb_password.c_str(), PASSWORD_SALT);
|
2005-12-09 06:00:32 +01:00
|
|
|
service->svc_enc_password.recalculate_length();
|
2005-12-02 17:54:04 +01:00
|
|
|
service->svc_enc_password.erase(0, 2);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-02-16 04:27:33 +01:00
|
|
|
/* If an executable is defined for the service, try to fork a new process.
|
2001-05-23 15:26:42 +02:00
|
|
|
* Only do this if we are working with a version 1 service */
|
|
|
|
|
2005-08-10 16:47:42 +02:00
|
|
|
#ifndef SERVICE_THREAD
|
2001-05-23 15:26:42 +02:00
|
|
|
if (serv->serv_executable && options.spb_version == isc_spb_version1)
|
|
|
|
#else
|
|
|
|
if (serv->serv_thd && options.spb_version == isc_spb_version1)
|
|
|
|
#endif
|
|
|
|
{
|
2005-08-10 16:47:42 +02:00
|
|
|
#ifndef SERVICE_THREAD
|
2003-12-31 06:36:12 +01:00
|
|
|
TEXT service_path[MAXPATHLEN];
|
2003-04-06 13:40:29 +02:00
|
|
|
gds__prefix(service_path, serv->serv_executable);
|
2001-05-23 15:26:42 +02:00
|
|
|
service_fork(service_path, service);
|
|
|
|
#else
|
|
|
|
/* if service is single threaded, only call if not currently running */
|
2004-02-20 07:43:27 +01:00
|
|
|
if (serv->serv_in_use == NULL) { /* No worry for multi-threading */
|
|
|
|
service_fork(serv->serv_thd, service);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2004-02-20 07:43:27 +01:00
|
|
|
else if (!*(serv->serv_in_use)) {
|
|
|
|
*(serv->serv_in_use) = true;
|
|
|
|
service_fork(serv->serv_thd, service);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
ERR_post(isc_service_att_err, isc_arg_gds,
|
|
|
|
isc_svc_in_use, isc_arg_string, serv->serv_name, 0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
} // try
|
2006-05-19 17:17:02 +02:00
|
|
|
catch (const Firebird::Exception&) {
|
2005-12-02 17:54:04 +01:00
|
|
|
delete service;
|
2004-03-01 04:35:23 +01:00
|
|
|
throw;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return service;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
void SVC_detach(Service* service)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* S V C _ d e t a c h
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Close down a service.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
#ifdef SERVER_SHUTDOWN
|
|
|
|
if (service->svc_do_shutdown) {
|
2005-06-24 13:14:51 +02:00
|
|
|
THREAD_EXIT();
|
|
|
|
JRD_shutdown_all(true);
|
|
|
|
if (shutdown_fct) {
|
|
|
|
(shutdown_fct) (shutdown_param);
|
|
|
|
}
|
|
|
|
else {
|
2001-05-23 15:26:42 +02:00
|
|
|
exit(0);
|
2005-06-24 13:14:51 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* The shutdown operation is complete, just wait to die */
|
2005-06-24 13:14:51 +02:00
|
|
|
while (true) {
|
|
|
|
THREAD_YIELD();
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
#endif /* SERVER_SHUTDOWN */
|
|
|
|
|
2005-08-10 16:47:42 +02:00
|
|
|
#ifdef SERVICE_THREAD
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Mark service as detached. */
|
|
|
|
/* If service thread is finished, cleanup memory being used by service. */
|
|
|
|
|
|
|
|
SVC_finish(service, SVC_detached);
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
/* Go ahead and cleanup memory being used by service */
|
2006-02-23 06:08:26 +01:00
|
|
|
cleanup(service);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-01-20 14:51:35 +01:00
|
|
|
#ifdef SERVER_SHUTDOWN
|
|
|
|
void SVC_shutdown_init(shutdown_fct_t fptr,
|
|
|
|
ULONG param)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* S V C _ s h u t d o w n _ i n i t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Set the global function pointer to the shutdown function.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2003-01-20 14:51:35 +01:00
|
|
|
shutdown_fct = fptr;
|
2001-05-23 15:26:42 +02:00
|
|
|
shutdown_param = param;
|
|
|
|
}
|
2003-01-20 14:51:35 +01:00
|
|
|
#endif // SERVER_SHUTDOWN
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
2005-08-10 16:47:42 +02:00
|
|
|
#ifdef SERVICE_THREAD
|
2004-03-18 06:56:06 +01:00
|
|
|
void SVC_fprintf(Service* service, const SCHAR* format, ...)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* S V C _ f p r i n t f
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
/* Ensure that service is not detached. */
|
|
|
|
if (!(service->svc_flags & SVC_detached)) {
|
|
|
|
va_list arglist;
|
|
|
|
char buf[1000];
|
|
|
|
ULONG i = 0;
|
|
|
|
|
|
|
|
va_start(arglist, format);
|
2003-10-29 11:53:47 +01:00
|
|
|
// CVC: No bounds checking on "buf"; we assume everything fits in it.
|
|
|
|
// Where is that limit documented??? I changed to vsnprintf
|
|
|
|
//n = vsprintf(buf, format, arglist);
|
|
|
|
int n = VSNPRINTF(buf, sizeof(buf), format, arglist);
|
2001-05-23 15:26:42 +02:00
|
|
|
va_end(arglist);
|
2003-10-29 11:53:47 +01:00
|
|
|
// Nothing is said if this answer generated by service_enqueue_bytes
|
|
|
|
// should be null terminated always. Given the old code that called
|
|
|
|
// vsprintf, it's clear that '\0' was't sent, so in the new code,
|
|
|
|
// n is adjusted in case of insufficient buffer to behave the same.
|
|
|
|
// Changed ULONG to int, since this is the official type of the
|
|
|
|
// printf family and makes negative test natural.
|
|
|
|
// We could send a truncated answer in this case, since vsnprintf
|
|
|
|
// returns negative when buffer is not enough. Since the old code
|
|
|
|
// didn't send anything after an error, enable this to test if sending
|
|
|
|
// a partial result would crash the receiver. Failure may happen before
|
|
|
|
// reaching end of buffer for other reasons, so we might transfer trash.
|
|
|
|
//if (n < 0)
|
|
|
|
//{
|
|
|
|
// n = sizeof(buf) - 1;
|
|
|
|
// buf[n] = 0;
|
|
|
|
//}
|
2001-05-23 15:26:42 +02:00
|
|
|
while (n > 0 && !(service->svc_flags & SVC_detached)) {
|
|
|
|
service_enqueue_byte(buf[i], service);
|
|
|
|
n--;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
void SVC_putc(Service* service, const UCHAR ch)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* S V C _ p u t c
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
/* Ensure that service is not detached. */
|
|
|
|
if (!(service->svc_flags & SVC_detached))
|
|
|
|
service_enqueue_byte(ch, service);
|
|
|
|
}
|
2003-09-15 15:13:45 +02:00
|
|
|
|
|
|
|
//____________________________________________________________
|
|
|
|
//
|
|
|
|
// Routine which is used by the service for calling back when there is output.
|
|
|
|
//
|
2003-10-29 11:53:47 +01:00
|
|
|
// CVC: Now we are using a SLONG to hold a pointer to the Service!
|
2003-09-15 15:13:45 +02:00
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
int SVC_output(Service* output_data, const UCHAR* output_buf)
|
2003-09-15 15:13:45 +02:00
|
|
|
{
|
2003-11-01 11:26:43 +01:00
|
|
|
SVC_fprintf(output_data, "%s", output_buf);
|
2003-09-15 15:13:45 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2005-08-10 16:47:42 +02:00
|
|
|
#endif /*SERVICE_THREAD*/
|
2004-11-17 09:57:59 +01:00
|
|
|
|
2006-02-23 06:08:26 +01:00
|
|
|
|
2004-03-24 20:48:57 +01:00
|
|
|
ISC_STATUS SVC_query2(Service* service,
|
2004-03-11 06:04:26 +01:00
|
|
|
thread_db* tdbb,
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT send_item_length,
|
2003-10-29 11:53:47 +01:00
|
|
|
const SCHAR* send_items,
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT recv_item_length,
|
2003-10-29 11:53:47 +01:00
|
|
|
const SCHAR* recv_items,
|
|
|
|
USHORT buffer_length,
|
|
|
|
SCHAR* info)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* S V C _ q u e r y 2
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Provide information on service object
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-10-29 11:53:47 +01:00
|
|
|
SCHAR item;
|
2002-11-04 12:19:21 +01:00
|
|
|
char buffer[MAXPATHLEN];
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT l, length, version, get_flags;
|
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Setup the status vector */
|
2004-11-16 09:52:29 +01:00
|
|
|
ISC_STATUS* status = tdbb->tdbb_status_vector;
|
2001-05-23 15:26:42 +02:00
|
|
|
*status++ = isc_arg_gds;
|
|
|
|
|
|
|
|
/* Process the send portion of the query first. */
|
|
|
|
|
2004-11-16 09:52:29 +01:00
|
|
|
USHORT timeout = 0;
|
2003-10-29 11:53:47 +01:00
|
|
|
const SCHAR* items = send_items;
|
|
|
|
const SCHAR* const end_items = items + send_item_length;
|
2001-05-23 15:26:42 +02:00
|
|
|
while (items < end_items && *items != isc_info_end)
|
|
|
|
{
|
|
|
|
switch ((item = *items++))
|
|
|
|
{
|
|
|
|
case isc_info_end:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if (items + 2 <= end_items) {
|
|
|
|
l =
|
2003-11-16 02:44:51 +01:00
|
|
|
(USHORT) gds__vax_integer(reinterpret_cast<
|
|
|
|
const UCHAR*>(items), 2);
|
2001-05-23 15:26:42 +02:00
|
|
|
items += 2;
|
|
|
|
if (items + l <= end_items) {
|
|
|
|
switch (item) {
|
|
|
|
case isc_info_svc_line:
|
|
|
|
service_put(service, items, l);
|
|
|
|
break;
|
|
|
|
case isc_info_svc_message:
|
|
|
|
service_put(service, items - 3, l + 3);
|
|
|
|
break;
|
|
|
|
case isc_info_svc_timeout:
|
|
|
|
timeout =
|
2003-11-16 02:44:51 +01:00
|
|
|
(USHORT) gds__vax_integer(reinterpret_cast<
|
|
|
|
const UCHAR*>(items), l);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case isc_info_svc_version:
|
|
|
|
version =
|
2003-11-16 02:44:51 +01:00
|
|
|
(USHORT) gds__vax_integer(reinterpret_cast<
|
|
|
|
const UCHAR*>(items), l);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
items += l;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
items += 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Process the receive portion of the query now. */
|
|
|
|
|
2003-10-29 11:53:47 +01:00
|
|
|
const SCHAR* const end = info + buffer_length;
|
2001-05-23 15:26:42 +02:00
|
|
|
items = recv_items;
|
2003-10-29 11:53:47 +01:00
|
|
|
const SCHAR* const end_items2 = items + recv_item_length;
|
2006-05-02 00:23:31 +02:00
|
|
|
|
|
|
|
SCHAR* start_info;
|
|
|
|
|
|
|
|
if (*items == isc_info_length) {
|
|
|
|
start_info = info;
|
|
|
|
items++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
start_info = 0;
|
|
|
|
}
|
|
|
|
|
2003-10-29 11:53:47 +01:00
|
|
|
while (items < end_items2 && *items != isc_info_end)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
if we attached to the "anonymous" service we allow only following queries:
|
|
|
|
|
2003-10-29 11:53:47 +01:00
|
|
|
isc_info_svc_get_config - called from within remote/ibconfig.cpp
|
|
|
|
isc_info_svc_dump_pool_info - called from within utilities/print_pool.cpp
|
2004-11-07 15:50:53 +01:00
|
|
|
// isc_info_svc_user_dbpath - called from within utilities/security.cpp
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
if (service->svc_user_flag == SVC_user_none)
|
|
|
|
{
|
|
|
|
switch (*items)
|
|
|
|
{
|
|
|
|
case isc_info_svc_get_config:
|
|
|
|
case isc_info_svc_dump_pool_info:
|
2004-11-07 15:50:53 +01:00
|
|
|
// case isc_info_svc_user_dbpath:
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ERR_post(isc_bad_spb_form, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch ((item = *items++))
|
|
|
|
{
|
|
|
|
case isc_info_end:
|
|
|
|
break;
|
|
|
|
|
|
|
|
#ifdef SERVER_SHUTDOWN
|
|
|
|
case isc_info_svc_svr_db_info:
|
2007-04-19 09:30:00 +02:00
|
|
|
if (service->svc_user_flag & SVC_user_dba)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
UCHAR dbbuf[1024];
|
2006-10-30 13:39:08 +01:00
|
|
|
ULONG num_dbs = 0;
|
|
|
|
ULONG num_att = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
*info++ = item;
|
2004-11-16 09:52:29 +01:00
|
|
|
TEXT* const ptr =
|
2001-12-24 03:51:06 +01:00
|
|
|
JRD_num_attachments(reinterpret_cast<char*>(dbbuf),
|
2001-05-23 15:26:42 +02:00
|
|
|
sizeof(dbbuf), JRD_info_dbnames,
|
|
|
|
&num_att, &num_dbs);
|
|
|
|
/* Move the number of attachments into the info buffer */
|
2003-10-29 11:53:47 +01:00
|
|
|
if (!ck_space_for_numeric(info, end))
|
|
|
|
return 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
*info++ = isc_spb_num_att;
|
|
|
|
ADD_SPB_NUMERIC(info, num_att);
|
|
|
|
|
|
|
|
/* Move the number of databases in use into the info buffer */
|
2003-10-29 11:53:47 +01:00
|
|
|
if (!ck_space_for_numeric(info, end))
|
|
|
|
return 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
*info++ = isc_spb_num_db;
|
|
|
|
ADD_SPB_NUMERIC(info, num_dbs);
|
|
|
|
|
|
|
|
/* Move db names into the info buffer */
|
2004-11-16 09:52:29 +01:00
|
|
|
TEXT* ptr2 = ptr;
|
|
|
|
if (ptr2) {
|
|
|
|
USHORT num = (USHORT) isc_vax_integer(ptr2, sizeof(USHORT));
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(num == num_dbs);
|
2001-05-23 15:26:42 +02:00
|
|
|
ptr2 += sizeof(USHORT);
|
|
|
|
for (; num; num--) {
|
|
|
|
length =
|
|
|
|
(USHORT) isc_vax_integer(ptr2, sizeof(USHORT));
|
|
|
|
ptr2 += sizeof(USHORT);
|
|
|
|
if (!
|
|
|
|
(info =
|
|
|
|
INF_put_item(isc_spb_dbname, length, ptr2, info,
|
2004-11-16 09:52:29 +01:00
|
|
|
end)))
|
|
|
|
{
|
|
|
|
// CVC: Shouldn't this place try to free ptr
|
|
|
|
// if it's different than dbbuf, too?
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ptr2 += length;
|
|
|
|
}
|
|
|
|
|
2004-11-16 09:52:29 +01:00
|
|
|
if (ptr != reinterpret_cast<TEXT*>(dbbuf))
|
2001-05-23 15:26:42 +02:00
|
|
|
gds__free(ptr); /* memory has been allocated by
|
|
|
|
JRD_num_attachments() */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info < end)
|
|
|
|
*info++ = isc_info_flag_end;
|
|
|
|
}
|
2007-04-19 09:30:00 +02:00
|
|
|
else
|
|
|
|
need_admin_privs(&status, "isc_info_svc_svr_db_info");
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_svr_online:
|
|
|
|
*info++ = item;
|
|
|
|
if (service->svc_user_flag & SVC_user_dba) {
|
2004-03-18 06:56:06 +01:00
|
|
|
service->svc_do_shutdown = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
WHY_set_shutdown(FALSE);
|
|
|
|
}
|
|
|
|
else
|
2003-09-19 05:37:24 +02:00
|
|
|
need_admin_privs(&status, "isc_info_svc_svr_online");
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_svr_offline:
|
|
|
|
*info++ = item;
|
|
|
|
if (service->svc_user_flag & SVC_user_dba) {
|
2004-03-18 06:56:06 +01:00
|
|
|
service->svc_do_shutdown = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
WHY_set_shutdown(TRUE);
|
|
|
|
}
|
|
|
|
else
|
2003-09-19 05:37:24 +02:00
|
|
|
need_admin_privs(&status, "isc_info_svc_svr_offline");
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
#endif /* SERVER_SHUTDOWN */
|
|
|
|
|
|
|
|
/* The following 3 service commands (or items) stuff the response
|
2007-02-11 10:04:54 +01:00
|
|
|
buffer 'info' with values of environment variable FIREBIRD,
|
|
|
|
FIREBIRD_LOCK or FIREBIRD_MSG. If the environment variable
|
2001-05-23 15:26:42 +02:00
|
|
|
is not set then default value is returned.
|
|
|
|
*/
|
|
|
|
case isc_info_svc_get_env:
|
|
|
|
case isc_info_svc_get_env_lock:
|
|
|
|
case isc_info_svc_get_env_msg:
|
|
|
|
switch (item) {
|
|
|
|
case isc_info_svc_get_env:
|
|
|
|
gds__prefix(buffer, "");
|
|
|
|
break;
|
|
|
|
case isc_info_svc_get_env_lock:
|
|
|
|
gds__prefix_lock(buffer, "");
|
|
|
|
break;
|
|
|
|
case isc_info_svc_get_env_msg:
|
|
|
|
gds__prefix_msg(buffer, "");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Note: it is safe to use strlen to get a length of "buffer"
|
|
|
|
because gds_prefix[_lock|_msg] return a zero-terminated
|
|
|
|
string
|
|
|
|
*/
|
|
|
|
info = INF_put_item(item, strlen(buffer), buffer, info, end);
|
|
|
|
if (!info) {
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
case isc_info_svc_dump_pool_info:
|
|
|
|
{
|
|
|
|
char fname[MAXPATHLEN];
|
2004-05-12 21:39:17 +02:00
|
|
|
size_t length2 = isc_vax_integer(items, sizeof(USHORT));
|
|
|
|
if (length2 >= sizeof(fname))
|
|
|
|
length2 = sizeof(fname) - 1; // truncation
|
2001-05-23 15:26:42 +02:00
|
|
|
items += sizeof(USHORT);
|
2004-05-12 21:39:17 +02:00
|
|
|
strncpy(fname, items, length2);
|
|
|
|
fname[length2] = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
JRD_print_all_counters(fname);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
2005-12-19 17:24:55 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
case isc_info_svc_get_config:
|
2003-07-04 14:12:54 +02:00
|
|
|
// TODO: iterate through all integer-based config values
|
|
|
|
// and return them to the client
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
2005-12-19 17:24:55 +01:00
|
|
|
/*
|
2001-05-23 15:26:42 +02:00
|
|
|
case isc_info_svc_default_config:
|
|
|
|
*info++ = item;
|
|
|
|
if (service->svc_user_flag & SVC_user_dba) {
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2003-07-04 14:12:54 +02:00
|
|
|
// TODO: reset the config values to defaults
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else
|
2003-09-19 05:37:24 +02:00
|
|
|
need_admin_privs(&status, "isc_info_svc_default_config");
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_set_config:
|
|
|
|
*info++ = item;
|
|
|
|
if (service->svc_user_flag & SVC_user_dba) {
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2003-07-04 14:12:54 +02:00
|
|
|
// TODO: set the config values
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else {
|
2003-09-19 05:37:24 +02:00
|
|
|
need_admin_privs(&status, "isc_info_svc_set_config");
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
break;
|
2003-07-04 14:12:54 +02:00
|
|
|
*/
|
2001-05-23 15:26:42 +02:00
|
|
|
case isc_info_svc_version:
|
|
|
|
/* The version of the service manager */
|
2003-10-29 11:53:47 +01:00
|
|
|
if (!ck_space_for_numeric(info, end))
|
|
|
|
return 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
*info++ = item;
|
|
|
|
ADD_SPB_NUMERIC(info, SERVICE_VERSION);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_capabilities:
|
|
|
|
/* bitmask defining any specific architectural differences */
|
2003-10-29 11:53:47 +01:00
|
|
|
if (!ck_space_for_numeric(info, end))
|
|
|
|
return 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
*info++ = item;
|
|
|
|
ADD_SPB_NUMERIC(info, SERVER_CAPABILITIES_FLAG);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_running:
|
|
|
|
/* Returns the status of the flag SVC_thd_running */
|
2003-10-29 11:53:47 +01:00
|
|
|
if (!ck_space_for_numeric(info, end))
|
|
|
|
return 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
*info++ = item;
|
|
|
|
if (service->svc_flags & SVC_thd_running)
|
|
|
|
ADD_SPB_NUMERIC(info, TRUE)
|
|
|
|
else
|
|
|
|
ADD_SPB_NUMERIC(info, FALSE)
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_server_version:
|
|
|
|
/* The version of the server engine */
|
|
|
|
info = INF_put_item(item, strlen(GDS_VERSION), GDS_VERSION, info, end);
|
|
|
|
if (!info) {
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_implementation:
|
2007-02-11 10:04:54 +01:00
|
|
|
/* The server implementation - e.g. Firebird/sun4 */
|
2001-05-23 15:26:42 +02:00
|
|
|
isc_format_implementation(IMPLEMENTATION, sizeof(buffer), buffer,
|
|
|
|
0, 0, NULL);
|
|
|
|
info = INF_put_item(item, strlen(buffer), buffer, info, end);
|
|
|
|
if (!info) {
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case isc_info_svc_user_dbpath:
|
2007-04-19 09:30:00 +02:00
|
|
|
if (service->svc_user_flag & SVC_user_dba)
|
2004-11-16 09:52:29 +01:00
|
|
|
{
|
2007-04-19 09:30:00 +02:00
|
|
|
/* The path to the user security database (security2.fdb) */
|
|
|
|
SecurityDatabase::getPath(buffer);
|
|
|
|
|
|
|
|
if (!(info = INF_put_item(item, strlen(buffer), buffer,
|
|
|
|
info, end)))
|
|
|
|
{
|
|
|
|
THREAD_ENTER();
|
|
|
|
return 0;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2007-04-19 09:30:00 +02:00
|
|
|
else
|
|
|
|
need_admin_privs(&status, "isc_info_svc_user_dbpath");
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_response:
|
|
|
|
service->svc_resp_len = 0;
|
2003-03-30 18:55:59 +02:00
|
|
|
if (info + 4 >= end) {
|
2001-05-23 15:26:42 +02:00
|
|
|
*info++ = isc_info_truncated;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
service_put(service, &item, 1);
|
|
|
|
service_get(service, &item, 1, GET_BINARY, 0, &length);
|
|
|
|
service_get(service, buffer, 2, GET_BINARY, 0, &length);
|
|
|
|
l =
|
2003-11-16 02:44:51 +01:00
|
|
|
(USHORT) gds__vax_integer(reinterpret_cast<
|
|
|
|
UCHAR*>(buffer), 2);
|
2003-03-30 18:55:59 +02:00
|
|
|
length = MIN(end - (info + 5), l);
|
2001-05-23 15:26:42 +02:00
|
|
|
service_get(service, info + 3, length, GET_BINARY, 0, &length);
|
|
|
|
info = INF_put_item(item, length, info + 3, info, end);
|
|
|
|
if (length != l) {
|
|
|
|
*info++ = isc_info_truncated;
|
|
|
|
l -= length;
|
|
|
|
if (l > service->svc_resp_buf_len) {
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
if (service->svc_resp_buf)
|
2004-09-26 13:23:32 +02:00
|
|
|
gds__free(service->svc_resp_buf);
|
2001-05-23 15:26:42 +02:00
|
|
|
service->svc_resp_buf = (UCHAR *) gds__alloc((SLONG) l);
|
|
|
|
/* FREE: in SVC_detach() */
|
|
|
|
if (!service->svc_resp_buf) { /* NOMEM: */
|
|
|
|
DEV_REPORT("SVC_query: out of memory");
|
|
|
|
/* NOMEM: not really handled well */
|
|
|
|
l = 0; /* set the length to zero */
|
|
|
|
}
|
|
|
|
service->svc_resp_buf_len = l;
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
service_get(service,
|
2004-11-16 09:52:29 +01:00
|
|
|
reinterpret_cast<char*>(service->svc_resp_buf),
|
2001-05-23 15:26:42 +02:00
|
|
|
l, GET_BINARY, 0, &length);
|
|
|
|
service->svc_resp_ptr = service->svc_resp_buf;
|
|
|
|
service->svc_resp_len = l;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_response_more:
|
2001-12-24 03:51:06 +01:00
|
|
|
if ( (l = length = service->svc_resp_len) )
|
2003-03-30 18:55:59 +02:00
|
|
|
length = MIN(end - (info + 5), l);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!
|
|
|
|
(info =
|
|
|
|
INF_put_item(item, length,
|
2004-03-18 06:56:06 +01:00
|
|
|
reinterpret_cast<const char*>
|
|
|
|
(service->svc_resp_ptr),
|
|
|
|
info, end)))
|
|
|
|
{
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
service->svc_resp_ptr += length;
|
|
|
|
service->svc_resp_len -= length;
|
|
|
|
if (length != l)
|
|
|
|
*info++ = isc_info_truncated;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_total_length:
|
|
|
|
service_put(service, &item, 1);
|
|
|
|
service_get(service, &item, 1, GET_BINARY, 0, &length);
|
|
|
|
service_get(service, buffer, 2, GET_BINARY, 0, &length);
|
2004-11-16 09:52:29 +01:00
|
|
|
l = (USHORT) gds__vax_integer(reinterpret_cast<
|
2003-11-18 08:58:35 +01:00
|
|
|
UCHAR*>(buffer), 2);
|
2001-05-23 15:26:42 +02:00
|
|
|
service_get(service, buffer, l, GET_BINARY, 0, &length);
|
|
|
|
if (!(info = INF_put_item(item, length, buffer, info, end))) {
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_line:
|
|
|
|
case isc_info_svc_to_eof:
|
|
|
|
case isc_info_svc_limbo_trans:
|
|
|
|
case isc_info_svc_get_users:
|
2003-03-30 18:55:59 +02:00
|
|
|
if (info + 4 >= end) {
|
2001-05-23 15:26:42 +02:00
|
|
|
*info++ = isc_info_truncated;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (item == isc_info_svc_line)
|
|
|
|
get_flags = GET_LINE;
|
2003-03-29 16:49:38 +01:00
|
|
|
else if (item == isc_info_svc_to_eof)
|
|
|
|
get_flags = GET_EOF;
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
2003-03-29 16:49:38 +01:00
|
|
|
get_flags = GET_BINARY;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-03-30 18:55:59 +02:00
|
|
|
service_get(service, info + 3, end - (info + 5), get_flags,
|
2001-05-23 15:26:42 +02:00
|
|
|
timeout, &length);
|
|
|
|
|
2002-02-16 04:27:33 +01:00
|
|
|
/* If the read timed out, return the data, if any, & a timeout
|
2001-05-23 15:26:42 +02:00
|
|
|
item. If the input buffer was not large enough
|
|
|
|
to store a read to eof, return the data that was read along
|
|
|
|
with an indication that more is available. */
|
|
|
|
|
2003-03-20 23:43:40 +01:00
|
|
|
if (!(info = INF_put_item(item, length, info + 3, info, end))) {
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2003-03-20 23:43:40 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (service->svc_flags & SVC_timeout)
|
|
|
|
{
|
|
|
|
*info++ = isc_info_svc_timeout;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!length && !(service->svc_flags & SVC_finished))
|
|
|
|
{
|
|
|
|
*info++ = isc_info_data_not_ready;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (item == isc_info_svc_to_eof &&
|
|
|
|
!(service->svc_flags & SVC_finished))
|
|
|
|
{
|
|
|
|
*info++ = isc_info_truncated;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2005-12-11 14:42:50 +01:00
|
|
|
|
|
|
|
default:
|
|
|
|
*status++ = isc_wish_list;
|
|
|
|
*status++ = isc_arg_end;
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (service->svc_user_flag == SVC_user_none)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info < end)
|
|
|
|
*info = isc_info_end;
|
|
|
|
|
2006-05-02 00:23:31 +02:00
|
|
|
if (start_info && (end - info >= 7))
|
|
|
|
{
|
|
|
|
SLONG number = 1 + (info - start_info);
|
|
|
|
memmove(start_info + 7, start_info, number);
|
2006-09-01 12:51:57 +02:00
|
|
|
USHORT length2 = INF_convert(number, buffer);
|
|
|
|
INF_put_item(isc_info_length, length2, buffer, start_info, end);
|
2006-05-02 00:23:31 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-03-24 20:48:57 +01:00
|
|
|
if (!(service->svc_flags & SVC_thd_running))
|
|
|
|
{
|
|
|
|
SVC_finish(service, SVC_finished);
|
|
|
|
}
|
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
return tdbb->tdbb_status_vector[1];
|
|
|
|
}
|
|
|
|
|
2006-02-23 06:08:26 +01:00
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
void SVC_query(Service* service,
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT send_item_length,
|
2003-10-29 11:53:47 +01:00
|
|
|
const SCHAR* send_items,
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT recv_item_length,
|
2003-10-29 11:53:47 +01:00
|
|
|
const SCHAR* recv_items,
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT buffer_length,
|
|
|
|
SCHAR* info)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* S V C _ q u e r y
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Provide information on service object.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-10-29 11:53:47 +01:00
|
|
|
SCHAR item, *p;
|
2003-11-01 11:26:43 +01:00
|
|
|
char buffer[256];
|
2003-04-06 13:40:29 +02:00
|
|
|
TEXT PathBuffer[MAXPATHLEN];
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT l, length, version, get_flags;
|
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Process the send portion of the query first. */
|
|
|
|
|
2004-11-16 09:52:29 +01:00
|
|
|
USHORT timeout = 0;
|
2003-10-29 11:53:47 +01:00
|
|
|
const SCHAR* items = send_items;
|
|
|
|
const SCHAR* const end_items = items + send_item_length;
|
2001-05-23 15:26:42 +02:00
|
|
|
while (items < end_items && *items != isc_info_end)
|
|
|
|
{
|
|
|
|
switch ((item = *items++))
|
|
|
|
{
|
|
|
|
case isc_info_end:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if (items + 2 <= end_items)
|
|
|
|
{
|
2003-11-16 02:44:51 +01:00
|
|
|
l = (USHORT) gds__vax_integer(reinterpret_cast<const UCHAR*>(items), 2);
|
2001-05-23 15:26:42 +02:00
|
|
|
items += 2;
|
|
|
|
if (items + l <= end_items)
|
|
|
|
{
|
|
|
|
switch (item) {
|
|
|
|
case isc_info_svc_line:
|
|
|
|
service_put(service, items, l);
|
|
|
|
break;
|
|
|
|
case isc_info_svc_message:
|
|
|
|
service_put(service, items - 3, l + 3);
|
|
|
|
break;
|
|
|
|
case isc_info_svc_timeout:
|
|
|
|
timeout =
|
2003-11-16 02:44:51 +01:00
|
|
|
(USHORT) gds__vax_integer(reinterpret_cast<const UCHAR*>(items), l);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case isc_info_svc_version:
|
|
|
|
version =
|
2003-11-16 02:44:51 +01:00
|
|
|
(USHORT) gds__vax_integer(reinterpret_cast<const UCHAR*>(items), l);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
items += l;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
items += 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Process the receive portion of the query now. */
|
|
|
|
|
2003-10-29 11:53:47 +01:00
|
|
|
const SCHAR* const end = info + buffer_length;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
items = recv_items;
|
2003-10-29 11:53:47 +01:00
|
|
|
const SCHAR* const end_items2 = items + recv_item_length;
|
|
|
|
while (items < end_items2 && *items != isc_info_end)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
switch ((item = *items++))
|
|
|
|
{
|
|
|
|
case isc_info_end:
|
|
|
|
break;
|
|
|
|
|
|
|
|
#ifdef SERVER_SHUTDOWN
|
|
|
|
case isc_info_svc_svr_db_info:
|
2007-04-19 09:30:00 +02:00
|
|
|
if (service->svc_user_flag & SVC_user_dba)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2006-10-30 13:39:08 +01:00
|
|
|
ULONG num_att = 0;
|
|
|
|
ULONG num_dbs = 0;
|
2001-12-24 03:51:06 +01:00
|
|
|
JRD_num_attachments(NULL, 0, 0, &num_att, &num_dbs);
|
2003-11-01 11:26:43 +01:00
|
|
|
length = INF_convert(num_att, buffer);
|
2001-12-24 03:51:06 +01:00
|
|
|
info = INF_put_item(item,
|
|
|
|
length,
|
2003-11-01 11:26:43 +01:00
|
|
|
buffer,
|
2001-12-24 03:51:06 +01:00
|
|
|
info,
|
|
|
|
end);
|
|
|
|
if (!info) {
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-12-24 03:51:06 +01:00
|
|
|
return;
|
|
|
|
}
|
2003-11-01 11:26:43 +01:00
|
|
|
length = INF_convert(num_dbs, buffer);
|
2001-12-24 03:51:06 +01:00
|
|
|
info = INF_put_item(item,
|
|
|
|
length,
|
2003-11-01 11:26:43 +01:00
|
|
|
buffer,
|
2001-12-24 03:51:06 +01:00
|
|
|
info,
|
|
|
|
end);
|
|
|
|
if (!info) {
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-12-24 03:51:06 +01:00
|
|
|
return;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2007-04-19 09:30:00 +02:00
|
|
|
/*
|
|
|
|
* Can not return error for service v.1 => simply ignore request
|
|
|
|
else
|
|
|
|
need_admin_privs(&status, "isc_info_svc_svr_db_info");
|
|
|
|
*/
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_svr_online:
|
|
|
|
*info++ = item;
|
|
|
|
if (service->svc_user_flag & SVC_user_dba) {
|
2004-03-18 06:56:06 +01:00
|
|
|
service->svc_do_shutdown = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
WHY_set_shutdown(FALSE);
|
|
|
|
*info++ = 0; /* Success */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*info++ = 2; /* No user authority */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_svr_offline:
|
|
|
|
*info++ = item;
|
|
|
|
if (service->svc_user_flag & SVC_user_dba) {
|
2004-03-18 06:56:06 +01:00
|
|
|
service->svc_do_shutdown = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
WHY_set_shutdown(TRUE);
|
|
|
|
*info++ = 0; /* Success */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*info++ = 2; /* No user authority */
|
|
|
|
break;
|
|
|
|
#endif /* SERVER_SHUTDOWN */
|
|
|
|
|
|
|
|
/* The following 3 service commands (or items) stuff the response
|
2007-02-11 10:04:54 +01:00
|
|
|
buffer 'info' with values of environment variable FIREBIRD,
|
|
|
|
FIREBIRD_LOCK or FIREBIRD_MSG. If the environment variable
|
2001-05-23 15:26:42 +02:00
|
|
|
is not set then default value is returned.
|
|
|
|
*/
|
|
|
|
case isc_info_svc_get_env:
|
|
|
|
case isc_info_svc_get_env_lock:
|
|
|
|
case isc_info_svc_get_env_msg:
|
|
|
|
switch (item) {
|
|
|
|
case isc_info_svc_get_env:
|
2003-04-06 13:40:29 +02:00
|
|
|
gds__prefix(PathBuffer, "");
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case isc_info_svc_get_env_lock:
|
2003-04-06 13:40:29 +02:00
|
|
|
gds__prefix_lock(PathBuffer, "");
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case isc_info_svc_get_env_msg:
|
2003-04-06 13:40:29 +02:00
|
|
|
gds__prefix_msg(PathBuffer, "");
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Note: it is safe to use strlen to get a length of "buffer"
|
|
|
|
because gds_prefix[_lock|_msg] return a zero-terminated
|
|
|
|
string
|
|
|
|
*/
|
2003-04-06 13:40:29 +02:00
|
|
|
if (!(info = INF_put_item(item, strlen(PathBuffer),
|
2004-12-24 09:52:39 +01:00
|
|
|
PathBuffer, info, end)))
|
|
|
|
{
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
case isc_info_svc_dump_pool_info:
|
|
|
|
{
|
|
|
|
char fname[MAXPATHLEN];
|
2004-05-12 21:39:17 +02:00
|
|
|
size_t length2 = isc_vax_integer(items, sizeof(USHORT));
|
|
|
|
if (length2 >= sizeof(fname))
|
|
|
|
length2 = sizeof(fname) - 1; // truncation
|
2001-05-23 15:26:42 +02:00
|
|
|
items += sizeof(USHORT);
|
2004-05-12 21:39:17 +02:00
|
|
|
strncpy(fname, items, length2);
|
|
|
|
fname[length2] = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
JRD_print_all_counters(fname);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
2003-07-04 14:12:54 +02:00
|
|
|
/*
|
2001-05-23 15:26:42 +02:00
|
|
|
case isc_info_svc_get_config:
|
2003-07-04 14:12:54 +02:00
|
|
|
// TODO: iterate through all integer-based config values
|
|
|
|
// and return them to the client
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_default_config:
|
|
|
|
*info++ = item;
|
|
|
|
if (service->svc_user_flag & SVC_user_dba) {
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2003-07-04 14:12:54 +02:00
|
|
|
// TODO: reset the config values to defaults
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2007-04-19 09:30:00 +02:00
|
|
|
*
|
|
|
|
* Can not return error for service v.1 => simply ignore request
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
2007-04-19 09:30:00 +02:00
|
|
|
need_admin_privs(&status, "isc_info_svc_default_config:");
|
|
|
|
*
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_set_config:
|
|
|
|
*info++ = item;
|
|
|
|
if (service->svc_user_flag & SVC_user_dba) {
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2003-07-04 14:12:54 +02:00
|
|
|
// TODO: set the config values
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2007-04-19 09:30:00 +02:00
|
|
|
*
|
|
|
|
* Can not return error for service v.1 => simply ignore request
|
|
|
|
else
|
|
|
|
need_admin_privs(&status, "isc_info_svc_set_config:");
|
|
|
|
*
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
2003-07-04 14:12:54 +02:00
|
|
|
*/
|
2001-05-23 15:26:42 +02:00
|
|
|
case isc_info_svc_version:
|
|
|
|
/* The version of the service manager */
|
|
|
|
|
|
|
|
length =
|
2003-11-01 11:26:43 +01:00
|
|
|
INF_convert(SERVICE_VERSION, buffer);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!
|
|
|
|
(info =
|
2003-11-01 11:26:43 +01:00
|
|
|
INF_put_item(item, length, buffer, info, end)))
|
|
|
|
{
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_capabilities:
|
|
|
|
/* bitmask defining any specific architectural differences */
|
|
|
|
|
|
|
|
length =
|
2003-11-01 11:26:43 +01:00
|
|
|
INF_convert(SERVER_CAPABILITIES_FLAG, buffer);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!
|
|
|
|
(info =
|
2003-11-01 11:26:43 +01:00
|
|
|
INF_put_item(item, length, buffer, info, end)))
|
|
|
|
{
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_server_version:
|
|
|
|
{
|
2003-10-29 11:53:47 +01:00
|
|
|
/* The version of the server engine */
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
p = buffer;
|
2003-10-29 11:53:47 +01:00
|
|
|
*p++ = 1; /* Count */
|
|
|
|
*p++ = sizeof(GDS_VERSION) - 1;
|
|
|
|
for (const TEXT* gvp = GDS_VERSION; *gvp; p++, gvp++)
|
|
|
|
*p = *gvp;
|
2003-11-01 11:26:43 +01:00
|
|
|
if (!(info = INF_put_item(item, p - buffer, buffer, info, end)))
|
2003-10-29 11:53:47 +01:00
|
|
|
{
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2003-10-29 11:53:47 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
case isc_info_svc_implementation:
|
2007-02-11 10:04:54 +01:00
|
|
|
/* The server implementation - e.g. Firebird/sun4 */
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
p = buffer;
|
2001-05-23 15:26:42 +02:00
|
|
|
*p++ = 1; /* Count */
|
|
|
|
*p++ = IMPLEMENTATION;
|
2003-11-01 11:26:43 +01:00
|
|
|
if (!(info = INF_put_item(item, p - buffer, buffer, info, end)))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case isc_info_svc_user_dbpath:
|
2007-04-19 09:30:00 +02:00
|
|
|
if (service->svc_user_flag & SVC_user_dba)
|
|
|
|
{
|
|
|
|
/* The path to the user security database (security2.fdb) */
|
|
|
|
SecurityDatabase::getPath(buffer);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-04-19 09:30:00 +02:00
|
|
|
if (!(info = INF_put_item(item, strlen(buffer), buffer, info, end)))
|
|
|
|
{
|
|
|
|
THREAD_ENTER();
|
|
|
|
return;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2007-04-19 09:30:00 +02:00
|
|
|
/*
|
|
|
|
* Can not return error for service v.1 => simply ignore request
|
|
|
|
else
|
|
|
|
need_admin_privs(&status, "isc_info_svc_user_dbpath");
|
|
|
|
*/
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_response:
|
|
|
|
service->svc_resp_len = 0;
|
|
|
|
if (info + 4 > end)
|
|
|
|
{
|
|
|
|
*info++ = isc_info_truncated;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
service_put(service, &item, 1);
|
|
|
|
service_get(service, &item, 1, GET_BINARY, 0, &length);
|
2003-11-01 11:26:43 +01:00
|
|
|
service_get(service, buffer, 2, GET_BINARY, 0, &length);
|
2003-11-16 02:44:51 +01:00
|
|
|
l = (USHORT) gds__vax_integer(reinterpret_cast<UCHAR*>(buffer), 2);
|
2001-05-23 15:26:42 +02:00
|
|
|
length = MIN(end - (info + 4), l);
|
|
|
|
service_get(service, info + 3, length, GET_BINARY, 0, &length);
|
|
|
|
info = INF_put_item(item, length, info + 3, info, end);
|
|
|
|
if (length != l)
|
|
|
|
{
|
|
|
|
*info++ = isc_info_truncated;
|
|
|
|
l -= length;
|
|
|
|
if (l > service->svc_resp_buf_len)
|
|
|
|
{
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
if (service->svc_resp_buf)
|
2004-09-26 13:23:32 +02:00
|
|
|
gds__free(service->svc_resp_buf);
|
2001-05-23 15:26:42 +02:00
|
|
|
service->svc_resp_buf = (UCHAR *) gds__alloc((SLONG) l);
|
|
|
|
/* FREE: in SVC_detach() */
|
|
|
|
if (!service->svc_resp_buf)
|
|
|
|
{ /* NOMEM: */
|
|
|
|
DEV_REPORT("SVC_query: out of memory");
|
|
|
|
/* NOMEM: not really handled well */
|
|
|
|
l = 0; /* set the length to zero */
|
|
|
|
}
|
|
|
|
service->svc_resp_buf_len = l;
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
service_get(service,
|
|
|
|
reinterpret_cast<char*>(service->svc_resp_buf),
|
|
|
|
l,
|
|
|
|
GET_BINARY,
|
|
|
|
0,
|
|
|
|
&length);
|
|
|
|
service->svc_resp_ptr = service->svc_resp_buf;
|
|
|
|
service->svc_resp_len = l;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_response_more:
|
2001-12-24 03:51:06 +01:00
|
|
|
if ( (l = length = service->svc_resp_len) )
|
2001-05-23 15:26:42 +02:00
|
|
|
length = MIN(end - (info + 4), l);
|
|
|
|
if (!(info = INF_put_item(item,
|
|
|
|
length,
|
2004-03-18 06:56:06 +01:00
|
|
|
reinterpret_cast<const char*>
|
|
|
|
(service->svc_resp_ptr),
|
2001-05-23 15:26:42 +02:00
|
|
|
info,
|
|
|
|
end)))
|
|
|
|
{
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
service->svc_resp_ptr += length;
|
|
|
|
service->svc_resp_len -= length;
|
|
|
|
if (length != l)
|
|
|
|
*info++ = isc_info_truncated;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_total_length:
|
|
|
|
service_put(service, &item, 1);
|
|
|
|
service_get(service, &item, 1, GET_BINARY, 0, &length);
|
2003-11-01 11:26:43 +01:00
|
|
|
service_get(service, buffer, 2, GET_BINARY, 0, &length);
|
2003-11-16 02:44:51 +01:00
|
|
|
l = (USHORT) gds__vax_integer(reinterpret_cast<UCHAR*>(buffer), 2);
|
2003-11-01 11:26:43 +01:00
|
|
|
service_get(service, buffer, l, GET_BINARY, 0, &length);
|
|
|
|
if (!(info = INF_put_item(item, length, buffer, info, end)))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_svc_line:
|
|
|
|
case isc_info_svc_to_eof:
|
|
|
|
if (info + 4 > end)
|
|
|
|
{
|
|
|
|
*info++ = isc_info_truncated;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
get_flags = (item == isc_info_svc_line) ? GET_LINE : GET_EOF;
|
|
|
|
service_get(service, info + 3, end - (info + 4), get_flags,
|
|
|
|
timeout, &length);
|
|
|
|
|
2002-02-16 04:27:33 +01:00
|
|
|
/* If the read timed out, return the data, if any, & a timeout
|
2001-05-23 15:26:42 +02:00
|
|
|
item. If the input buffer was not large enough
|
|
|
|
to store a read to eof, return the data that was read along
|
|
|
|
with an indication that more is available. */
|
|
|
|
|
|
|
|
info = INF_put_item(item, length, info + 3, info, end);
|
|
|
|
|
|
|
|
if (service->svc_flags & SVC_timeout)
|
|
|
|
*info++ = isc_info_svc_timeout;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!length && !(service->svc_flags & SVC_finished))
|
|
|
|
*info++ = isc_info_data_not_ready;
|
|
|
|
else
|
|
|
|
if (item == isc_info_svc_to_eof &&
|
|
|
|
!(service->svc_flags & SVC_finished))
|
|
|
|
*info++ = isc_info_truncated;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info < end)
|
|
|
|
{
|
|
|
|
*info = isc_info_end;
|
|
|
|
}
|
|
|
|
|
2004-03-24 20:48:57 +01:00
|
|
|
if (!(service->svc_flags & SVC_thd_running))
|
|
|
|
{
|
|
|
|
SVC_finish(service, SVC_finished);
|
|
|
|
}
|
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-30 18:32:11 +01:00
|
|
|
void* SVC_start(Service* service, USHORT spb_length, const SCHAR* spb_data)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* S V C _ s t a r t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2003-03-29 16:49:38 +01:00
|
|
|
* Start a Firebird service
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
2004-03-01 04:35:23 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
/* NOTE: The parameter RESERVED must not be used
|
|
|
|
* for any purpose as there are networking issues
|
|
|
|
* involved (as with any handle that goes over the
|
2002-02-16 04:27:33 +01:00
|
|
|
* network). This parameter will be implemented at
|
2001-05-23 15:26:42 +02:00
|
|
|
* a later date.
|
2004-03-01 04:35:23 +01:00
|
|
|
*/
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-09-26 11:26:40 +02:00
|
|
|
isc_resv_handle reserved = (isc_resv_handle)0; /* Reserved for future functionality */
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-11-30 18:32:11 +01:00
|
|
|
Firebird::ClumpletReader spb(Firebird::ClumpletReader::SpbStart,
|
|
|
|
reinterpret_cast<const UCHAR*>(spb_data), spb_length);
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
/* The name of the service is the first element of the buffer */
|
2005-11-30 18:32:11 +01:00
|
|
|
const UCHAR svc_id = spb.getClumpTag();
|
2004-02-20 07:43:27 +01:00
|
|
|
serv_entry* serv;
|
|
|
|
for (serv = services; serv->serv_action; serv++)
|
2001-05-23 15:26:42 +02:00
|
|
|
if (serv->serv_action == svc_id)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (!serv->serv_name)
|
2003-05-05 10:40:35 +02:00
|
|
|
ERR_post(isc_service_att_err, isc_arg_gds, isc_service_not_supported, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* currently we do not use "anonymous" service for any purposes but
|
|
|
|
isc_service_query() */
|
2005-12-08 16:33:03 +01:00
|
|
|
if (service->svc_user_flag == SVC_user_none) {
|
2001-05-23 15:26:42 +02:00
|
|
|
ERR_post(isc_bad_spb_form, 0);
|
2005-12-08 16:33:03 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-06-06 14:37:24 +02:00
|
|
|
thd_mutex.enter();
|
2001-05-23 15:26:42 +02:00
|
|
|
if (service->svc_flags & SVC_thd_running) {
|
2007-06-06 14:37:24 +02:00
|
|
|
thd_mutex.leave();
|
2001-05-23 15:26:42 +02:00
|
|
|
ERR_post(isc_svc_in_use, isc_arg_string,
|
2006-02-23 06:08:26 +01:00
|
|
|
error_string(serv->serv_name, strlen(serv->serv_name)),
|
2004-02-20 07:43:27 +01:00
|
|
|
0);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2005-12-02 17:54:04 +01:00
|
|
|
/* Another service may have been started with this service block.
|
|
|
|
* If so, we must reset the service flags.
|
|
|
|
*/
|
|
|
|
service->svc_switches.erase();
|
|
|
|
if (!(service->svc_flags & SVC_detached))
|
|
|
|
{
|
|
|
|
service->svc_flags = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2005-12-02 17:54:04 +01:00
|
|
|
service->svc_flags |= SVC_thd_running;
|
2007-06-06 14:37:24 +02:00
|
|
|
thd_mutex.leave();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-22 16:28:54 +02:00
|
|
|
thread_db* tdbb = JRD_get_thread_data();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-12-02 17:54:04 +01:00
|
|
|
if (!service->svc_perm_sw.hasData())
|
|
|
|
{
|
|
|
|
/* If svc_perm_sw is not used -- call a command-line parsing utility */
|
|
|
|
conv_switches(spb, service->svc_switches);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Command line options (isc_spb_options) is used.
|
|
|
|
* Currently the only case in which it might happen is -- gbak utility
|
|
|
|
* is called with a "-server" switch.
|
|
|
|
*/
|
|
|
|
service->svc_switches = service->svc_perm_sw;
|
|
|
|
}
|
|
|
|
|
2002-02-16 04:27:33 +01:00
|
|
|
/* Only need to add username and password information to those calls which need
|
2001-05-23 15:26:42 +02:00
|
|
|
* to make a database connection
|
|
|
|
*/
|
2005-11-30 18:32:11 +01:00
|
|
|
if (svc_id == isc_action_svc_backup ||
|
|
|
|
svc_id == isc_action_svc_restore ||
|
|
|
|
svc_id == isc_action_svc_repair ||
|
|
|
|
svc_id == isc_action_svc_add_user ||
|
|
|
|
svc_id == isc_action_svc_delete_user ||
|
|
|
|
svc_id == isc_action_svc_modify_user ||
|
|
|
|
svc_id == isc_action_svc_display_user ||
|
|
|
|
svc_id == isc_action_svc_db_stats ||
|
|
|
|
svc_id == isc_action_svc_properties)
|
2003-11-28 07:48:34 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
/* add the username and password to the end of svc_switches if needed */
|
2006-12-08 19:38:15 +01:00
|
|
|
if (service->svc_switches.hasData())
|
|
|
|
{
|
2007-04-07 10:47:58 +02:00
|
|
|
#ifdef TRUSTED_SERVICES
|
2006-12-08 19:38:15 +01:00
|
|
|
if (service->svc_trusted_login.hasData())
|
2005-12-02 17:54:04 +01:00
|
|
|
{
|
|
|
|
service->svc_switches += ' ';
|
2006-12-08 19:38:15 +01:00
|
|
|
service->svc_switches += TRUSTED_USER_SWITCH;
|
2005-12-02 17:54:04 +01:00
|
|
|
service->svc_switches += ' ';
|
|
|
|
service->svc_switches += service->svc_username;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2006-12-08 19:38:15 +01:00
|
|
|
else
|
|
|
|
#endif
|
2005-12-02 17:54:04 +01:00
|
|
|
{
|
2006-12-08 19:38:15 +01:00
|
|
|
if (service->svc_username.hasData())
|
|
|
|
{
|
|
|
|
service->svc_switches += ' ';
|
|
|
|
service->svc_switches += USERNAME_SWITCH;
|
|
|
|
service->svc_switches += ' ';
|
|
|
|
service->svc_switches += service->svc_username;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (service->svc_enc_password.hasData())
|
|
|
|
{
|
|
|
|
service->svc_switches += ' ';
|
|
|
|
service->svc_switches += PASSWORD_SWITCH;
|
|
|
|
service->svc_switches += ' ';
|
|
|
|
service->svc_switches += service->svc_enc_password;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-12-02 17:54:04 +01:00
|
|
|
|
|
|
|
// All services except for get_ib_log require switches
|
2005-11-30 18:32:11 +01:00
|
|
|
spb.rewind();
|
2007-03-02 10:04:30 +01:00
|
|
|
if ((!service->svc_switches.hasData()) && svc_id != isc_action_svc_get_fb_log)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
ERR_post(isc_bad_spb_form, 0);
|
2005-12-08 16:33:03 +01:00
|
|
|
}
|
2007-03-02 10:04:30 +01:00
|
|
|
|
|
|
|
// Do not let everyone look at server log
|
|
|
|
if (svc_id == isc_action_svc_get_fb_log && !(service->svc_user_flag & SVC_user_dba))
|
|
|
|
{
|
|
|
|
ERR_post(isc_adm_task_denied, 0);
|
|
|
|
}
|
|
|
|
|
2005-08-10 16:47:42 +02:00
|
|
|
#ifndef SERVICE_THREAD
|
2004-11-16 09:52:29 +01:00
|
|
|
TEXT service_path[MAXPATHLEN];
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (serv->serv_executable) {
|
2003-04-06 13:40:29 +02:00
|
|
|
gds__prefix(service_path, serv->serv_executable);
|
2001-05-23 15:26:42 +02:00
|
|
|
service->svc_flags = SVC_forked;
|
|
|
|
service_fork(service_path, service);
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
/* Break up the command line into individual arguments. */
|
2006-07-27 16:24:09 +02:00
|
|
|
service->parseSwitches();
|
|
|
|
service->svc_argv[0] = (TEXT *)(serv->serv_thd);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* the service block can be reused hence free a memory from the
|
|
|
|
* previous usage as well as init a status vector.
|
|
|
|
*/
|
|
|
|
|
2006-06-16 10:13:20 +02:00
|
|
|
memset((void *) service->svc_status, 0, sizeof(ISC_STATUS_ARRAY));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (service->svc_stdout)
|
|
|
|
gds__free(service->svc_stdout);
|
|
|
|
|
2001-05-24 16:54:26 +02:00
|
|
|
service->svc_stdout = (UCHAR*)gds__alloc((SLONG) SVC_STDOUT_BUFFER_SIZE + 1);
|
2001-05-23 15:26:42 +02:00
|
|
|
/* FREE: at SVC_detach() */
|
|
|
|
if (!service->svc_stdout) /* NOMEM: */
|
2002-02-16 04:27:33 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
ERR_post(isc_virmemexh, 0);
|
2001-05-24 16:54:26 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (serv->serv_thd) {
|
2007-06-05 09:14:01 +02:00
|
|
|
service->svc_flags &= ~SVC_evnt_fired;
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-06-08 15:41:08 +02:00
|
|
|
gds__thread_start(serv->serv_thd, service, THREAD_medium, 0,
|
2001-05-23 15:26:42 +02:00
|
|
|
(void *) &service->svc_handle);
|
|
|
|
|
2007-06-05 09:14:01 +02:00
|
|
|
// Check for the service being detached. This will prevent the thread
|
|
|
|
// from waiting infinitely if the client goes away.
|
|
|
|
while (!(service->svc_flags & SVC_detached))
|
|
|
|
{
|
|
|
|
// The semaphore will be released once the particular service
|
|
|
|
// has reached a point in which it can start to return
|
|
|
|
// information to the client. This will allow isc_service_start
|
|
|
|
// to include in its status vector information about the service's
|
|
|
|
// ability to start.
|
|
|
|
// This is needed since gds__thread_start will almost always succeed.
|
|
|
|
if (service->svcStart.tryEnter(60))
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2007-06-05 09:14:01 +02:00
|
|
|
// svc_started was called
|
2003-05-05 09:06:06 +02:00
|
|
|
break;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
|
|
|
ERR_post(isc_svcnotdef,
|
|
|
|
isc_arg_string,
|
2006-02-23 06:08:26 +01:00
|
|
|
error_string(serv->serv_name, strlen(serv->serv_name)),
|
2001-12-24 03:51:06 +01:00
|
|
|
0);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-08-10 16:47:42 +02:00
|
|
|
#endif /* SERVICE_THREAD */
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return reinterpret_cast<void*>(reserved);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-02-23 06:08:26 +01:00
|
|
|
THREAD_ENTRY_DECLARE SVC_read_fb_log(THREAD_ENTRY_PARAM arg)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* S V C _ r e a d _ i b _ l o g
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2003-03-29 16:49:38 +01:00
|
|
|
* Service function which reads the Firebird
|
2001-05-23 15:26:42 +02:00
|
|
|
* log file into the service buffers.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-08-31 14:55:33 +02:00
|
|
|
bool svc_started = false;
|
2004-06-08 15:41:08 +02:00
|
|
|
Service* service = (Service*)arg;
|
2005-08-10 16:47:42 +02:00
|
|
|
#ifdef SERVICE_THREAD
|
2003-08-31 14:55:33 +02:00
|
|
|
ISC_STATUS *status = service->svc_status;
|
2001-05-23 15:26:42 +02:00
|
|
|
*status++ = isc_arg_gds;
|
|
|
|
#endif
|
|
|
|
|
2004-11-16 09:52:29 +01:00
|
|
|
TEXT name[MAXPATHLEN];
|
2001-05-23 15:26:42 +02:00
|
|
|
gds__prefix(name, LOGFILE);
|
2004-04-29 00:43:34 +02:00
|
|
|
FILE* file = fopen(name, "r");
|
2004-02-20 07:43:27 +01:00
|
|
|
if (file != NULL) {
|
2005-08-10 16:47:42 +02:00
|
|
|
#ifdef SERVICE_THREAD
|
2002-11-14 09:33:08 +01:00
|
|
|
*status++ = FB_SUCCESS;
|
2001-05-23 15:26:42 +02:00
|
|
|
*status++ = isc_arg_end;
|
|
|
|
#endif
|
2004-02-20 07:43:27 +01:00
|
|
|
service->svc_started();
|
2003-08-31 14:55:33 +02:00
|
|
|
svc_started = true;
|
2004-11-16 09:52:29 +01:00
|
|
|
TEXT buffer[100];
|
2004-04-29 00:43:34 +02:00
|
|
|
while (!feof(file) && !ferror(file)) {
|
|
|
|
fgets(buffer, sizeof(buffer), file);
|
2005-08-10 16:47:42 +02:00
|
|
|
#ifdef SERVICE_THREAD
|
2001-05-23 15:26:42 +02:00
|
|
|
SVC_fprintf(service, "%s", buffer);
|
|
|
|
#else
|
|
|
|
service_put(service, buffer, sizeof(buffer));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-04-29 00:43:34 +02:00
|
|
|
if (!file || file && ferror(file)) {
|
2005-08-10 16:47:42 +02:00
|
|
|
#ifdef SERVICE_THREAD
|
2001-05-23 15:26:42 +02:00
|
|
|
*status++ = isc_sys_request;
|
|
|
|
if (!file) {
|
2007-03-28 06:20:36 +02:00
|
|
|
SVC_STATUS_ARG(status, "fopen");
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else {
|
2007-03-28 06:20:36 +02:00
|
|
|
SVC_STATUS_ARG(status, "fgets");
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
*status++ = SYS_ARG;
|
|
|
|
*status++ = errno;
|
|
|
|
*status++ = isc_arg_end;
|
|
|
|
#endif
|
|
|
|
if (!svc_started)
|
2003-08-31 14:55:33 +02:00
|
|
|
{
|
2004-02-20 07:43:27 +01:00
|
|
|
service->svc_started();
|
2003-08-31 14:55:33 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (file)
|
2004-04-29 00:43:34 +02:00
|
|
|
fclose(file);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-08-10 16:47:42 +02:00
|
|
|
#ifdef SERVICE_THREAD
|
2001-05-23 15:26:42 +02:00
|
|
|
SVC_finish(service, SVC_finished);
|
|
|
|
#else
|
2006-02-23 06:08:26 +01:00
|
|
|
cleanup(service);
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
2003-09-15 15:13:45 +02:00
|
|
|
return (FINI_OK);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
static void get_options(Firebird::ClumpletReader& spb,
|
|
|
|
Serv_param_block* options)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g e t _ o p t i o n s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Parse service parameter block picking up options and things.
|
|
|
|
*
|
|
|
|
**************************************/
|
2005-11-27 21:53:09 +01:00
|
|
|
const UCHAR p = spb.getBufferTag();
|
2005-12-08 16:33:03 +01:00
|
|
|
if (p != isc_spb_version1 && p != isc_spb_current_version) {
|
2001-05-23 15:26:42 +02:00
|
|
|
ERR_post(isc_bad_spb_form, isc_arg_gds, isc_wrospbver, 0);
|
2005-12-08 16:33:03 +01:00
|
|
|
}
|
2005-11-27 21:53:09 +01:00
|
|
|
options->spb_version = p;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
for (spb.rewind(); !(spb.isEof()); spb.moveNext())
|
|
|
|
{
|
|
|
|
switch (spb.getClumpTag())
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
case isc_spb_sys_user_name:
|
2005-11-27 21:53:09 +01:00
|
|
|
spb.getString(options->spb_sys_user_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_spb_user_name:
|
2005-11-27 21:53:09 +01:00
|
|
|
spb.getString(options->spb_user_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_spb_password:
|
2005-11-27 21:53:09 +01:00
|
|
|
spb.getString(options->spb_password);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_spb_password_enc:
|
2005-11-27 21:53:09 +01:00
|
|
|
spb.getString(options->spb_password_enc);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
2007-04-07 10:47:58 +02:00
|
|
|
#ifdef TRUSTED_SERVICES
|
2006-12-08 19:38:15 +01:00
|
|
|
case isc_spb_trusted_auth:
|
|
|
|
spb.getString(options->spb_trusted_login);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
case isc_spb_command_line:
|
2005-11-27 21:53:09 +01:00
|
|
|
spb.getString(options->spb_command_line);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
case isc_spb_address_path:
|
2003-11-28 07:48:34 +01:00
|
|
|
{
|
2005-11-27 21:53:09 +01:00
|
|
|
Firebird::ClumpletReader address_stack(Firebird::ClumpletReader::UnTagged,
|
|
|
|
spb.getBytes(), spb.getClumpLength());
|
|
|
|
while (!address_stack.isEof()) {
|
|
|
|
if (address_stack.getClumpTag() != isc_dpb_address) {
|
|
|
|
address_stack.moveNext();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
Firebird::ClumpletReader address(Firebird::ClumpletReader::UnTagged,
|
|
|
|
address_stack.getBytes(), address_stack.getClumpLength());
|
|
|
|
while (!address.isEof()) {
|
|
|
|
switch (address.getClumpTag()) {
|
|
|
|
case isc_dpb_addr_protocol:
|
|
|
|
address.getString(options->spb_network_protocol);
|
|
|
|
break;
|
|
|
|
case isc_dpb_addr_endpoint:
|
|
|
|
address.getString(options->spb_remote_address);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
address.moveNext();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2003-11-28 07:48:34 +01:00
|
|
|
}
|
2005-11-27 21:53:09 +01:00
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
}
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-10 16:47:42 +02:00
|
|
|
#ifndef SERVICE_THREAD
|
|
|
|
static void io_error(const TEXT* string,
|
2001-05-23 15:26:42 +02:00
|
|
|
SLONG status,
|
2005-08-10 16:47:42 +02:00
|
|
|
const TEXT* filename, ISC_STATUS operation)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* i o _ e r r o r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2005-08-10 16:47:42 +02:00
|
|
|
* Report an I/O error.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
ERR_post(isc_io_error, isc_arg_string, string, isc_arg_string, filename,
|
|
|
|
isc_arg_gds, operation, SYS_ERR, status, 0);
|
|
|
|
}
|
2003-04-02 16:31:37 +02:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
2005-08-10 16:47:42 +02:00
|
|
|
#ifdef SERVICE_THREAD
|
2001-05-23 15:26:42 +02:00
|
|
|
static USHORT service_add_one(USHORT i)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e r v i c e _ a d d _ o n e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
return ((i % SVC_STDOUT_BUFFER_SIZE) + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
static USHORT service_empty(Service* service)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e r v i c e _ e m p t y
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
if (service_add_one(service->svc_stdout_tail) == service->svc_stdout_head)
|
2001-05-24 16:54:26 +02:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
static USHORT service_full(Service* service)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e r v i c e _ f u l l
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
if (service_add_one(service_add_one(service->svc_stdout_tail)) ==
|
2004-11-16 09:52:29 +01:00
|
|
|
service->svc_stdout_head)
|
|
|
|
{
|
|
|
|
return (1);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
static UCHAR service_dequeue_byte(Service* service)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e r v i c e _ d e q u e u e _ b y t e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-20 07:43:27 +01:00
|
|
|
const UCHAR ch = service->svc_stdout[service->svc_stdout_head];
|
2001-05-23 15:26:42 +02:00
|
|
|
service->svc_stdout_head = service_add_one(service->svc_stdout_head);
|
|
|
|
|
|
|
|
return (ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
static void service_enqueue_byte(UCHAR ch, Service* service)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e r v i c e _ e n q u e u e _ b y t e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
/* Wait for space in buffer while service is not detached. */
|
|
|
|
while (service_full(service) && !(service->svc_flags & SVC_detached))
|
2003-05-24 09:46:27 +02:00
|
|
|
THREAD_SLEEP(1);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Ensure that service is not detached. */
|
|
|
|
if (!(service->svc_flags & SVC_detached)) {
|
|
|
|
service->svc_stdout_tail = service_add_one(service->svc_stdout_tail);
|
|
|
|
service->svc_stdout[service->svc_stdout_tail] = ch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-07-02 12:47:03 +02:00
|
|
|
static void service_fork(ThreadEntryPoint* service_executable, Service* service)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e r v i c e _ f o r k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Startup a service.
|
|
|
|
*
|
|
|
|
**************************************/
|
2006-07-28 03:44:36 +02:00
|
|
|
|
2006-07-28 04:17:11 +02:00
|
|
|
// Break up the command line into individual arguments.
|
2006-07-27 16:24:09 +02:00
|
|
|
service->parseSwitches();
|
2006-07-28 03:44:36 +02:00
|
|
|
|
2006-07-27 16:24:09 +02:00
|
|
|
USHORT argc = service->svc_argc;
|
|
|
|
service->svc_argv[0] = (TEXT *)(service_executable);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2004-06-08 15:41:08 +02:00
|
|
|
gds__thread_start(service_executable,
|
2004-11-08 10:38:30 +01:00
|
|
|
service, THREAD_medium, 0, (void*)&service->svc_handle);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
static void service_get(Service* service,
|
2001-05-24 16:54:26 +02:00
|
|
|
SCHAR* buffer,
|
|
|
|
USHORT length,
|
|
|
|
USHORT flags,
|
|
|
|
USHORT timeout,
|
|
|
|
USHORT* return_length)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e r v i c e _ g e t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-10-31 12:33:45 +01:00
|
|
|
|
2002-08-14 13:14:01 +02:00
|
|
|
#ifdef HAVE_GETTIMEOFDAY
|
2001-05-23 15:26:42 +02:00
|
|
|
struct timeval start_time, end_time;
|
2003-10-31 12:33:45 +01:00
|
|
|
GETTIMEOFDAY(&start_time);
|
2002-08-14 13:14:01 +02:00
|
|
|
#else
|
|
|
|
time_t start_time, end_time;
|
|
|
|
time(&start_time);
|
2002-08-24 11:40:38 +02:00
|
|
|
#endif
|
2003-10-31 12:33:45 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
*return_length = 0;
|
|
|
|
service->svc_flags &= ~SVC_timeout;
|
|
|
|
|
|
|
|
while (length) {
|
|
|
|
if (service_empty(service))
|
2003-05-24 09:46:27 +02:00
|
|
|
THREAD_SLEEP(1);
|
2002-08-14 13:14:01 +02:00
|
|
|
#ifdef HAVE_GETTIMEOFDAY
|
2003-10-31 12:33:45 +01:00
|
|
|
GETTIMEOFDAY(&end_time);
|
2004-11-16 09:52:29 +01:00
|
|
|
const time_t elapsed_time = end_time.tv_sec - start_time.tv_sec;
|
2002-08-14 13:14:01 +02:00
|
|
|
#else
|
|
|
|
time(&end_time);
|
2004-11-16 09:52:29 +01:00
|
|
|
const time_t elapsed_time = end_time - start_time;
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
if ((timeout) && (elapsed_time >= timeout)) {
|
|
|
|
service->svc_flags &= SVC_timeout;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!service_empty(service) && length > 0) {
|
2004-12-24 09:52:39 +01:00
|
|
|
const int ch = service_dequeue_byte(service);
|
2001-05-23 15:26:42 +02:00
|
|
|
length--;
|
|
|
|
|
|
|
|
/* If returning a line of information, replace all new line
|
|
|
|
* characters with a space. This will ensure that the output is
|
|
|
|
* consistent when returning a line or to eof
|
|
|
|
*/
|
|
|
|
if ((flags & GET_LINE) && (ch == '\n')) {
|
|
|
|
buffer[(*return_length)++] = ' ';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
buffer[(*return_length)++] = ch;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (service_empty(service) && (service->svc_flags & SVC_finished))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
static void service_put(Service* service, const SCHAR* buffer, USHORT length)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e r v i c e _ p u t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Send output to a service. It is assumed
|
|
|
|
* that we have checked out of the scheduler.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
/* Nothing */
|
|
|
|
}
|
2005-08-10 16:47:42 +02:00
|
|
|
#endif /* SERVICE_THREAD */
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
2005-08-10 16:47:42 +02:00
|
|
|
#ifndef SERVICE_THREAD
|
2005-10-22 14:35:04 +02:00
|
|
|
|
|
|
|
#ifdef WIN_NT
|
|
|
|
|
|
|
|
static void service_fork(TEXT* service_path, Service* service)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e r v i c e _ f o r k ( W I N _ N T )
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Startup a service. Just a stub.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
ERR_post(isc_service_att_err, isc_arg_gds, isc_service_not_supported, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void service_get(
|
|
|
|
Service* service,
|
|
|
|
SCHAR * buffer,
|
|
|
|
USHORT length,
|
|
|
|
USHORT flags, USHORT timeout, USHORT * return_length)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e r v i c e _ g e t ( W I N _ N T )
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get input from a service.
|
|
|
|
* Just a stub
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
}
|
|
|
|
|
|
|
|
static void service_put(Service* service, const SCHAR* buffer, USHORT length)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e r v i c e _ p u t ( W I N _ N T )
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Send output to a service.
|
|
|
|
* Just a stub
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
static void service_fork(TEXT* service_path, Service* service)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e r v i c e _ f o r k ( G E N E R I C )
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Startup a service.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-20 07:43:27 +01:00
|
|
|
int pair1[2], pair2[2];
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (pipe(pair1) < 0 || pipe(pair2) < 0)
|
2005-08-10 16:47:42 +02:00
|
|
|
io_error("pipe", errno, "", isc_io_create_err);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Probe service executable to see it if plausibly exists. */
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
struct stat stat_buf;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (statistics(service_path, &stat_buf) == -1)
|
2005-08-10 16:47:42 +02:00
|
|
|
io_error("stat", errno, service_path, isc_io_access_err);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Break up the command line into individual arguments. */
|
2006-07-27 16:24:09 +02:00
|
|
|
service->parseSwitches();
|
|
|
|
const char **argv = &service->svc_argv[0];
|
|
|
|
*argv = service_path;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* At last we can fork the sub-process. If the fork succeeds, repeat
|
|
|
|
it so that we don't have defunct processes hanging around. */
|
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
int pid;
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
switch (pid = vfork()) {
|
|
|
|
case -1:
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
ERR_post(isc_sys_request, isc_arg_string, "vfork", SYS_ERR, errno, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0:
|
|
|
|
if (vfork() != 0)
|
|
|
|
_exit(FINI_OK);
|
|
|
|
|
|
|
|
close(pair1[0]);
|
|
|
|
close(pair2[1]);
|
|
|
|
if (pair2[0] != 0) {
|
|
|
|
close(0);
|
|
|
|
dup(pair2[0]);
|
|
|
|
close(pair2[0]);
|
|
|
|
}
|
|
|
|
if (pair1[1] != 1) {
|
|
|
|
close(1);
|
|
|
|
dup(pair1[1]);
|
|
|
|
close(pair1[1]);
|
|
|
|
}
|
|
|
|
close(2);
|
|
|
|
dup(1);
|
2002-10-07 15:33:45 +02:00
|
|
|
#ifdef DEV_BUILD
|
|
|
|
{
|
|
|
|
char buf[2 * MAXPATHLEN];
|
2006-07-27 16:24:09 +02:00
|
|
|
const char** s = argv;
|
2002-10-07 15:33:45 +02:00
|
|
|
|
|
|
|
strcpy (buf, "service_fork:");
|
|
|
|
while (*s != (char *)0)
|
|
|
|
{
|
2004-02-20 07:43:27 +01:00
|
|
|
strcat(buf, " ");
|
|
|
|
strcat(buf, *s);
|
2002-10-07 15:33:45 +02:00
|
|
|
s++;
|
|
|
|
}
|
2003-03-29 16:49:38 +01:00
|
|
|
gds__log(buf);
|
2002-10-07 15:33:45 +02:00
|
|
|
}
|
|
|
|
#endif
|
2006-07-27 16:24:09 +02:00
|
|
|
execvp(argv[0], const_cast<char* const*>(argv));
|
2001-05-23 15:26:42 +02:00
|
|
|
_exit(FINI_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
close(pair1[1]);
|
|
|
|
close(pair2[0]);
|
|
|
|
|
|
|
|
waitpid(pid, NULL, 0);
|
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-12-02 17:54:04 +01:00
|
|
|
if (!(service->svc_input = fdopen(pair1[0], "r")) ||
|
|
|
|
!(service->svc_output = fdopen(pair2[1], "w")))
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
2005-08-10 16:47:42 +02:00
|
|
|
io_error("fdopen", errno, "service path", isc_io_access_err);
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void service_get(
|
2004-03-18 06:56:06 +01:00
|
|
|
Service* service,
|
2001-05-23 15:26:42 +02:00
|
|
|
SCHAR * buffer,
|
|
|
|
USHORT length,
|
|
|
|
USHORT flags, USHORT timeout, USHORT * return_length)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e r v i c e _ g e t ( G E N E R I C )
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get input from a service. It is assumed
|
|
|
|
* that we have checked out of the scheduler.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
struct itimerval sv_timr;
|
|
|
|
struct sigaction sv_hndlr;
|
|
|
|
|
2003-09-19 02:36:12 +02:00
|
|
|
is_service_running(service);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-19 02:36:12 +02:00
|
|
|
errno = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
service->svc_flags &= ~SVC_timeout;
|
2004-02-20 07:43:27 +01:00
|
|
|
SCHAR* buf = buffer;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
SSHORT iter = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (timeout) {
|
2003-09-08 22:23:46 +02:00
|
|
|
ISC_set_timer((SLONG) (timeout * 100000), timeout_handler, service,
|
2001-07-12 07:46:06 +02:00
|
|
|
(SLONG*)&sv_timr, (void**)&sv_hndlr);
|
2001-05-23 15:26:42 +02:00
|
|
|
iter = timeout * 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!timeout || iter) {
|
2004-04-29 00:43:34 +02:00
|
|
|
const int c = getc((FILE *) service->svc_input);
|
2004-02-20 07:43:27 +01:00
|
|
|
if (c != EOF) {
|
2006-05-19 17:17:02 +02:00
|
|
|
*buf++ = (flags & GET_LINE) && (c == '\n') ? ' ' : c;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!(--length))
|
|
|
|
break;
|
|
|
|
if (((flags & GET_LINE) && c == '\n') ||
|
|
|
|
(!(flags & GET_BINARY) && c == '\001'))
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else if (!errno) {
|
|
|
|
service->svc_flags |= SVC_finished;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (SYSCALL_INTERRUPTED(errno)) {
|
|
|
|
if (timeout)
|
|
|
|
--iter;
|
|
|
|
}
|
|
|
|
else {
|
2004-02-20 07:43:27 +01:00
|
|
|
const int errno_save = errno;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (timeout)
|
2003-09-08 22:23:46 +02:00
|
|
|
ISC_reset_timer(timeout_handler, service, (SLONG*)&sv_timr,
|
2001-07-12 07:46:06 +02:00
|
|
|
(void**)&sv_hndlr);
|
2005-08-10 16:47:42 +02:00
|
|
|
io_error("getc", errno_save, "service pipe", isc_io_read_err);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (timeout) {
|
2003-09-08 22:23:46 +02:00
|
|
|
ISC_reset_timer(timeout_handler, service, (SLONG*)&sv_timr, (void**)&sv_hndlr);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!iter)
|
|
|
|
service->svc_flags |= SVC_timeout;
|
|
|
|
}
|
|
|
|
|
|
|
|
*return_length = buf - buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
static void service_put(Service* service, const SCHAR* buffer, USHORT length)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e r v i c e _ p u t ( G E N E R I C )
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Send output to a service. It is assumed
|
|
|
|
* that we have checked out of the scheduler.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2003-09-19 02:36:12 +02:00
|
|
|
is_service_running(service);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-19 02:36:12 +02:00
|
|
|
while (length--) {
|
2004-04-29 00:43:34 +02:00
|
|
|
if (putc(*buffer, (FILE *) service->svc_output) != EOF)
|
2001-05-23 15:26:42 +02:00
|
|
|
buffer++;
|
|
|
|
else if (SYSCALL_INTERRUPTED(errno)) {
|
2004-04-29 00:43:34 +02:00
|
|
|
rewind((FILE *) service->svc_output);
|
2001-05-23 15:26:42 +02:00
|
|
|
length++;
|
|
|
|
}
|
|
|
|
else
|
2005-08-10 16:47:42 +02:00
|
|
|
io_error("putc", errno, "service pipe", isc_io_write_err);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-04-29 00:43:34 +02:00
|
|
|
if (fflush((FILE *) service->svc_output) == EOF)
|
2005-08-10 16:47:42 +02:00
|
|
|
io_error("fflush", errno, "service pipe", isc_io_write_err);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
static void timeout_handler(void* service)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* t i m e o u t _ h a n d l e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Called when no input has been received
|
|
|
|
* through a pipe for a specificed period
|
|
|
|
* of time.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
}
|
2005-10-22 14:35:04 +02:00
|
|
|
#endif // !WIN_NT
|
2005-08-10 16:47:42 +02:00
|
|
|
#endif // SERVICE_THREAD
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
2006-02-23 06:08:26 +01:00
|
|
|
static void cleanup(Service* service)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2006-02-23 06:08:26 +01:00
|
|
|
* c l e a n u p
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Cleanup memory used by service.
|
|
|
|
*
|
|
|
|
**************************************/
|
2001-12-24 03:51:06 +01:00
|
|
|
delete service;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
void SVC_finish(Service* service, USHORT flag)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* S V C _ f i n i s h
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* o Set the flag (either SVC_finished for the main service thread or
|
|
|
|
* SVC_detached for the client thread).
|
|
|
|
* o If both main thread and client thread are completed that is main
|
|
|
|
* thread is finished and client is detached then free memory
|
|
|
|
* used by service.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2007-06-06 14:37:24 +02:00
|
|
|
svc_mutex.enter();
|
2004-01-07 11:23:46 +01:00
|
|
|
if (service && ((flag == SVC_finished) || (flag == SVC_detached)))
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
service->svc_flags |= flag;
|
|
|
|
if ((service->svc_flags & SVC_finished) &&
|
2004-01-07 11:23:46 +01:00
|
|
|
(service->svc_flags & SVC_detached))
|
|
|
|
{
|
2006-02-23 06:08:26 +01:00
|
|
|
cleanup(service);
|
2004-01-07 11:23:46 +01:00
|
|
|
}
|
|
|
|
else if (service->svc_flags & SVC_finished)
|
|
|
|
{
|
2004-02-20 07:43:27 +01:00
|
|
|
if (service->svc_service && service->svc_service->serv_in_use)
|
2004-01-07 11:23:46 +01:00
|
|
|
{
|
2004-02-20 07:43:27 +01:00
|
|
|
*(service->svc_service->serv_in_use) = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2004-01-07 11:23:46 +01:00
|
|
|
|
|
|
|
service->svc_flags &= ~SVC_thd_running;
|
|
|
|
|
|
|
|
#ifdef WIN_NT
|
|
|
|
CloseHandle((HANDLE) service->svc_handle);
|
|
|
|
#endif
|
|
|
|
service->svc_handle = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
2007-06-06 14:37:24 +02:00
|
|
|
svc_mutex.leave();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-02-23 06:08:26 +01:00
|
|
|
static const TEXT* error_string(const TEXT* data, USHORT length)
|
|
|
|
{
|
|
|
|
/********************************************
|
|
|
|
*
|
|
|
|
* e r r o r _ s t r i n g
|
|
|
|
*
|
|
|
|
********************************************
|
|
|
|
*
|
|
|
|
* Functional Description:
|
|
|
|
* Uses ERR_string to save string data for the
|
|
|
|
* status vector
|
2007-03-28 06:20:36 +02:00
|
|
|
* CVC: None of the callees check the pointer, so we do here as paranoid measure.
|
|
|
|
* The chain is error_string->ERR_string->status_nstring->InterlockedStringsBuffer::alloc
|
|
|
|
* ->CircularBuffer::alloc->memcpy
|
2006-02-23 06:08:26 +01:00
|
|
|
********************************************/
|
2007-03-28 06:20:36 +02:00
|
|
|
if (data)
|
|
|
|
return ERR_string(data, length);
|
|
|
|
|
|
|
|
data = "(null string)";
|
|
|
|
return ERR_string(data, strlen(data));
|
2006-02-23 06:08:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const TEXT* error_string(const Firebird::string& s)
|
|
|
|
{
|
|
|
|
return ERR_string(s.c_str(), s.length());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-12-02 17:54:04 +01:00
|
|
|
static void conv_switches(Firebird::ClumpletReader& spb, Firebird::string& switches)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* c o n v _ s w i t c h e s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Convert spb flags to utility switches.
|
|
|
|
*
|
|
|
|
**************************************/
|
2005-11-30 18:32:11 +01:00
|
|
|
spb.rewind();
|
|
|
|
if (spb.getClumpTag() < isc_action_min || spb.getClumpTag() > isc_action_max)
|
2001-05-23 15:26:42 +02:00
|
|
|
return; /* error action not defined */
|
|
|
|
|
2005-11-30 18:32:11 +01:00
|
|
|
// convert to string
|
|
|
|
Firebird::string sw;
|
|
|
|
if (! process_switches(spb, sw))
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
2005-11-30 18:32:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sw.insert(0, ' ');
|
|
|
|
sw.insert(0, SERVICE_THD_PARAM);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-12-02 17:54:04 +01:00
|
|
|
switches = sw;
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
static const TEXT* find_switch(int in_spb_sw, const in_sw_tab_t* table)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* f i n d _ s w i t c h
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
for (const in_sw_tab_t* in_sw_tab = table; in_sw_tab->in_sw_name; in_sw_tab++)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
if (in_spb_sw == in_sw_tab->in_spb_sw)
|
|
|
|
return in_sw_tab->in_sw_name;
|
|
|
|
}
|
|
|
|
|
2003-08-28 15:16:03 +02:00
|
|
|
return NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-30 18:32:11 +01:00
|
|
|
static bool process_switches(Firebird::ClumpletReader& spb,
|
|
|
|
Firebird::string& switches)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* p r o c e s s _ s w i t c h e s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
*Functional description
|
|
|
|
* Loop through the appropriate switch table
|
|
|
|
* looking for the text for the given command switch.
|
|
|
|
*
|
|
|
|
**************************************/
|
2005-11-30 18:32:11 +01:00
|
|
|
if (spb.getBufferLength() == 0)
|
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-11-30 18:32:11 +01:00
|
|
|
spb.rewind();
|
|
|
|
const UCHAR svc_action = spb.getClumpTag();
|
|
|
|
spb.moveNext();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-04-26 16:59:46 +02:00
|
|
|
Firebird::string burp_database, burp_backup;
|
|
|
|
int burp_options = 0;
|
2004-02-20 07:43:27 +01:00
|
|
|
bool found = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-11-30 18:32:11 +01:00
|
|
|
do
|
|
|
|
{
|
|
|
|
switch (svc_action)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
case isc_action_svc_delete_user:
|
|
|
|
case isc_action_svc_display_user:
|
|
|
|
if (!found) {
|
2005-11-30 18:32:11 +01:00
|
|
|
if (!get_action_svc_parameter(svc_action, gsec_action_in_sw_table, switches))
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
2005-11-30 18:32:11 +01:00
|
|
|
return false;
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
else {
|
2007-04-27 17:07:42 +02:00
|
|
|
if (spb.isEof() && svc_action == isc_action_svc_display_user)
|
2005-12-02 17:54:04 +01:00
|
|
|
{
|
2007-04-27 17:07:42 +02:00
|
|
|
// in case of "display all users" the spb buffer contains
|
2007-10-08 15:35:54 +02:00
|
|
|
// nothing but isc_action_svc_display_user or isc_spb_dbname
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
2005-12-02 17:54:04 +01:00
|
|
|
}
|
2007-10-10 04:06:20 +02:00
|
|
|
|
2007-10-08 15:35:54 +02:00
|
|
|
if (spb.getClumpTag() != isc_spb_sec_username &&
|
2007-10-10 04:06:20 +02:00
|
|
|
spb.getClumpTag() != isc_spb_dbname)
|
|
|
|
{
|
2007-04-27 17:07:42 +02:00
|
|
|
// unexpected item in service parameter block, expected @1
|
|
|
|
ERR_post(isc_unexp_spb_form, isc_arg_string,
|
|
|
|
error_string(SPB_SEC_USERNAME,
|
|
|
|
strlen(SPB_SEC_USERNAME)),
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
found = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-27 17:07:42 +02:00
|
|
|
switch (spb.getClumpTag())
|
|
|
|
{
|
|
|
|
case isc_spb_sql_role_name:
|
2005-09-30 18:16:39 +02:00
|
|
|
case isc_spb_dbname:
|
2005-11-30 18:32:11 +01:00
|
|
|
if (!get_action_svc_parameter(spb.getClumpTag(), gsec_in_sw_table, switches))
|
2005-09-30 18:16:39 +02:00
|
|
|
{
|
2005-11-30 18:32:11 +01:00
|
|
|
return false;
|
2005-09-30 18:16:39 +02:00
|
|
|
}
|
2007-04-27 17:07:42 +02:00
|
|
|
// fall through ....
|
|
|
|
case isc_spb_sec_username:
|
2005-11-30 18:32:11 +01:00
|
|
|
get_action_svc_string(spb, switches);
|
2005-09-30 18:16:39 +02:00
|
|
|
break;
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
default:
|
2005-11-30 18:32:11 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_action_svc_add_user:
|
|
|
|
case isc_action_svc_modify_user:
|
|
|
|
if (!found) {
|
2005-11-30 18:32:11 +01:00
|
|
|
if (!get_action_svc_parameter(svc_action, gsec_action_in_sw_table, switches))
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
2005-11-30 18:32:11 +01:00
|
|
|
return false;
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
else {
|
2005-11-30 18:32:11 +01:00
|
|
|
if (spb.getClumpTag() != isc_spb_sec_username) {
|
2007-04-27 17:07:42 +02:00
|
|
|
// unexpected item in service parameter block, expected @1
|
2001-05-23 15:26:42 +02:00
|
|
|
ERR_post(isc_unexp_spb_form, isc_arg_string,
|
2006-02-23 06:08:26 +01:00
|
|
|
error_string(SPB_SEC_USERNAME,
|
2004-02-20 07:43:27 +01:00
|
|
|
strlen(SPB_SEC_USERNAME)),
|
|
|
|
0);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2007-04-27 17:07:42 +02:00
|
|
|
found = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-27 17:07:42 +02:00
|
|
|
switch (spb.getClumpTag())
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
case isc_spb_sec_userid:
|
|
|
|
case isc_spb_sec_groupid:
|
2005-11-30 18:32:11 +01:00
|
|
|
if (!get_action_svc_parameter(spb.getClumpTag(), gsec_in_sw_table, switches))
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
2005-11-30 18:32:11 +01:00
|
|
|
return false;
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
2005-11-30 18:32:11 +01:00
|
|
|
get_action_svc_data(spb, switches);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_spb_sql_role_name:
|
|
|
|
case isc_spb_sec_password:
|
|
|
|
case isc_spb_sec_groupname:
|
|
|
|
case isc_spb_sec_firstname:
|
|
|
|
case isc_spb_sec_middlename:
|
|
|
|
case isc_spb_sec_lastname:
|
2005-09-30 18:16:39 +02:00
|
|
|
case isc_spb_dbname:
|
2005-11-30 18:32:11 +01:00
|
|
|
if (!get_action_svc_parameter(spb.getClumpTag(), gsec_in_sw_table, switches))
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
2005-11-30 18:32:11 +01:00
|
|
|
return false;
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
2007-04-27 17:07:42 +02:00
|
|
|
// fall through ....
|
|
|
|
case isc_spb_sec_username:
|
2005-11-30 18:32:11 +01:00
|
|
|
get_action_svc_string(spb, switches);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2005-11-30 18:32:11 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_action_svc_db_stats:
|
2005-11-30 18:32:11 +01:00
|
|
|
switch (spb.getClumpTag()) {
|
2001-05-23 15:26:42 +02:00
|
|
|
case isc_spb_dbname:
|
2005-11-30 18:32:11 +01:00
|
|
|
get_action_svc_string(spb, switches);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_spb_options:
|
2005-11-30 18:32:11 +01:00
|
|
|
if (!get_action_svc_bitmask(spb, dba_in_sw_table, switches))
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
2005-11-30 18:32:11 +01:00
|
|
|
return false;
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
2003-08-26 09:23:58 +02:00
|
|
|
|
|
|
|
case isc_spb_command_line:
|
2005-11-30 18:32:11 +01:00
|
|
|
get_action_svc_string(spb, switches);
|
2003-08-26 09:23:58 +02:00
|
|
|
break;
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
default:
|
2005-12-01 06:34:18 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_action_svc_backup:
|
|
|
|
case isc_action_svc_restore:
|
2005-11-30 18:32:11 +01:00
|
|
|
switch (spb.getClumpTag()) {
|
2001-05-23 15:26:42 +02:00
|
|
|
case isc_spb_bkp_file:
|
2007-04-26 16:59:46 +02:00
|
|
|
get_action_svc_string(spb, burp_backup);
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
case isc_spb_dbname:
|
2007-04-26 16:59:46 +02:00
|
|
|
get_action_svc_string(spb, burp_database);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case isc_spb_options:
|
2007-04-26 16:59:46 +02:00
|
|
|
burp_options |= spb.getInt();
|
2005-11-30 18:32:11 +01:00
|
|
|
if (!get_action_svc_bitmask(spb, burp_in_sw_table, switches))
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
2005-12-01 06:34:18 +01:00
|
|
|
return false;
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case isc_spb_bkp_length:
|
2007-04-26 16:59:46 +02:00
|
|
|
get_action_svc_data(spb, burp_backup);
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
case isc_spb_res_length:
|
2007-04-26 16:59:46 +02:00
|
|
|
get_action_svc_data(spb, burp_database);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case isc_spb_bkp_factor:
|
|
|
|
case isc_spb_res_buffers:
|
|
|
|
case isc_spb_res_page_size:
|
2005-11-30 18:32:11 +01:00
|
|
|
if (!get_action_svc_parameter(spb.getClumpTag(), burp_in_sw_table, switches))
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
2005-12-01 06:34:18 +01:00
|
|
|
return false;
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
2005-11-30 18:32:11 +01:00
|
|
|
get_action_svc_data(spb, switches);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case isc_spb_res_access_mode:
|
2005-12-08 16:33:03 +01:00
|
|
|
if (!get_action_svc_parameter(*(spb.getBytes()), burp_in_sw_table, switches))
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
2005-12-01 06:34:18 +01:00
|
|
|
return false;
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case isc_spb_verbose:
|
2005-11-30 18:32:11 +01:00
|
|
|
if (!get_action_svc_parameter(spb.getClumpTag(), burp_in_sw_table, switches))
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
2005-12-01 06:34:18 +01:00
|
|
|
return false;
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
default:
|
2005-12-01 06:34:18 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_action_svc_repair:
|
|
|
|
case isc_action_svc_properties:
|
2005-11-30 18:32:11 +01:00
|
|
|
switch (spb.getClumpTag()) {
|
2001-05-23 15:26:42 +02:00
|
|
|
case isc_spb_dbname:
|
2005-11-30 18:32:11 +01:00
|
|
|
get_action_svc_string(spb, switches);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case isc_spb_options:
|
2005-11-30 18:32:11 +01:00
|
|
|
if (!get_action_svc_bitmask(spb, alice_in_sw_table, switches))
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
2005-12-01 06:34:18 +01:00
|
|
|
return false;
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case isc_spb_prp_page_buffers:
|
|
|
|
case isc_spb_prp_sweep_interval:
|
|
|
|
case isc_spb_prp_shutdown_db:
|
|
|
|
case isc_spb_prp_deny_new_attachments:
|
|
|
|
case isc_spb_prp_deny_new_transactions:
|
|
|
|
case isc_spb_prp_set_sql_dialect:
|
|
|
|
case isc_spb_rpr_commit_trans:
|
|
|
|
case isc_spb_rpr_rollback_trans:
|
|
|
|
case isc_spb_rpr_recover_two_phase:
|
2005-11-30 18:32:11 +01:00
|
|
|
if (!get_action_svc_parameter(spb.getClumpTag(), alice_in_sw_table, switches))
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
2005-12-01 06:34:18 +01:00
|
|
|
return false;
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
2005-11-30 18:32:11 +01:00
|
|
|
get_action_svc_data(spb, switches);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case isc_spb_prp_write_mode:
|
|
|
|
case isc_spb_prp_access_mode:
|
|
|
|
case isc_spb_prp_reserve_space:
|
2005-12-10 11:15:56 +01:00
|
|
|
if (!get_action_svc_parameter(*(spb.getBytes()), alice_in_sw_table, switches))
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
2005-12-01 06:34:18 +01:00
|
|
|
return false;
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
default:
|
2005-12-01 06:34:18 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2005-12-01 06:34:18 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
2005-11-30 18:32:11 +01:00
|
|
|
|
|
|
|
spb.moveNext();
|
2005-12-01 06:34:18 +01:00
|
|
|
} while (! spb.isEof());
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-04-26 16:59:46 +02:00
|
|
|
// postfixes for burp
|
|
|
|
switch (svc_action)
|
|
|
|
{
|
|
|
|
case isc_action_svc_backup:
|
|
|
|
switches += (burp_database + burp_backup);
|
|
|
|
break;
|
|
|
|
case isc_action_svc_restore:
|
|
|
|
if (! (burp_options & (isc_spb_res_create | isc_spb_res_replace)))
|
|
|
|
{
|
|
|
|
// user not specified create or replace database
|
|
|
|
// default to create for restore
|
|
|
|
switches += "-CREATE_DATABASE ";
|
|
|
|
}
|
|
|
|
switches += (burp_backup + burp_database);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-12-04 13:30:34 +01:00
|
|
|
switches.rtrim();
|
2005-12-01 06:34:18 +01:00
|
|
|
return switches.length() > 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-30 18:32:11 +01:00
|
|
|
static bool get_action_svc_bitmask(const Firebird::ClumpletReader& spb,
|
|
|
|
const in_sw_tab_t* table,
|
|
|
|
Firebird::string& switches)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g e t _ a c t i o n _ s v c _ b i t m a s k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get bitmask from within spb buffer,
|
|
|
|
* find corresponding switches within specified table,
|
|
|
|
* add them to the command line,
|
|
|
|
* adjust pointers.
|
|
|
|
*
|
|
|
|
**************************************/
|
2005-11-30 18:32:11 +01:00
|
|
|
const int opt = spb.getInt();
|
2003-11-28 07:48:34 +01:00
|
|
|
ISC_ULONG mask = 1;
|
2005-11-30 18:32:11 +01:00
|
|
|
for (int count = (sizeof(ISC_ULONG) * 8) - 1; count--; mask <<= 1)
|
|
|
|
{
|
|
|
|
if (opt & mask)
|
|
|
|
{
|
2003-12-31 06:36:12 +01:00
|
|
|
const TEXT* s_ptr = find_switch((opt & mask), table);
|
|
|
|
if (!s_ptr)
|
2005-11-30 18:32:11 +01:00
|
|
|
{
|
2004-02-20 07:43:27 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2005-11-30 18:32:11 +01:00
|
|
|
|
|
|
|
switches += '-';
|
|
|
|
switches += s_ptr;
|
|
|
|
switches += ' ';
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-30 18:32:11 +01:00
|
|
|
static void get_action_svc_string(const Firebird::ClumpletReader& spb,
|
|
|
|
Firebird::string& switches)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g e t _ a c t i o n _ s v c _ s t r i n g
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get string from within spb buffer,
|
|
|
|
* add it to the command line, adjust pointers.
|
|
|
|
*
|
|
|
|
* All string parameters are delimited by SVC_TRMNTR. This
|
|
|
|
* is done to ensure that paths with spaces are handled correctly
|
|
|
|
* when creating the argc / argv paramters for the service.
|
|
|
|
*
|
|
|
|
**************************************/
|
2005-11-30 18:32:11 +01:00
|
|
|
Firebird::string s;
|
|
|
|
spb.getString(s);
|
2006-07-27 16:24:09 +02:00
|
|
|
for (size_t i = 0; i < s.length(); ++i)
|
|
|
|
{
|
|
|
|
if (s[i] == SVC_TRMNTR)
|
|
|
|
{
|
|
|
|
s.insert(i, 1, SVC_TRMNTR);
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
2005-11-30 18:32:11 +01:00
|
|
|
switches += SVC_TRMNTR;
|
|
|
|
switches += s;
|
|
|
|
switches += SVC_TRMNTR;
|
|
|
|
switches += ' ';
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-30 18:32:11 +01:00
|
|
|
static void get_action_svc_data(const Firebird::ClumpletReader& spb,
|
|
|
|
Firebird::string& switches)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g e t _ a c t i o n _ s v c _ d a t a
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get data from within spb buffer,
|
|
|
|
* add it to the command line, adjust pointers.
|
|
|
|
*
|
|
|
|
**************************************/
|
2005-11-30 18:32:11 +01:00
|
|
|
Firebird::string s;
|
|
|
|
s.printf("%"ULONGFORMAT" ", spb.getInt());
|
|
|
|
switches += s;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-30 18:32:11 +01:00
|
|
|
static bool get_action_svc_parameter(UCHAR action,
|
|
|
|
const in_sw_tab_t* table,
|
|
|
|
Firebird::string& switches)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g e t _ a c t i o n _ s v c _ p a r a m e t e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get parameter from within spb buffer,
|
|
|
|
* find corresponding switch within specified table,
|
|
|
|
* add it to the command line,
|
|
|
|
* adjust pointers.
|
|
|
|
*
|
|
|
|
**************************************/
|
2005-11-30 18:32:11 +01:00
|
|
|
const TEXT* s_ptr = find_switch(action, table);
|
2003-12-31 06:36:12 +01:00
|
|
|
if (!s_ptr)
|
2005-11-30 18:32:11 +01:00
|
|
|
{
|
2004-02-20 07:43:27 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2005-11-30 18:32:11 +01:00
|
|
|
switches += '-';
|
|
|
|
switches += s_ptr;
|
|
|
|
switches += ' ';
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
/* The following two functions are temporary stubs and will be
|
2002-02-16 04:27:33 +01:00
|
|
|
* removed as the services API takes shape. They are used to
|
2001-05-23 15:26:42 +02:00
|
|
|
* test that the paths for starting services and parsing command-lines
|
|
|
|
* are followed correctly.
|
|
|
|
*/
|
2004-06-08 15:41:08 +02:00
|
|
|
THREAD_ENTRY_DECLARE test_thread(THREAD_ENTRY_PARAM)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
gds__log("Starting service");
|
2003-09-15 15:13:45 +02:00
|
|
|
return FINI_OK;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
void test_cmd(USHORT spb_length, SCHAR* spb, TEXT** switches)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
gds__log("test_cmd called");
|
|
|
|
}
|
|
|
|
#endif
|
2003-10-29 11:53:47 +01:00
|
|
|
|