3
* PROGRAM: Firebird server manager
5
* DESCRIPTION: server manager's routines
7
* The contents of this file are subject to the Interbase Public
8
* License Version 1.0 (the "License"); you may not use this file
9
* except in compliance with the License. You may obtain a copy
10
* of the License at http://www.Inprise.com/IPL.html
12
* Software distributed under the License is distributed on an
13
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
14
* or implied. See the License for the specific language governing
15
* rights and limitations under the License.
17
* The Original Code was created by Inprise Corporation
18
* and its predecessors. Portions created by Inprise Corporation are
19
* Copyright (C) Inprise Corporation.
21
* All Rights Reserved.
22
* Contributor(s): ______________________________________.
37
#include <sys/types.h>
39
# include <sys/wait.h>
43
#include "../jrd/common.h"
44
#include "../jrd/ibase.h"
45
#include "../jrd/gds_proto.h"
46
#include "../jrd/gdsassert.h"
47
#include "../jrd/svc_undoc.h"
48
#include "../common/stuff.h"
49
#include "../utilities/ibmgr/ibmgr.h"
50
#include "../utilities/ibmgr/srvrmgr_proto.h"
52
const int SPB_BUFLEN = 128; /* service params buffer length */
53
//#define SEND_BUFLEN 32 /* length of send and resp */
54
//#define RESP_BUFLEN 128 /* used by isc_service_query */
56
/* After we fork and exec a guardian process, to determine
57
if the server have started we wait ATTACH_PAUSE seconds
58
and try to attach to it. This happens ATTACH_RETRY number
61
const int ATTACH_PAUSE = 1; /* seconds to pause before attach */
62
const int ATTACH_RETRY = 10; /* Number of attach retries */
65
static bool attach_service(ibmgr_data_t*);
66
static bool detach_service(ibmgr_data_t*);
67
static bool print_pool(ibmgr_data_t*);
68
static bool start_shutdown(ibmgr_data_t*);
69
static bool start_server(ibmgr_data_t*);
70
#ifdef NOT_USED_OR_REPLACED
71
static bool server_is_ok(ibmgr_data_t*);
73
static bool server_is_up(ibmgr_data_t*);
75
void SRVRMGR_cleanup( ibmgr_data_t* data)
77
/**************************************
79
* S R V R M G R _ c l e a n u p
81
**************************************
83
* Functional description
84
* If we are attached to a service, detaches
86
**************************************/
92
USHORT SRVRMGR_exec_line(ibmgr_data_t* data)
94
/**************************************
96
* S R V R M G R _ e x e c _ l i n e
98
**************************************
100
* Functional description
101
* Executes command line
103
**************************************/
104
fb_assert(data->attached || data->reattach);
106
/* If reattach is true and we currently attached, then we
107
will detach from service. This is potentially dangerous
108
situation, because if shutdown is true (server shutdown
109
was initiated) server will be shutdowned.
110
I do not check the shutdown flag here because reattach
111
could be true only if shutdown has not been initiated.
113
if (data->operation != OP_START)
114
if (data->reattach) {
115
fb_assert(!data->shutdown);
118
/* Attached flag should be NULL after detach_service
120
detach_service(data);
121
if (attach_service(data) == false)
126
switch (data->operation) {
128
if (start_server(data) == false)
129
return MSG_STARTFAIL;
133
switch (data->suboperation) {
136
data->shutdown = true;
137
if (start_shutdown(data) == false) {
138
data->shutdown = false;
139
return MSG_SSHUTFAIL;
141
detach_service(data);
142
data->shutdown = false;
143
data->reattach |= (REA_HOST | REA_USER | REA_PASSWORD);
147
printf("SHUTDOWN NO ATTACHMENTS\n");
148
data->shutdown = true;
152
printf("SHUTDOWN NO TRANSACTIONS\n");
153
data->shutdown = true;
157
printf("SHUTDOWN IGNORE\n");
158
data->shutdown = false;
164
switch (data->suboperation) {
166
if (print_pool(data) == false)
167
return MSG_PRPOOLFAIL;
175
"ASSERT: file %s line %"LINEFORMAT": unknown operation %d\n",
176
__FILE__, __LINE__, data->operation);
185
void SRVRMGR_msg_get( USHORT number, TEXT * msg)
187
/**************************************
189
* S R V R M G R _ m s g _ g e t
191
**************************************
193
* Functional description
194
* Retrieve a message from the error file
196
**************************************/
198
/* The following line will be the future of this function
200
static const SafeArg arg;
201
fb_msg_format (0, MSG_FAC, number, MSG_LEN, msg, arg);
212
rs = "operation already specified";
215
rs = "no operation specified";
218
rs = "illegal operation/switch combination";
221
rs = "warning: shutdown is in progress";
224
rs = "can not change host, password or user";
227
rs = "fbmgr version";
230
rs = "invalid switch";
233
rs = "ambiguous switch";
236
rs = "invalid switch combination";
239
rs = "warning: only 8 significant bytes of password used";
242
rs = "invalid user (only 32 bytes allowed";
245
rs = "invalid parameter, no switch specified";
248
rs = "switch does not take any parameter";
251
rs = "switch requires parameter";
254
rs = "syntax error in command line";
257
rs = "can not get password entry";
260
rs = "can not attach to server";
263
rs = "can not start another shutdown";
266
rs = "can not start server shutdown";
269
rs = "server shutdown completed";
272
rs = "can not quit now, use shut -ign";
275
rs = "check $FIREBIRD/firebird.log file for errors";
278
rs = "can not start server";
281
rs = "server is already running";
284
rs = "server has been successfully started";
287
rs = "no permissions to perform operation";
290
rs = "Failed to print pool info";
293
rs = "Print pool Successfull";
295
case MSG_FLNMTOOLONG:
296
rs = "File name too long";
299
rs = "can not get an error message";
306
static bool attach_service( ibmgr_data_t* data)
308
/**************************************
310
* a t t a c h _ s e r v i c e
312
**************************************
314
* Functional description
315
* Attaches to "anonymous" or "query_server"
316
* service depending on thr user name.
318
**************************************/
319
ISC_STATUS_ARRAY status;
322
/* Obviously we should not be already attached to service
324
fb_assert(!data->attached);
326
strcpy(svc_name, data->host);
328
TEXT spb[SPB_BUFLEN];
331
if (!strcmp(data->user, SYSDBA_USER_NAME)) {
332
*p++ = isc_spb_version1;
333
*p++ = isc_spb_user_name;
334
*p++ = strlen(SYSDBA_USER_NAME);
335
strcpy(p, SYSDBA_USER_NAME);
337
*p++ = isc_spb_password;
338
*p++ = strlen(data->password);
339
strcpy(p, data->password);
341
strcat(svc_name, ":query_server");
344
fprintf(OUTFILE, "spb: \"%s\"\nsvc_name: \"%s\"\n", spb, svc_name);
347
isc_service_attach(status, 0, svc_name, &data->attached, strlen(spb),
351
strcat(svc_name, ":anonymous");
352
isc_service_attach(status, 0, svc_name, &data->attached, 0, "");
355
if (status[0] == 1 && status[1] > 0) {
357
fprintf(OUTFILE, "ERROR: %lu\n", status[1]);
359
fb_assert(status[1] != isc_svcnotdef);
360
isc_print_status(status);
367
static bool detach_service( ibmgr_data_t* data)
369
/**************************************
371
* d e t a c h _ s e r v i c e
373
**************************************
375
* Functional description
376
* Detaches from service.
377
* If IBMGR_shutdown_start was called
378
* before, shutdowns the server.
380
**************************************/
381
ISC_STATUS_ARRAY status;
383
/* We should be attached if we want to detach
385
fb_assert(data->attached);
387
isc_service_detach(status, &data->attached);
390
if (status[0] == 1 && status[1] > 0) {
391
/* If as a result of detach_service server has been
392
shutdowned we will get an error.
393
MMM - need to check for that error and return true
396
fprintf(OUTFILE, "ERROR: %lu\n", status[1]);
399
isc_print_status(status);
406
static bool start_shutdown( ibmgr_data_t* data)
408
/**************************************
410
* s t a r t _ s h u t d o w n
412
**************************************
414
* Functional description
415
* Initiate shutdown process
417
**************************************/
418
ISC_STATUS_ARRAY status;
421
/* We should be attached to ask for any service
423
fb_assert(data->attached);
425
const char sendbuf[] = { isc_info_svc_svr_offline };
426
isc_service_query(status, &data->attached, 0, 0, NULL,
427
1, sendbuf, sizeof(respbuf), respbuf);
429
if (status[0] == 1 && status[1] > 0) {
430
isc_print_status(status);
437
static bool start_server( ibmgr_data_t* data)
439
/**************************************
441
* s t a r t _ s e r v e r
443
**************************************
445
* Functional description
446
* start the superserver using guardian process
448
**************************************/
451
/* If we are currently attached and host has not been changed,
452
server on this host is up and running.
454
if (data->attached && !(data->reattach & REA_HOST)) {
455
SRVRMGR_msg_get(MSG_SRVUP, msg);
456
fprintf(OUTFILE, "%s\n", msg);
460
if (data->attached) {
461
detach_service(data);
462
data->reattach |= (REA_HOST | REA_USER | REA_PASSWORD);
465
fb_assert(data->reattach);
467
/* Let's see if server is already running, try to attach to it
469
if (server_is_up(data) == true) {
470
SRVRMGR_msg_get(MSG_SRVUP, msg);
471
fprintf(OUTFILE, "%s\n", msg);
475
/* We failed to attach to service, thus server might not be running
476
You know what? We'll try to start it.
478
TEXT path[MAXPATHLEN];
479
gds__prefix(path, SERVER_GUARDIAN);
481
// CVC: Newer compilers won't accept assigning literal strings to non-const
482
// char pointers, so this code prevents changing argv's type to const TEXT* argv[4]
483
// that may not be accepted by execv().
484
static char option_o[] = "-o";
485
static char option_s[] = "-s";
486
static char option_f[] = "-f";
487
static char option_p[] = "-p";
491
if (data->suboperation == SOP_START_ONCE)
493
else if (data->suboperation == SOP_START_SIGNORE)
499
if (data->pidfile[0]) {
501
argv[3] = data->pidfile;
506
printf("Argument list:\n\"%s\"\n\"%s\"\n", argv[0], argv[1]);
510
#if (defined SOLARIS_MT)
511
/* Accoding Sun's documentation vfork() is not MT-safe
512
while linking with libthreads, fork1 - fork one thread
514
if (!(pid = fork1())) {
515
if (execv(path, argv) == -1) {
516
printf("Could not create child process %s with args %s \n",
524
if (!(pid = vfork())) {
530
/* Wait a little bit to let the server start
533
for (int retry = ATTACH_RETRY; retry; retry--) {
536
/* What we want to do here is to find out if the server has
537
started or not. We do it by trying to attach to the server
538
by calling isc_service_attach (in server_is_up()).
539
But in a local server startup (and this the way it works
540
currently) before calling isc_service_attach, we can check
541
if the child process (ibguard) exited or not. If it did,
542
then the server exited with startup error and there is no
543
need to try to attach to it.
545
int exit_status; // unused after the call below.
546
const pid_t ret_value = waitpid(pid, &exit_status, WNOHANG);
548
/* waitpid() returns guardian process pid if the server has
549
exited (or killed by a signal), -1 if error happened,
550
0 if an exit status of a child process is unavailable (that
551
means in our case that the server is running).
553
#if (defined SOLARIS_MT)
554
// Trying to understand why it died
555
if ((ret_value == pid) && ( WIFEXITED(exit_status)
556
|| WCOREDUMP(exit_status)
557
|| WIFSIGNALED(exit_status)))
559
printf("Guardian process %ld terminated with code %ld\n",
560
pid, WEXITSTATUS(exit_status));
567
if (ret_value == pid) {
569
printf("Guardian process %ld terminated\n", pid);
574
#endif /* SOLARIS_MT */
577
else if (ret_value == -1) {
578
printf("waitpid returned error, errno = %ld\n", errno);
583
printf("Attach retries left: %d\n", retry);
585
if (server_is_up(data) == true) {
586
SRVRMGR_msg_get(MSG_SRVUPOK, msg);
587
fprintf(OUTFILE, "%s\n", msg);
591
SRVRMGR_msg_get(MSG_STARTERR, msg);
592
fprintf(OUTFILE, "%s\n", msg);
597
static bool server_is_up( ibmgr_data_t* data)
599
/**************************************
601
* s e r v e r _ i s _ u p
603
**************************************
605
* Functional description
606
* checks if superserver is running
607
* trying to attach to "anonymous" service.
609
**************************************/
610
ISC_STATUS_ARRAY status;
612
isc_svc_handle svc_handle = 0;
614
/* Obviously we should not be already attached to service
616
fb_assert(!data->attached);
620
/* To find out if we the server is already running we
621
will try to attach to it. We are going to use "anonymous"
622
service in order not to get an error like wrong user/password
624
strcpy(svc_name, data->host);
625
strcat(svc_name, ":anonymous");
626
isc_service_attach(status, 0, svc_name, &svc_handle, 0, "");
628
if (status[0] == 1 && status[1] > 0) {
630
fprintf(OUTFILE, "server_is_up ERROR: %lu\n", status[1]);
632
fb_assert(status[1] != isc_svcnotdef);
634
/* Server can be running but attach could fail for
635
other reasons. For example, attach could return
636
not enough memory error. Let's take care of it.
638
if (status[1] == isc_virmemexh)
643
isc_service_detach(status, &svc_handle);
648
static bool print_pool( ibmgr_data_t* data)
650
/**************************************
652
* p r i n t _ p o o l
654
**************************************
656
* Functional description
657
* Make the server print memory pools
659
**************************************/
661
/* We should be attached to ask for any service
663
fb_assert(data->attached);
666
char* sptr = sendbuf;
667
const USHORT path_length = strlen(data->print_file);
668
*sptr = isc_info_svc_dump_pool_info;
670
add_word(reinterpret_cast<UCHAR*&>(sptr), path_length);
671
strcpy(sptr, data->print_file);
674
ISC_STATUS_ARRAY status;
676
isc_service_query(status, &data->attached, 0, 0, NULL,
677
sptr - sendbuf, sendbuf, sizeof(respbuf), respbuf);
678
if (status[0] == 1 && status[1] > 0) {
679
isc_print_status(status);