2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: JRD Journal Server
|
|
|
|
* MODULE: misc.c
|
2002-02-16 04:54:56 +01:00
|
|
|
* DESCRIPTION:
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
* 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 04:54:56 +01:00
|
|
|
*
|
|
|
|
* 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "M88K" port
|
|
|
|
*
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
#include "firebird.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/ib_stdio.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include "../jrd/time.h"
|
|
|
|
#include "../jrd/common.h"
|
|
|
|
|
|
|
|
#ifdef WIN_NT
|
|
|
|
#include <sys/timeb.h>
|
2002-06-29 19:21:08 +02:00
|
|
|
#include <winsock2.h>
|
2001-05-23 15:26:42 +02:00
|
|
|
#define TEXT SCHAR
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "../jrd/ods.h"
|
2001-07-30 01:43:24 +02:00
|
|
|
#include "../jrd/gds.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/license.h"
|
|
|
|
#include "../journal/journal.h"
|
|
|
|
|
|
|
|
#ifndef INCLUDE_FB_BLK
|
2001-12-24 03:51:06 +01:00
|
|
|
#include "../include/old_fb_blk.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "../jrd/jrn.h"
|
|
|
|
#include "../journal/gjrn_proto.h"
|
|
|
|
#include "../journal/misc_proto.h"
|
|
|
|
#include "../jrd/gds_proto.h"
|
|
|
|
|
|
|
|
#define LETTER(c) (c >= 'A' && c <= 'Z')
|
|
|
|
#define DIGIT(c) (c >= '0' && c <= '9')
|
|
|
|
|
|
|
|
#define DECIMAL_LIMIT (1 << 30) / 5
|
|
|
|
#define TODAY "TODAY"
|
|
|
|
#define NOW "NOW"
|
|
|
|
#define TOMORROW "TOMORROW"
|
|
|
|
#define YESTERDAY "YESTERDAY"
|
|
|
|
|
|
|
|
|
|
|
|
static void now_to_date(struct tm *, SLONG[2]);
|
|
|
|
|
|
|
|
static TEXT *months[] = {
|
|
|
|
"JANUARY",
|
|
|
|
"FEBRUARY",
|
|
|
|
"MARCH",
|
|
|
|
"APRIL",
|
|
|
|
"MAY",
|
|
|
|
"JUNE",
|
|
|
|
"JULY",
|
|
|
|
"AUGUST",
|
|
|
|
"SEPTEMBER",
|
|
|
|
"OCTOBER",
|
|
|
|
"NOVEMBER",
|
|
|
|
"DECEMBER",
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
UCHAR *MISC_alloc_jrnl(size)
|
|
|
|
SLONG size;
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M I S C _ a l l o c _ j r n l
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Allocate block of memory.
|
|
|
|
* Zero it out.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
UCHAR *p, *block;
|
|
|
|
|
|
|
|
if (!(block = (UCHAR *) gds__alloc((SLONG) size))) {
|
|
|
|
GJRN_printf(109, NULL, NULL, NULL, NULL); /* msg 109: malloc failed??? */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = block;
|
|
|
|
do
|
|
|
|
*p++ = 0;
|
|
|
|
while (--size);
|
|
|
|
|
|
|
|
return block;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void MISC_down_case( UCHAR * in, UCHAR * out)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M I S C _ d o w n _ c a s e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Copy a string, down casing as we go.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
UCHAR c;
|
|
|
|
|
|
|
|
while (c = *in++)
|
|
|
|
*out++ = (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c;
|
|
|
|
|
|
|
|
*out = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void MISC_free_jrnl( int *block)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M I S C _ f r e e _ j r n l
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Release an unwanted block.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
gds__free(block);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int MISC_get_line( TEXT * prompt, TEXT * buffer, SSHORT size)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M I S C _ g e t _ l i n e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Eat a command line throwing away extra bytes. Return FALSE
|
|
|
|
* if end of file.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
TEXT *end;
|
|
|
|
SSHORT c;
|
|
|
|
SSHORT count;
|
|
|
|
|
|
|
|
GJRN_output("%s", prompt);
|
|
|
|
end = buffer + size - 1;
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
if (sw_service_gjrn)
|
|
|
|
GJRN_output("\001");
|
|
|
|
fflush(stdout);
|
|
|
|
|
|
|
|
while ((c = getchar()) != '\n') {
|
|
|
|
count++;
|
|
|
|
if (c == EOF) {
|
|
|
|
*buffer = 0;
|
|
|
|
GJRN_output("%s", "\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (buffer < end)
|
|
|
|
*buffer++ = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
*buffer = 0;
|
|
|
|
|
|
|
|
if (!count)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void MISC_get_new_value( SCHAR * string1, SCHAR * buffer, int size)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M I S C _ g e t _ n e w _ v a l u e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SCHAR temp[25];
|
|
|
|
SCHAR buff[MSG_LENGTH];
|
|
|
|
|
|
|
|
GJRN_output("%s is: %s\n", string1, buffer);
|
|
|
|
|
|
|
|
GJRN_get_msg(84, buff, NULL, NULL, NULL);
|
|
|
|
MISC_get_line(buff, temp, sizeof(temp));
|
|
|
|
|
|
|
|
MISC_down_case(temp, temp);
|
|
|
|
|
|
|
|
if (temp[0] != 'y')
|
|
|
|
return;
|
|
|
|
|
|
|
|
GJRN_get_msg(85, buff, NULL, NULL, NULL);
|
|
|
|
MISC_get_line(buff, buffer, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void MISC_get_time( struct timeval *current)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M I S C _ g e t _ t i m e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get the current time of day.
|
|
|
|
*
|
|
|
|
**************************************/
|
2002-08-14 13:14:01 +02:00
|
|
|
#ifdef HAVE_GETTIMEOFDAY
|
|
|
|
#ifdef GETTIMEOFDAY_RETURNS_TIMEZONE
|
|
|
|
(void)gettimeofday(current, (struct timezone *)0);
|
|
|
|
#else
|
|
|
|
(void)gettimeofday(current);
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
struct timeb buffer;
|
|
|
|
|
|
|
|
ftime(&buffer);
|
|
|
|
current->tv_sec = buffer.time;
|
|
|
|
current->tv_usec = (SLONG) buffer.millitm * 1000L;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void MISC_get_wal_info( LTJC * msg, SCHAR * db_name, SCHAR * dir_name)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M I S C _ g e t _ w a l _ i n f o
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* get wal info from message
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SCHAR *p, *q, *b;
|
|
|
|
SSHORT l;
|
|
|
|
|
|
|
|
db_name[0] = 0;
|
|
|
|
dir_name[0] = 0;
|
|
|
|
|
|
|
|
for (p = msg->ltjc_data; p[0] != JRNW_END; p += 2 + p[1]) {
|
|
|
|
switch (*p) {
|
|
|
|
case gds__dpb_wal_backup_dir:
|
|
|
|
b = dir_name;
|
|
|
|
q = &p[2];
|
|
|
|
l = p[1];
|
|
|
|
if (l)
|
|
|
|
do
|
|
|
|
*b++ = *q++;
|
|
|
|
while (--l);
|
|
|
|
*b++ = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case JRNW_DB_NAME:
|
|
|
|
b = db_name;
|
|
|
|
q = &p[2];
|
|
|
|
l = p[1];
|
|
|
|
if (l)
|
|
|
|
do
|
|
|
|
*b++ = *q++;
|
|
|
|
while (--l);
|
|
|
|
*b++ = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void MISC_print_journal_syntax(void)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M I S C _ p r i n t _ j o u r n a l _ s y n t a x
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* print possible options
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
GJRN_print_syntax();
|
|
|
|
|
|
|
|
GJRN_printf(7, NULL, NULL, NULL, NULL); /* msg 7: <utility> : -enable | -disable | -online_dump | -server | -console | -restore */
|
|
|
|
|
|
|
|
/* server options */
|
|
|
|
GJRN_printf(75, NULL, NULL, NULL, NULL); /* msg 75: <server options> */
|
|
|
|
GJRN_printf(8, NULL, NULL, NULL, NULL); /* msg 8: -j <journal directory> */
|
|
|
|
|
|
|
|
/* console options */
|
|
|
|
GJRN_printf(76, NULL, NULL, NULL, NULL); /* msg 76: <console options> */
|
|
|
|
GJRN_printf(8, NULL, NULL, NULL, NULL); /* msg 8: -j <journal directory> */
|
|
|
|
GJRN_printf(77, NULL, NULL, NULL, NULL); /* msg 77: -s <command> */
|
|
|
|
|
|
|
|
/* enable options */
|
|
|
|
GJRN_printf(78, NULL, NULL, NULL, NULL); /* msg 78: <enable options> */
|
|
|
|
GJRN_printf(8, NULL, NULL, NULL, NULL); /* msg 8: -j <journal directory> */
|
|
|
|
GJRN_printf(9, NULL, NULL, NULL, NULL); /* msg 9: -a <archive base name> */
|
|
|
|
|
|
|
|
/* disable options */
|
|
|
|
GJRN_printf(79, NULL, NULL, NULL, NULL); /* msg 79: <disable options> */
|
|
|
|
|
|
|
|
/* restore options */
|
|
|
|
GJRN_printf(80, NULL, NULL, NULL, NULL); /* msg 80: <restore options> */
|
|
|
|
GJRN_printf(8, NULL, NULL, NULL, NULL); /* msg 8: -j <journal directory> */
|
|
|
|
GJRN_printf(11, NULL, NULL, NULL, NULL); /* msg 11: -u <until options> */
|
|
|
|
GJRN_printf(10, NULL, NULL, NULL, NULL); /* msg 10: -i -interactive mode */
|
|
|
|
GJRN_printf(142, NULL, NULL, NULL, NULL); /* msg 142: -m <output message file> */
|
|
|
|
GJRN_printf(196, NULL, NULL, NULL, NULL); /* msg 196: -a\t\t-activate partially recovered database */
|
|
|
|
GJRN_printf(197, NULL, NULL, NULL, NULL); /* msg 197: \t\t-p <database name for partial recovery> */
|
|
|
|
|
|
|
|
/* online dump options */
|
|
|
|
GJRN_printf(81, NULL, NULL, NULL, NULL); /* msg 81: <online dump options> */
|
|
|
|
GJRN_printf(10, NULL, NULL, NULL, NULL); /* msg 10: -i -interactive mode */
|
|
|
|
GJRN_printf(82, NULL, NULL, NULL, NULL); /* msg 82: -f <file name> */
|
|
|
|
GJRN_printf(83, NULL, NULL, NULL, NULL); /* msg 83: -s <file size> */
|
|
|
|
|
|
|
|
GJRN_abort(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int MISC_time_convert( TEXT * string, USHORT length, SLONG date[2])
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* M I S C _ t i m e _ c o n v e r t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Convert an arbitrary string to a date. Return SUCCESS if successful,
|
|
|
|
* otherwise FAILURE.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
TEXT c, *p, temp[15], *t, *end, **month_ptr, *m;
|
|
|
|
USHORT n, month_position, i, components[7];
|
|
|
|
SLONG xclock;
|
|
|
|
struct tm times, times2;
|
|
|
|
|
|
|
|
p = string;
|
|
|
|
end = p + length;
|
|
|
|
month_position = 0;
|
|
|
|
|
|
|
|
xclock = time(0);
|
|
|
|
times2 = *localtime(&xclock);
|
|
|
|
|
|
|
|
for (i = 0; i < 7; i++)
|
|
|
|
components[i] = 0;
|
|
|
|
|
|
|
|
/* Parse components */
|
|
|
|
|
|
|
|
for (i = 0; i < 7; i++) {
|
|
|
|
|
|
|
|
/* Skip leading blanks. If we run out of characters, we're done
|
|
|
|
with parse. */
|
|
|
|
|
|
|
|
while (p < end && (*p == ' ' || *p == '\t'))
|
|
|
|
p++;
|
|
|
|
if (p == end)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Handle digit or character strings */
|
|
|
|
|
|
|
|
c = UPPER(*p);
|
|
|
|
if (DIGIT(c)) {
|
|
|
|
n = 0;
|
|
|
|
while (p < end && DIGIT(*p))
|
|
|
|
n = n * 10 + *p++ - '0';
|
|
|
|
}
|
|
|
|
else if (LETTER(c)) {
|
|
|
|
t = temp;
|
|
|
|
while (p < end && LETTER(c)) {
|
|
|
|
c = UPPER(*p);
|
|
|
|
if (!LETTER(c))
|
|
|
|
break;
|
|
|
|
*t++ = c;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
*t = 0;
|
|
|
|
month_ptr = months;
|
|
|
|
while (TRUE) {
|
|
|
|
if (!*month_ptr) {
|
|
|
|
|
|
|
|
/* it's not a month name, so it's either a magic word or
|
|
|
|
a non-date string. If there are more characters, it's bad */
|
|
|
|
|
|
|
|
while (++p < end)
|
|
|
|
if (*p != ' ' && *p != '\t' && *p != 0)
|
|
|
|
return FAILURE;
|
|
|
|
if (strcmp(temp, NOW) == 0) {
|
|
|
|
now_to_date(×2, date);
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
times2.tm_hour = times2.tm_min = times2.tm_sec = 0;
|
|
|
|
gds__encode_date(×2, date);
|
|
|
|
if (strcmp(temp, TODAY) == 0)
|
|
|
|
return SUCCESS;
|
|
|
|
if (strcmp(temp, TOMORROW) == 0) {
|
|
|
|
++date[0];
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
if (strcmp(temp, YESTERDAY) == 0) {
|
|
|
|
--date[0];
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
for (t = temp, m = *month_ptr++; *t && *t == *m; t++, m++);
|
|
|
|
if (!*t)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
n = month_ptr - months;
|
|
|
|
month_position = i;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return FAILURE;
|
|
|
|
components[i] = n;
|
|
|
|
while (p < end && (*p == ' ' || *p == '\t'))
|
|
|
|
p++;
|
|
|
|
if (*p == '/' || *p == '-' || *p == ',' || *p == ':') {
|
|
|
|
p++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (*p == '.') {
|
|
|
|
if (!month_position && i < 2)
|
|
|
|
month_position = 1;
|
|
|
|
p++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Slide things into day, month, year form */
|
|
|
|
|
|
|
|
if (!components[0] && !components[1] && !components[2]) {
|
|
|
|
date[0] = date[1] = 0;
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (month_position) {
|
|
|
|
times.tm_mon = components[1];
|
|
|
|
times.tm_mday = components[0];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
times.tm_mon = components[0];
|
|
|
|
times.tm_mday = components[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle defaulting of year */
|
|
|
|
|
|
|
|
if ((times.tm_year = components[2]) == 0)
|
|
|
|
times.tm_year = times2.tm_year + 1900;
|
|
|
|
else if (times.tm_year < 100) {
|
|
|
|
if (times.tm_year < (times2.tm_year - 50) % 100)
|
|
|
|
times.tm_year += 2000;
|
|
|
|
else
|
|
|
|
times.tm_year += 1900;
|
|
|
|
}
|
|
|
|
|
|
|
|
times.tm_year -= 1900;
|
|
|
|
times.tm_mon -= 1;
|
|
|
|
times.tm_hour = components[3];
|
|
|
|
times.tm_min = components[4];
|
|
|
|
times.tm_sec = components[5];
|
|
|
|
|
|
|
|
/* convert day/month/year to Julian and validate result */
|
|
|
|
|
|
|
|
gds__encode_date(×, date);
|
|
|
|
gds__decode_date(date, ×2);
|
|
|
|
|
|
|
|
if (times.tm_year != times2.tm_year ||
|
|
|
|
times.tm_mon != times2.tm_mon || times.tm_mday != times2.tm_mday)
|
|
|
|
return FAILURE;
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void now_to_date( struct tm *xtime, SLONG date[2])
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* n o w _ t o _ d a t e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Convert "now" (or best guess) to
|
|
|
|
* a date attempting to get millisecond
|
|
|
|
* precision. This unfortunately means
|
|
|
|
* that we use one routine for VAX, and
|
|
|
|
* another for Unix.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
gds__encode_date(xtime, date);
|
|
|
|
}
|