Add bandb code.
This commit is contained in:
parent
31478ab689
commit
832ed81ad9
6 changed files with 2235 additions and 0 deletions
92
bandb/Makefile.in
Normal file
92
bandb/Makefile.in
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
#
|
||||||
|
# Makefile.in for bandb/src
|
||||||
|
#
|
||||||
|
# $Id: Makefile.in 1285 2006-05-05 15:03:53Z nenolod $
|
||||||
|
#
|
||||||
|
|
||||||
|
CC = @CC@
|
||||||
|
INSTALL = @INSTALL@
|
||||||
|
INSTALL_BIN = @INSTALL_PROGRAM@
|
||||||
|
INSTALL_DATA = @INSTALL_DATA@
|
||||||
|
INSTALL_SUID = @INSTALL_PROGRAM@ -o root -m 4755
|
||||||
|
RM = @RM@
|
||||||
|
LEX = @LEX@
|
||||||
|
LEXLIB = @LEXLIB@
|
||||||
|
CFLAGS = @IRC_CFLAGS@ -DIRCD_PREFIX=\"@prefix@\"
|
||||||
|
LDFLAGS = @LDFLAGS@
|
||||||
|
MKDEP = @MKDEP@ -DIRCD_PREFIX=\"@prefix@\"
|
||||||
|
MV = @MV@
|
||||||
|
RM = @RM@
|
||||||
|
prefix = @prefix@
|
||||||
|
exec_prefix = @exec_prefix@
|
||||||
|
bindir = @bindir@
|
||||||
|
libdir = @libdir@
|
||||||
|
libexecdir = @libexecdir@
|
||||||
|
confdir = @confdir@
|
||||||
|
localstatedir = @localstatedir@
|
||||||
|
|
||||||
|
ZIP_LIB = @ZLIB_LD@
|
||||||
|
|
||||||
|
IRCDLIBS = @MODULES_LIBS@ -L../libratbox/src/.libs -lratbox @LIBS@ $(SSL_LIBS) $(ZIP_LIB)
|
||||||
|
|
||||||
|
INCLUDES = -I. -I../include -I../libratbox/include $(SSL_INCLUDES)
|
||||||
|
CPPFLAGS = ${INCLUDES} @CPPFLAGS@
|
||||||
|
|
||||||
|
PROGS = bandb bantool
|
||||||
|
|
||||||
|
BANDB_SOURCES = \
|
||||||
|
bandb.c \
|
||||||
|
rsdb_sprintf.c \
|
||||||
|
rsdb_sqlite3.c
|
||||||
|
|
||||||
|
BANDB_OBJECTS = ${BANDB_SOURCES:.c=.o}
|
||||||
|
|
||||||
|
BANTOOL_SOURCES = \
|
||||||
|
bantool.c \
|
||||||
|
rsdb_sprintf.c \
|
||||||
|
rsdb_sqlite3.c
|
||||||
|
|
||||||
|
BANTOOL_OBJECTS = ${BANDB_SOURCES:.c=.o}
|
||||||
|
|
||||||
|
all: bandb bantool
|
||||||
|
|
||||||
|
build: all
|
||||||
|
|
||||||
|
bandb: ${BANDB_OBJECTS}
|
||||||
|
${CC} ${CFLAGS} ${LDFLAGS} -o $@ ${OBJECTS} ${IRCDLIBS}
|
||||||
|
|
||||||
|
bantool: ${BANTOOL_OBJECTS}
|
||||||
|
${CC} ${CFLAGS} ${LDFLAGS} -o $@ ${OBJECTS} ${IRCDLIBS}
|
||||||
|
|
||||||
|
install: build
|
||||||
|
@echo "ircd: installing bandb ($(PROGS))"
|
||||||
|
@for i in $(PROGS); do \
|
||||||
|
if test -f $(DESTDIR)$(bindir)/$$i; then \
|
||||||
|
$(MV) $(DESTDIR)$(bindir)/$$i $(DESTDIR)$(bindir)/$$i.old; \
|
||||||
|
fi; \
|
||||||
|
$(INSTALL_BIN) $$i $(DESTDIR)$(bindir); \
|
||||||
|
done
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
${CC} ${CPPFLAGS} ${CFLAGS} -c $<
|
||||||
|
|
||||||
|
.PHONY: depend clean distclean
|
||||||
|
depend:
|
||||||
|
@${MKDEP} ${CPPFLAGS} ${SOURCES} > .depend.tmp
|
||||||
|
@sed -e '/^# DO NOT DELETE THIS LINE/,$$d' <Makefile >Makefile.depend
|
||||||
|
@echo '# DO NOT DELETE THIS LINE!!!' >>Makefile.depend
|
||||||
|
@echo '# make depend needs it.' >>Makefile.depend
|
||||||
|
@cat .depend.tmp >>Makefile.depend
|
||||||
|
@mv Makefile.depend Makefile
|
||||||
|
@rm -f .depend.tmp
|
||||||
|
|
||||||
|
clean:
|
||||||
|
${RM} -f *.o *~ *.core core bandb
|
||||||
|
|
||||||
|
lint:
|
||||||
|
lint -aacgprxhH $(CPPFLAGS) -DIRCD_PREFIX=\"@prefix@\" $(SOURCES) >>../lint.out
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
${RM} -f Makefile
|
||||||
|
|
||||||
|
# End of Makefile
|
309
bandb/bandb.c
Normal file
309
bandb/bandb.c
Normal file
|
@ -0,0 +1,309 @@
|
||||||
|
/* bandb/bandb.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006 Lee Hardy <lee -at- leeh.co.uk>
|
||||||
|
* Copyright (C) 2006-2008 ircd-ratbox development team
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* 1.Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2.Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3.The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $Id: bandb.c 26094 2008-09-19 15:33:46Z androsyn $
|
||||||
|
*/
|
||||||
|
#include "setup.h"
|
||||||
|
#include <ratbox_lib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "rsdb.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define MAXPARA 10
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
BANDB_KLINE,
|
||||||
|
BANDB_DLINE,
|
||||||
|
BANDB_XLINE,
|
||||||
|
BANDB_RESV,
|
||||||
|
LAST_BANDB_TYPE
|
||||||
|
} bandb_type;
|
||||||
|
|
||||||
|
static char bandb_letter[LAST_BANDB_TYPE] = {
|
||||||
|
'K', 'D', 'X', 'R'
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *bandb_table[LAST_BANDB_TYPE] = {
|
||||||
|
"kline", "dline", "xline", "resv"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static rb_helper *bandb_helper;
|
||||||
|
|
||||||
|
static void check_schema(void);
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_ban(bandb_type type, char *parv[], int parc)
|
||||||
|
{
|
||||||
|
const char *mask1 = NULL;
|
||||||
|
const char *mask2 = NULL;
|
||||||
|
const char *oper = NULL;
|
||||||
|
const char *curtime = NULL;
|
||||||
|
const char *reason = NULL;
|
||||||
|
const char *perm = NULL;
|
||||||
|
int para = 1;
|
||||||
|
|
||||||
|
if(type == BANDB_KLINE)
|
||||||
|
{
|
||||||
|
if(parc != 7)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if(parc != 6)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mask1 = parv[para++];
|
||||||
|
|
||||||
|
if(type == BANDB_KLINE)
|
||||||
|
mask2 = parv[para++];
|
||||||
|
|
||||||
|
oper = parv[para++];
|
||||||
|
curtime = parv[para++];
|
||||||
|
perm = parv[para++];
|
||||||
|
reason = parv[para++];
|
||||||
|
|
||||||
|
rsdb_exec(NULL,
|
||||||
|
"INSERT INTO %s (mask1, mask2, oper, time, perm, reason) VALUES('%Q', '%Q', '%Q', %s, %s, '%Q')",
|
||||||
|
bandb_table[type], mask1, mask2 ? mask2 : "", oper, curtime, perm, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_unban(bandb_type type, char *parv[], int parc)
|
||||||
|
{
|
||||||
|
const char *mask1 = NULL;
|
||||||
|
const char *mask2 = NULL;
|
||||||
|
|
||||||
|
if(type == BANDB_KLINE)
|
||||||
|
{
|
||||||
|
if(parc != 3)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if(parc != 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mask1 = parv[1];
|
||||||
|
|
||||||
|
if(type == BANDB_KLINE)
|
||||||
|
mask2 = parv[2];
|
||||||
|
|
||||||
|
rsdb_exec(NULL, "DELETE FROM %s WHERE mask1='%Q' AND mask2='%Q'",
|
||||||
|
bandb_table[type], mask1, mask2 ? mask2 : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
list_bans(void)
|
||||||
|
{
|
||||||
|
static char buf[512];
|
||||||
|
struct rsdb_table table;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
/* schedule a clear of anything already pending */
|
||||||
|
rb_helper_write_queue(bandb_helper, "C");
|
||||||
|
|
||||||
|
for(i = 0; i < LAST_BANDB_TYPE; i++)
|
||||||
|
{
|
||||||
|
rsdb_exec_fetch(&table, "SELECT mask1,mask2,oper,reason FROM %s WHERE 1",
|
||||||
|
bandb_table[i]);
|
||||||
|
|
||||||
|
for(j = 0; j < table.row_count; j++)
|
||||||
|
{
|
||||||
|
if(i == BANDB_KLINE)
|
||||||
|
rb_snprintf(buf, sizeof(buf), "%c %s %s %s :%s",
|
||||||
|
bandb_letter[i], table.row[j][0],
|
||||||
|
table.row[j][1], table.row[j][2], table.row[j][3]);
|
||||||
|
else
|
||||||
|
rb_snprintf(buf, sizeof(buf), "%c %s %s :%s",
|
||||||
|
bandb_letter[i], table.row[j][0],
|
||||||
|
table.row[j][2], table.row[j][3]);
|
||||||
|
|
||||||
|
rb_helper_write_queue(bandb_helper, "%s", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
rsdb_exec_fetch_end(&table);
|
||||||
|
}
|
||||||
|
|
||||||
|
rb_helper_write(bandb_helper, "F");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_request(rb_helper *helper)
|
||||||
|
{
|
||||||
|
static char *parv[MAXPARA + 1];
|
||||||
|
static char readbuf[READBUF_SIZE];
|
||||||
|
int parc;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
|
||||||
|
while((len = rb_helper_read(helper, readbuf, sizeof(readbuf))) > 0)
|
||||||
|
{
|
||||||
|
parc = rb_string_to_array(readbuf, parv, MAXPARA);
|
||||||
|
|
||||||
|
if(parc < 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (parv[0][0])
|
||||||
|
{
|
||||||
|
case 'K':
|
||||||
|
parse_ban(BANDB_KLINE, parv, parc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'D':
|
||||||
|
parse_ban(BANDB_DLINE, parv, parc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'X':
|
||||||
|
parse_ban(BANDB_XLINE, parv, parc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'R':
|
||||||
|
parse_ban(BANDB_RESV, parv, parc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'k':
|
||||||
|
parse_unban(BANDB_KLINE, parv, parc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
parse_unban(BANDB_DLINE, parv, parc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'x':
|
||||||
|
parse_unban(BANDB_XLINE, parv, parc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
parse_unban(BANDB_RESV, parv, parc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'L':
|
||||||
|
list_bans();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
error_cb(rb_helper *helper)
|
||||||
|
{
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef WINDOWS
|
||||||
|
static void
|
||||||
|
dummy_handler(int sig)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
setup_signals()
|
||||||
|
{
|
||||||
|
#ifndef WINDOWS
|
||||||
|
struct sigaction act;
|
||||||
|
|
||||||
|
act.sa_flags = 0;
|
||||||
|
act.sa_handler = SIG_IGN;
|
||||||
|
sigemptyset(&act.sa_mask);
|
||||||
|
sigaddset(&act.sa_mask, SIGPIPE);
|
||||||
|
sigaddset(&act.sa_mask, SIGALRM);
|
||||||
|
#ifdef SIGTRAP
|
||||||
|
sigaddset(&act.sa_mask, SIGTRAP);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SIGWINCH
|
||||||
|
sigaddset(&act.sa_mask, SIGWINCH);
|
||||||
|
sigaction(SIGWINCH, &act, 0);
|
||||||
|
#endif
|
||||||
|
sigaction(SIGPIPE, &act, 0);
|
||||||
|
#ifdef SIGTRAP
|
||||||
|
sigaction(SIGTRAP, &act, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
act.sa_handler = dummy_handler;
|
||||||
|
sigaction(SIGALRM, &act, 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
db_error_cb(const char *errstr)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
rb_snprintf(buf, sizeof(buf), "! :%s", errstr);
|
||||||
|
rb_helper_write(bandb_helper, buf);
|
||||||
|
rb_sleep(2 << 30, 0);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
setup_signals();
|
||||||
|
bandb_helper = rb_helper_child(parse_request, error_cb, NULL, NULL, NULL, 256, 256, 256, 256); /* XXX fix me */
|
||||||
|
if(bandb_helper == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"This is ircd-ratbox bandb. You aren't supposed to run me directly. Maybe you want bantool?\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
"However I will print my Id tag $Id: bandb.c 26094 2008-09-19 15:33:46Z androsyn $\n");
|
||||||
|
fprintf(stderr, "Have a nice day\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
rsdb_init(db_error_cb);
|
||||||
|
check_schema();
|
||||||
|
rb_helper_loop(bandb_helper, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_schema(void)
|
||||||
|
{
|
||||||
|
struct rsdb_table table;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < LAST_BANDB_TYPE; i++)
|
||||||
|
{
|
||||||
|
rsdb_exec_fetch(&table,
|
||||||
|
"SELECT name FROM sqlite_master WHERE type='table' AND name='%s'",
|
||||||
|
bandb_table[i]);
|
||||||
|
|
||||||
|
rsdb_exec_fetch_end(&table);
|
||||||
|
|
||||||
|
if(!table.row_count)
|
||||||
|
rsdb_exec(NULL,
|
||||||
|
"CREATE TABLE %s (mask1 TEXT, mask2 TEXT, oper TEXT, time INTEGER, perm INTEGER, reason TEXT)",
|
||||||
|
bandb_table[i]);
|
||||||
|
}
|
||||||
|
}
|
899
bandb/bantool.c
Normal file
899
bandb/bantool.c
Normal file
|
@ -0,0 +1,899 @@
|
||||||
|
/**
|
||||||
|
* ircd-ratbox: A slightly useful ircd.
|
||||||
|
* bantool.c: The ircd-ratbox database managment tool.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
|
||||||
|
* Copyright (C) 1996-2002 Hybrid Development Team
|
||||||
|
* Copyright (C) 2002-2008 ircd-ratbox development team
|
||||||
|
* Copyright (C) 2008 Daniel J Reidy <dubkat@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
* USA
|
||||||
|
*
|
||||||
|
* $Id: bantool.c 26164 2008-10-26 19:52:43Z androsyn $
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* The following server admins have either contributed various configs to test against,
|
||||||
|
* or helped with debugging and feature requests. Many thanks to them.
|
||||||
|
* stevoo / efnet.port80.se
|
||||||
|
* AndroSyn / irc2.choopa.net, irc.igs.ca
|
||||||
|
* Salvation / irc.blessed.net
|
||||||
|
* JamesOff / efnet.demon.co.uk
|
||||||
|
*
|
||||||
|
* Thanks to AndroSyn for challenging me to learn C on the fly :)
|
||||||
|
* BUGS Direct Question, Bug Reports, and Feature Requests to #ratbox on EFnet.
|
||||||
|
* BUGS Complaints >/dev/null
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _XOPEN_SOURCE
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "stdinc.h"
|
||||||
|
#include "rsdb.h"
|
||||||
|
|
||||||
|
#define EmptyString(x) ((x == NULL) || (*(x) == '\0'))
|
||||||
|
#define CheckEmpty(x) EmptyString(x) ? "" : x
|
||||||
|
|
||||||
|
#define BT_VERSION "0.4.1"
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
BANDB_KLINE,
|
||||||
|
BANDB_KLINE_PERM,
|
||||||
|
BANDB_DLINE,
|
||||||
|
BANDB_DLINE_PERM,
|
||||||
|
BANDB_XLINE,
|
||||||
|
BANDB_XLINE_PERM,
|
||||||
|
BANDB_RESV,
|
||||||
|
BANDB_RESV_PERM,
|
||||||
|
LAST_BANDB_TYPE
|
||||||
|
} bandb_type;
|
||||||
|
|
||||||
|
|
||||||
|
static char bandb_letter[LAST_BANDB_TYPE] = {
|
||||||
|
'K', 'K', 'D', 'D', 'X', 'X', 'R', 'R'
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *bandb_table[LAST_BANDB_TYPE] = {
|
||||||
|
"kline", "kline", "dline", "dline", "xline", "xline", "resv", "resv"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *bandb_suffix[LAST_BANDB_TYPE] = {
|
||||||
|
"", ".perm",
|
||||||
|
"", ".perm",
|
||||||
|
"", ".perm",
|
||||||
|
"", ".perm"
|
||||||
|
};
|
||||||
|
|
||||||
|
static char me[PATH_MAX];
|
||||||
|
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
/* report counters */
|
||||||
|
struct counter
|
||||||
|
{
|
||||||
|
unsigned int klines;
|
||||||
|
unsigned int dlines;
|
||||||
|
unsigned int xlines;
|
||||||
|
unsigned int resvs;
|
||||||
|
unsigned int error;
|
||||||
|
} count = {0, 0, 0, 0, 0};
|
||||||
|
|
||||||
|
/* flags set by command line options */
|
||||||
|
struct flags
|
||||||
|
{
|
||||||
|
int none;
|
||||||
|
int export;
|
||||||
|
int import;
|
||||||
|
int verify;
|
||||||
|
int vacuum;
|
||||||
|
int pretend;
|
||||||
|
int verbose;
|
||||||
|
int wipe;
|
||||||
|
int dupes_ok;
|
||||||
|
} flag = {YES, NO, NO, NO, NO, NO, NO, NO, NO};
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
|
static int table_has_rows(const char *table);
|
||||||
|
static int table_exists(const char *table);
|
||||||
|
|
||||||
|
static const char *clean_gecos_field(const char *gecos);
|
||||||
|
static char *bt_smalldate(const char *string);
|
||||||
|
static char *getfield(char *newline);
|
||||||
|
static char *strip_quotes(const char *string);
|
||||||
|
static char *mangle_reason(const char *string);
|
||||||
|
static char *escape_quotes(const char *string);
|
||||||
|
|
||||||
|
static void db_error_cb(const char *errstr);
|
||||||
|
static void db_reclaim_slack(void);
|
||||||
|
static void export_config(const char *conf, int id);
|
||||||
|
static void import_config(const char *conf, int id);
|
||||||
|
static void check_schema(void);
|
||||||
|
static void print_help(int i_exit);
|
||||||
|
static void wipe_schema(void);
|
||||||
|
static void drop_dupes(const char *user, const char *host, const char *t);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* swing your pants
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char etc[PATH_MAX];
|
||||||
|
char conf[PATH_MAX];
|
||||||
|
int opt;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
rb_strlcpy(me, argv[0], sizeof(me));
|
||||||
|
|
||||||
|
while((opt = getopt(argc, argv, "hieuspvwd")) != -1)
|
||||||
|
{
|
||||||
|
switch (opt)
|
||||||
|
{
|
||||||
|
case 'h':
|
||||||
|
print_help(EXIT_SUCCESS);
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
flag.none = NO;
|
||||||
|
flag.import = YES;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
flag.none = NO;
|
||||||
|
flag.export = YES;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
flag.none = NO;
|
||||||
|
flag.verify = YES;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
flag.none = NO;
|
||||||
|
flag.vacuum = YES;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
flag.pretend = YES;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
flag.verbose = YES;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
flag.wipe = YES;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
flag.dupes_ok = YES;
|
||||||
|
break;
|
||||||
|
default: /* '?' */
|
||||||
|
print_help(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* they should really read the help. */
|
||||||
|
if(flag.none)
|
||||||
|
print_help(EXIT_FAILURE);
|
||||||
|
|
||||||
|
if((flag.import && flag.export) || (flag.export && flag.wipe)
|
||||||
|
|| (flag.verify && flag.pretend) || (flag.export && flag.pretend))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "* Error: Conflicting flags.\n");
|
||||||
|
if(flag.export && flag.pretend)
|
||||||
|
fprintf(stderr, "* There is nothing to 'pretend' when exporting.\n");
|
||||||
|
|
||||||
|
fprintf(stderr, "* For an explination of commands, run: %s -h\n", me);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(argv[optind] != NULL)
|
||||||
|
rb_strlcpy(etc, argv[optind], sizeof(etc));
|
||||||
|
else
|
||||||
|
rb_strlcpy(etc, ETCPATH, sizeof(ETCPATH));
|
||||||
|
|
||||||
|
fprintf(stdout,
|
||||||
|
"* ircd-ratbox bantool v.%s ($Id: bantool.c 26164 2008-10-26 19:52:43Z androsyn $)\n",
|
||||||
|
BT_VERSION);
|
||||||
|
|
||||||
|
if(flag.pretend == NO)
|
||||||
|
{
|
||||||
|
if(rsdb_init(db_error_cb) == -1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "* Error: Unable to open database\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
check_schema();
|
||||||
|
|
||||||
|
if(flag.vacuum)
|
||||||
|
db_reclaim_slack();
|
||||||
|
|
||||||
|
if(flag.import && flag.wipe)
|
||||||
|
{
|
||||||
|
flag.dupes_ok = YES; /* dont check for dupes if we are wiping the db clean */
|
||||||
|
for(i = 0; i < 3; i++)
|
||||||
|
fprintf(stdout,
|
||||||
|
"* WARNING: YOU ARE ABOUT TO WIPE YOUR DATABASE!\n");
|
||||||
|
|
||||||
|
fprintf(stdout, "* Press ^C to abort! ");
|
||||||
|
fflush(stdout);
|
||||||
|
rb_sleep(10, 0);
|
||||||
|
fprintf(stdout, "Carrying on...\n");
|
||||||
|
wipe_schema();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(flag.verbose && flag.dupes_ok == YES)
|
||||||
|
fprintf(stdout, "* Allowing duplicate bans...\n");
|
||||||
|
|
||||||
|
/* checking for our files to import or export */
|
||||||
|
for(i = 0; i < LAST_BANDB_TYPE; i++)
|
||||||
|
{
|
||||||
|
rb_snprintf(conf, sizeof(conf), "%s/%s.conf%s",
|
||||||
|
etc, bandb_table[i], bandb_suffix[i]);
|
||||||
|
|
||||||
|
if(flag.import && flag.pretend == NO)
|
||||||
|
rsdb_transaction(RSDB_TRANS_START);
|
||||||
|
|
||||||
|
if(flag.import)
|
||||||
|
import_config(conf, i);
|
||||||
|
|
||||||
|
if(flag.export)
|
||||||
|
export_config(conf, i);
|
||||||
|
|
||||||
|
if(flag.import && flag.pretend == NO)
|
||||||
|
rsdb_transaction(RSDB_TRANS_END);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(flag.import)
|
||||||
|
{
|
||||||
|
if(count.error && flag.verbose)
|
||||||
|
fprintf(stderr, "* I was unable to locate %i config files to import.\n",
|
||||||
|
count.error);
|
||||||
|
|
||||||
|
fprintf(stdout, "* Import Stats: Klines: %i, Dlines: %i, Xlines: %i, Resvs: %i \n",
|
||||||
|
count.klines, count.dlines, count.xlines, count.resvs);
|
||||||
|
|
||||||
|
fprintf(stdout,
|
||||||
|
"*\n* If your IRC server is currently running, newly imported bans \n* will not take effect until you issue the command: /quote rehash bans\n");
|
||||||
|
|
||||||
|
if(flag.pretend)
|
||||||
|
fprintf(stdout,
|
||||||
|
"* Pretend mode engaged. Nothing was actually entered into the database.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* export the database to old-style flat files
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
export_config(const char *conf, int id)
|
||||||
|
{
|
||||||
|
struct rsdb_table table;
|
||||||
|
static char sql[BUFSIZE * 2];
|
||||||
|
static char buf[512];
|
||||||
|
FILE *fd = NULL;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
/* for sanity sake */
|
||||||
|
const int mask1 = 0;
|
||||||
|
const int mask2 = 1;
|
||||||
|
const int reason = 2;
|
||||||
|
const int oper = 3;
|
||||||
|
const int ts = 4;
|
||||||
|
/* const int perm = 5; */
|
||||||
|
|
||||||
|
if(!table_has_rows(bandb_table[id]))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(strstr(conf, ".perm") != 0)
|
||||||
|
rb_snprintf(sql, sizeof(sql),
|
||||||
|
"SELECT DISTINCT mask1,mask2,reason,oper,time FROM %s WHERE perm = 1 ORDER BY time",
|
||||||
|
bandb_table[id]);
|
||||||
|
else
|
||||||
|
rb_snprintf(sql, sizeof(sql),
|
||||||
|
"SELECT DISTINCT mask1,mask2,reason,oper,time FROM %s WHERE perm = 0 ORDER BY time",
|
||||||
|
bandb_table[id]);
|
||||||
|
|
||||||
|
rsdb_exec_fetch(&table, sql);
|
||||||
|
if(table.row_count <= 0)
|
||||||
|
{
|
||||||
|
rsdb_exec_fetch_end(&table);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(flag.verbose)
|
||||||
|
fprintf(stdout, "* checking for %s: ", conf); /* debug */
|
||||||
|
|
||||||
|
/* open config for reading, or skip to the next */
|
||||||
|
if(!(fd = fopen(conf, "w")))
|
||||||
|
{
|
||||||
|
if(flag.verbose)
|
||||||
|
fprintf(stdout, "\tmissing.\n");
|
||||||
|
count.error++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(j = 0; j < table.row_count; j++)
|
||||||
|
{
|
||||||
|
switch (id)
|
||||||
|
{
|
||||||
|
case BANDB_DLINE:
|
||||||
|
case BANDB_DLINE_PERM:
|
||||||
|
rb_snprintf(buf, sizeof(buf),
|
||||||
|
"\"%s\",\"%s\",\"\",\"%s\",\"%s\",%s\n",
|
||||||
|
table.row[j][mask1],
|
||||||
|
mangle_reason(table.row[j][reason]),
|
||||||
|
bt_smalldate(table.row[j][ts]),
|
||||||
|
table.row[j][oper], table.row[j][ts]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BANDB_XLINE:
|
||||||
|
case BANDB_XLINE_PERM:
|
||||||
|
rb_snprintf(buf, sizeof(buf),
|
||||||
|
"\"%s\",\"0\",\"%s\",\"%s\",%s\n",
|
||||||
|
escape_quotes(table.row[j][mask1]),
|
||||||
|
mangle_reason(table.row[j][reason]),
|
||||||
|
table.row[j][oper], table.row[j][ts]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BANDB_RESV:
|
||||||
|
case BANDB_RESV_PERM:
|
||||||
|
rb_snprintf(buf, sizeof(buf),
|
||||||
|
"\"%s\",\"%s\",\"%s\",%s\n",
|
||||||
|
table.row[j][mask1],
|
||||||
|
mangle_reason(table.row[j][reason]),
|
||||||
|
table.row[j][oper], table.row[j][ts]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
default: /* Klines */
|
||||||
|
rb_snprintf(buf, sizeof(buf),
|
||||||
|
"\"%s\",\"%s\",\"%s\",\"\",\"%s\",\"%s\",%s\n",
|
||||||
|
table.row[j][mask1], table.row[j][mask2],
|
||||||
|
mangle_reason(table.row[j][reason]),
|
||||||
|
bt_smalldate(table.row[j][ts]), table.row[j][oper],
|
||||||
|
table.row[j][ts]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fd, "%s", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
rsdb_exec_fetch_end(&table);
|
||||||
|
if(flag.verbose)
|
||||||
|
fprintf(stdout, "\twritten.\n");
|
||||||
|
fclose(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* attempt to condense the individual conf functions into one
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
import_config(const char *conf, int id)
|
||||||
|
{
|
||||||
|
FILE *fd;
|
||||||
|
|
||||||
|
char line[BUFSIZE];
|
||||||
|
char *p;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
char f_perm = 0;
|
||||||
|
char *f_mask1 = NULL;
|
||||||
|
char *f_mask2 = NULL;
|
||||||
|
char *f_oper = NULL;
|
||||||
|
char *f_time = NULL;
|
||||||
|
char *f_reason = NULL;
|
||||||
|
char *f_oreason = NULL;
|
||||||
|
char newreason[REASONLEN];
|
||||||
|
|
||||||
|
if(flag.verbose)
|
||||||
|
fprintf(stdout, "* checking for %s: ", conf); /* debug */
|
||||||
|
|
||||||
|
/* open config for reading, or skip to the next */
|
||||||
|
if(!(fd = fopen(conf, "r")))
|
||||||
|
{
|
||||||
|
if(flag.verbose)
|
||||||
|
fprintf(stdout, "%*s", strlen(bandb_suffix[id]) > 0 ? 10 : 15,
|
||||||
|
"missing.\n");
|
||||||
|
count.error++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strstr(conf, ".perm") != 0)
|
||||||
|
f_perm = 1;
|
||||||
|
|
||||||
|
|
||||||
|
/* xline
|
||||||
|
* "SYSTEM","0","banned","stevoo!stevoo@efnet.port80.se{stevoo}",1111080437
|
||||||
|
* resv
|
||||||
|
* "OseK","banned nickname","stevoo!stevoo@efnet.port80.se{stevoo}",1111031619
|
||||||
|
* dline
|
||||||
|
* "194.158.192.0/19","laptop scammers","","2005/3/17 05.33","stevoo!stevoo@efnet.port80.se{stevoo}",1111033988
|
||||||
|
*/
|
||||||
|
while(fgets(line, sizeof(line), fd))
|
||||||
|
{
|
||||||
|
if((p = strpbrk(line, "\r\n")) != NULL)
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
|
if((*line == '\0') || (*line == '#'))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* mask1 */
|
||||||
|
f_mask1 = getfield(line);
|
||||||
|
|
||||||
|
if(EmptyString(f_mask1))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* mask2 */
|
||||||
|
switch (id)
|
||||||
|
{
|
||||||
|
case BANDB_XLINE:
|
||||||
|
case BANDB_XLINE_PERM:
|
||||||
|
f_mask1 = escape_quotes(clean_gecos_field(f_mask1));
|
||||||
|
getfield(NULL); /* empty field */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BANDB_RESV:
|
||||||
|
case BANDB_RESV_PERM:
|
||||||
|
case BANDB_DLINE:
|
||||||
|
case BANDB_DLINE_PERM:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
f_mask2 = getfield(NULL);
|
||||||
|
if(EmptyString(f_mask2))
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reason */
|
||||||
|
f_reason = getfield(NULL);
|
||||||
|
if(EmptyString(f_reason))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* oper comment */
|
||||||
|
switch (id)
|
||||||
|
{
|
||||||
|
case BANDB_KLINE:
|
||||||
|
case BANDB_KLINE_PERM:
|
||||||
|
case BANDB_DLINE:
|
||||||
|
case BANDB_DLINE_PERM:
|
||||||
|
f_oreason = getfield(NULL);
|
||||||
|
getfield(NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
f_oper = getfield(NULL);
|
||||||
|
f_time = strip_quotes(f_oper + strlen(f_oper) + 2);
|
||||||
|
|
||||||
|
/* meh */
|
||||||
|
if(id == BANDB_KLINE || id == BANDB_KLINE_PERM)
|
||||||
|
{
|
||||||
|
if(strstr(f_mask1, "!") != NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"* SKIPPING INVALID KLINE %s@%s set by %s\n",
|
||||||
|
f_mask1, f_mask2, f_oper);
|
||||||
|
fprintf(stderr, " You may wish to re-apply it correctly.\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* append operreason_field to reason_field */
|
||||||
|
if(!EmptyString(f_oreason))
|
||||||
|
rb_snprintf(newreason, sizeof(newreason), "%s | %s", f_reason, f_oreason);
|
||||||
|
else
|
||||||
|
rb_snprintf(newreason, sizeof(newreason), "%s", f_reason);
|
||||||
|
|
||||||
|
if(flag.pretend == NO)
|
||||||
|
{
|
||||||
|
if(flag.dupes_ok == NO)
|
||||||
|
drop_dupes(f_mask1, f_mask2, bandb_table[id]);
|
||||||
|
|
||||||
|
rsdb_exec(NULL,
|
||||||
|
"INSERT INTO %s (mask1, mask2, oper, time, perm, reason) VALUES('%Q','%Q','%Q','%Q','%d','%Q')",
|
||||||
|
bandb_table[id], f_mask1, f_mask2, f_oper, f_time, f_perm,
|
||||||
|
newreason);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(flag.pretend && flag.verbose)
|
||||||
|
fprintf(stdout,
|
||||||
|
"%s: perm(%d) mask1(%s) mask2(%s) oper(%s) reason(%s) time(%s)\n",
|
||||||
|
bandb_table[id], f_perm, f_mask1, f_mask2, f_oper, newreason,
|
||||||
|
f_time);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (bandb_letter[id])
|
||||||
|
{
|
||||||
|
case 'K':
|
||||||
|
count.klines += i;
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
count.dlines += i;
|
||||||
|
break;
|
||||||
|
case 'X':
|
||||||
|
count.xlines += i;
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
count.resvs += i;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(flag.verbose)
|
||||||
|
fprintf(stdout, "%*s\n", strlen(bandb_suffix[id]) > 0 ? 10 : 15, "imported.");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getfield
|
||||||
|
*
|
||||||
|
* inputs - input buffer
|
||||||
|
* output - next field
|
||||||
|
* side effects - field breakup for ircd.conf file.
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
getfield(char *newline)
|
||||||
|
{
|
||||||
|
static char *line = NULL;
|
||||||
|
char *end, *field;
|
||||||
|
|
||||||
|
if(newline != NULL)
|
||||||
|
line = newline;
|
||||||
|
|
||||||
|
if(line == NULL)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
field = line;
|
||||||
|
|
||||||
|
/* XXX make this skip to first " if present */
|
||||||
|
if(*field == '"')
|
||||||
|
field++;
|
||||||
|
else
|
||||||
|
return (NULL); /* mal-formed field */
|
||||||
|
|
||||||
|
end = strchr(line, ',');
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
/* no trailing , - last field */
|
||||||
|
if(end == NULL)
|
||||||
|
{
|
||||||
|
end = line + strlen(line);
|
||||||
|
line = NULL;
|
||||||
|
|
||||||
|
if(*end == '"')
|
||||||
|
{
|
||||||
|
*end = '\0';
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* look for a ", to mark the end of a field.. */
|
||||||
|
if(*(end - 1) == '"')
|
||||||
|
{
|
||||||
|
line = end + 1;
|
||||||
|
end--;
|
||||||
|
*end = '\0';
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* search for the next ',' */
|
||||||
|
end++;
|
||||||
|
end = strchr(end, ',');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* strip away "quotes" from around strings
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
strip_quotes(const char *string)
|
||||||
|
{
|
||||||
|
static char buf[14]; /* int(11) + 2 + \0 */
|
||||||
|
char *str = buf;
|
||||||
|
|
||||||
|
if(string == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while(*string)
|
||||||
|
{
|
||||||
|
if(*string != '"')
|
||||||
|
{
|
||||||
|
*str++ = *string;
|
||||||
|
}
|
||||||
|
string++;
|
||||||
|
}
|
||||||
|
*str = '\0';
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* escape quotes in a string
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
escape_quotes(const char *string)
|
||||||
|
{
|
||||||
|
static char buf[BUFSIZE * 2];
|
||||||
|
char *str = buf;
|
||||||
|
|
||||||
|
if(string == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while(*string)
|
||||||
|
{
|
||||||
|
if(*string == '"')
|
||||||
|
{
|
||||||
|
*str++ = '\\';
|
||||||
|
*str++ = '"';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*str++ = *string;
|
||||||
|
}
|
||||||
|
string++;
|
||||||
|
}
|
||||||
|
*str = '\0';
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static char *
|
||||||
|
mangle_reason(const char *string)
|
||||||
|
{
|
||||||
|
static char buf[BUFSIZE * 2];
|
||||||
|
char *str = buf;
|
||||||
|
|
||||||
|
if(string == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while(*string)
|
||||||
|
{
|
||||||
|
switch (*string)
|
||||||
|
{
|
||||||
|
case '"':
|
||||||
|
*str = '\'';
|
||||||
|
break;
|
||||||
|
case ':':
|
||||||
|
*str = ' ';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*str = *string;
|
||||||
|
}
|
||||||
|
string++;
|
||||||
|
str++;
|
||||||
|
|
||||||
|
}
|
||||||
|
*str = '\0';
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* change spaces to \s in gecos field
|
||||||
|
*/
|
||||||
|
static const char *
|
||||||
|
clean_gecos_field(const char *gecos)
|
||||||
|
{
|
||||||
|
static char buf[BUFSIZE * 2];
|
||||||
|
char *str = buf;
|
||||||
|
|
||||||
|
if(gecos == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while(*gecos)
|
||||||
|
{
|
||||||
|
if(*gecos == ' ')
|
||||||
|
{
|
||||||
|
*str++ = '\\';
|
||||||
|
*str++ = 's';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*str++ = *gecos;
|
||||||
|
gecos++;
|
||||||
|
}
|
||||||
|
*str = '\0';
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* verify the database integrity, and if necessary create apropriate tables
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
check_schema(void)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
char type[8]; /* longest string is 'INTEGER\0' */
|
||||||
|
|
||||||
|
if(flag.verify || flag.verbose)
|
||||||
|
fprintf(stdout, "* Verifying database.\n");
|
||||||
|
|
||||||
|
const char *columns[] = {
|
||||||
|
"perm",
|
||||||
|
"mask1",
|
||||||
|
"mask2",
|
||||||
|
"oper",
|
||||||
|
"time",
|
||||||
|
"reason",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
for(i = 0; i < LAST_BANDB_TYPE; i++)
|
||||||
|
{
|
||||||
|
if(!table_exists(bandb_table[i]))
|
||||||
|
{
|
||||||
|
rsdb_exec(NULL,
|
||||||
|
"CREATE TABLE %s (mask1 TEXT, mask2 TEXT, oper TEXT, time INTEGER, perm INTEGER, reason TEXT)",
|
||||||
|
bandb_table[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* i can't think of any better way to do this, other then attempt to
|
||||||
|
* force the creation of column that may, or may not already exist. --dubkat
|
||||||
|
*/
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(j = 0; columns[j] != NULL; j++)
|
||||||
|
{
|
||||||
|
if(!strcmp(columns[j], "time") && !strcmp(columns[j], "perm"))
|
||||||
|
rb_strlcpy(type, "INTEGER", sizeof(type));
|
||||||
|
else
|
||||||
|
rb_strlcpy(type, "TEXT", sizeof(type));
|
||||||
|
|
||||||
|
/* attempt to add a column with extreme prejudice, errors are ignored */
|
||||||
|
rsdb_exec(NULL, "ALTER TABLE %s ADD COLUMN %s %s", bandb_table[i],
|
||||||
|
columns[j], type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i++; /* skip over .perm */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
db_reclaim_slack(void)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "* Reclaiming free space.\n");
|
||||||
|
rsdb_exec(NULL, "VACUUM");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check that appropriate tables exist.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
table_exists(const char *dbtab)
|
||||||
|
{
|
||||||
|
struct rsdb_table table;
|
||||||
|
rsdb_exec_fetch(&table, "SELECT name FROM sqlite_master WHERE type='table' AND name='%s'",
|
||||||
|
dbtab);
|
||||||
|
rsdb_exec_fetch_end(&table);
|
||||||
|
return table.row_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check that there are actual entries in a table
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
table_has_rows(const char *dbtab)
|
||||||
|
{
|
||||||
|
struct rsdb_table table;
|
||||||
|
rsdb_exec_fetch(&table, "SELECT * FROM %s", dbtab);
|
||||||
|
rsdb_exec_fetch_end(&table);
|
||||||
|
return table.row_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* completly wipes out an existing ban.db of all entries.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
wipe_schema(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
rsdb_transaction(RSDB_TRANS_START);
|
||||||
|
for(i = 0; i < LAST_BANDB_TYPE; i++)
|
||||||
|
{
|
||||||
|
rsdb_exec(NULL, "DROP TABLE %s", bandb_table[i]);
|
||||||
|
i++; /* double increment to skip over .perm */
|
||||||
|
}
|
||||||
|
rsdb_transaction(RSDB_TRANS_END);
|
||||||
|
|
||||||
|
check_schema();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remove pre-existing duplicate bans from the database.
|
||||||
|
* we favor the new, imported ban over the one in the database
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
drop_dupes(const char *user, const char *host, const char *t)
|
||||||
|
{
|
||||||
|
rsdb_exec(NULL, "DELETE FROM %s WHERE mask1='%Q' AND mask2='%Q'", t, user, host);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
db_error_cb(const char *errstr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert unix timestamp to human readable (small) date
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
bt_smalldate(const char *string)
|
||||||
|
{
|
||||||
|
static char buf[MAX_DATE_STRING];
|
||||||
|
struct tm *lt;
|
||||||
|
time_t t;
|
||||||
|
t = strtol(string, NULL, 10);
|
||||||
|
lt = gmtime(&t);
|
||||||
|
if(lt == NULL)
|
||||||
|
return NULL;
|
||||||
|
rb_snprintf(buf, sizeof(buf), "%d/%d/%d %02d.%02d",
|
||||||
|
lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* you are here ->.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
print_help(int i_exit)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "bantool v.%s - the ircd-ratbox database tool.\n", BT_VERSION);
|
||||||
|
fprintf(stderr, "Copyright (C) 2008 Daniel J Reidy <dubkat@gmail.com>\n");
|
||||||
|
fprintf(stderr, "$Id: bantool.c 26164 2008-10-26 19:52:43Z androsyn $\n\n");
|
||||||
|
fprintf(stderr, "This program is distributed in the hope that it will be useful,\n"
|
||||||
|
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||||
|
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
|
||||||
|
"GNU General Public License for more details.\n\n");
|
||||||
|
|
||||||
|
fprintf(stderr, "Usage: %s <-i|-e> [-p] [-v] [-h] [-d] [-w] [path]\n", me);
|
||||||
|
fprintf(stderr, " -h : Display some slightly useful help.\n");
|
||||||
|
fprintf(stderr, " -i : Actually import configs into your database.\n");
|
||||||
|
fprintf(stderr, " -e : Export your database to old-style flat files.\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
" This is suitable for redistrubuting your banlists, or creating backups.\n");
|
||||||
|
fprintf(stderr, " -s : Reclaim empty slack space the database may be taking up.\n");
|
||||||
|
fprintf(stderr, " -u : Update the database tables to support any new features.\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
" This is automaticlly done if you are importing or exporting\n");
|
||||||
|
fprintf(stderr, " but should be run whenever you upgrade the ircd.\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
" -p : pretend, checks for the configs, and parses them, then tells you some data...\n");
|
||||||
|
fprintf(stderr, " but does not touch your database.\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
" -v : Be verbose... and it *is* very verbose! (intended for debugging)\n");
|
||||||
|
fprintf(stderr, " -d : Enable checking for redunant entries.\n");
|
||||||
|
fprintf(stderr, " -w : Completly wipe your database clean. May be used with -i \n");
|
||||||
|
fprintf(stderr,
|
||||||
|
" path : An optional directory containing old ratbox configs for import, or export.\n");
|
||||||
|
fprintf(stderr, " If not specified, it looks in PREFIX/etc.\n");
|
||||||
|
exit(i_exit);
|
||||||
|
}
|
42
bandb/rsdb.h
Normal file
42
bandb/rsdb.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/* $Id: rsdb.h 26164 2008-10-26 19:52:43Z androsyn $ */
|
||||||
|
#ifndef INCLUDED_rsdb_h
|
||||||
|
#define INCLUDED_rsdb_h
|
||||||
|
|
||||||
|
/* error handler callback */
|
||||||
|
typedef void rsdb_error_cb(const char *);
|
||||||
|
|
||||||
|
typedef int (*rsdb_callback) (int, const char **);
|
||||||
|
|
||||||
|
typedef enum rsdb_transtype
|
||||||
|
{
|
||||||
|
RSDB_TRANS_START,
|
||||||
|
RSDB_TRANS_END
|
||||||
|
}
|
||||||
|
rsdb_transtype;
|
||||||
|
|
||||||
|
struct rsdb_table
|
||||||
|
{
|
||||||
|
char ***row;
|
||||||
|
int row_count;
|
||||||
|
int col_count;
|
||||||
|
void *arg;
|
||||||
|
};
|
||||||
|
|
||||||
|
int rsdb_init(rsdb_error_cb *);
|
||||||
|
void rsdb_shutdown(void);
|
||||||
|
|
||||||
|
const char *rsdb_quote(const char *src);
|
||||||
|
|
||||||
|
void rsdb_exec(rsdb_callback cb, const char *format, ...);
|
||||||
|
|
||||||
|
void rsdb_exec_fetch(struct rsdb_table *data, const char *format, ...);
|
||||||
|
void rsdb_exec_fetch_end(struct rsdb_table *data);
|
||||||
|
|
||||||
|
void rsdb_transaction(rsdb_transtype type);
|
||||||
|
/* rsdb_snprintf.c */
|
||||||
|
|
||||||
|
int rs_vsnprintf(char *dest, const size_t bytes, const char *format, va_list args);
|
||||||
|
int rs_snprintf(char *dest, const size_t bytes, const char *format, ...);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
628
bandb/rsdb_snprintf.c
Normal file
628
bandb/rsdb_snprintf.c
Normal file
|
@ -0,0 +1,628 @@
|
||||||
|
/*
|
||||||
|
* libString, Copyright (C) 1999 Patrick Alken
|
||||||
|
* This library comes with absolutely NO WARRANTY
|
||||||
|
*
|
||||||
|
* Should you choose to use and/or modify this source code, please
|
||||||
|
* do so under the terms of the GNU General Public License under which
|
||||||
|
* this library is distributed.
|
||||||
|
*
|
||||||
|
* $Id: rsdb_snprintf.c 26094 2008-09-19 15:33:46Z androsyn $
|
||||||
|
*/
|
||||||
|
#include "stdinc.h"
|
||||||
|
#include "rsdb.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This table is arranged in chronological order from 0-999,
|
||||||
|
* however the numbers are written backwards, so the number 100
|
||||||
|
* is expressed in this table as "001".
|
||||||
|
* It's purpose is to ensure fast conversions from integers to
|
||||||
|
* ASCII strings. When an integer variable is encountered, a
|
||||||
|
* simple hash algorithm is used to determine where to look
|
||||||
|
* in this array for the corresponding string.
|
||||||
|
* This outperforms continually dividing by 10 and using the
|
||||||
|
* digit obtained as a character, because we can now divide by
|
||||||
|
* 1000 and use the remainder directly, thus cutting down on
|
||||||
|
* the number of costly divisions needed. For an integer's worst
|
||||||
|
* case, 2 divisions are needed because it can only go up to
|
||||||
|
* 32767, so after 2 divisions by 1000, and some algebra, we will
|
||||||
|
* be left with 327 which we can get from this table. This is much
|
||||||
|
* better than the 5 divisions by 10 that we would need if we did
|
||||||
|
* it the conventional way. Of course, if we made this table go
|
||||||
|
* from 0-9999, only 1 division would be needed.
|
||||||
|
* Longs and unsigned ints of course, are another matter :-).
|
||||||
|
*
|
||||||
|
* Patrick Alken <wnder@underworld.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set this to the number of indices (numbers) in our table
|
||||||
|
*/
|
||||||
|
#define TABLE_MAX 1000
|
||||||
|
|
||||||
|
static const char *IntTable[] = {
|
||||||
|
"000", "100", "200", "300", "400",
|
||||||
|
"500", "600", "700", "800", "900",
|
||||||
|
"010", "110", "210", "310", "410",
|
||||||
|
"510", "610", "710", "810", "910",
|
||||||
|
"020", "120", "220", "320", "420",
|
||||||
|
"520", "620", "720", "820", "920",
|
||||||
|
"030", "130", "230", "330", "430",
|
||||||
|
"530", "630", "730", "830", "930",
|
||||||
|
"040", "140", "240", "340", "440",
|
||||||
|
"540", "640", "740", "840", "940",
|
||||||
|
"050", "150", "250", "350", "450",
|
||||||
|
"550", "650", "750", "850", "950",
|
||||||
|
"060", "160", "260", "360", "460",
|
||||||
|
"560", "660", "760", "860", "960",
|
||||||
|
"070", "170", "270", "370", "470",
|
||||||
|
"570", "670", "770", "870", "970",
|
||||||
|
"080", "180", "280", "380", "480",
|
||||||
|
"580", "680", "780", "880", "980",
|
||||||
|
"090", "190", "290", "390", "490",
|
||||||
|
"590", "690", "790", "890", "990",
|
||||||
|
"001", "101", "201", "301", "401",
|
||||||
|
"501", "601", "701", "801", "901",
|
||||||
|
"011", "111", "211", "311", "411",
|
||||||
|
"511", "611", "711", "811", "911",
|
||||||
|
"021", "121", "221", "321", "421",
|
||||||
|
"521", "621", "721", "821", "921",
|
||||||
|
"031", "131", "231", "331", "431",
|
||||||
|
"531", "631", "731", "831", "931",
|
||||||
|
"041", "141", "241", "341", "441",
|
||||||
|
"541", "641", "741", "841", "941",
|
||||||
|
"051", "151", "251", "351", "451",
|
||||||
|
"551", "651", "751", "851", "951",
|
||||||
|
"061", "161", "261", "361", "461",
|
||||||
|
"561", "661", "761", "861", "961",
|
||||||
|
"071", "171", "271", "371", "471",
|
||||||
|
"571", "671", "771", "871", "971",
|
||||||
|
"081", "181", "281", "381", "481",
|
||||||
|
"581", "681", "781", "881", "981",
|
||||||
|
"091", "191", "291", "391", "491",
|
||||||
|
"591", "691", "791", "891", "991",
|
||||||
|
"002", "102", "202", "302", "402",
|
||||||
|
"502", "602", "702", "802", "902",
|
||||||
|
"012", "112", "212", "312", "412",
|
||||||
|
"512", "612", "712", "812", "912",
|
||||||
|
"022", "122", "222", "322", "422",
|
||||||
|
"522", "622", "722", "822", "922",
|
||||||
|
"032", "132", "232", "332", "432",
|
||||||
|
"532", "632", "732", "832", "932",
|
||||||
|
"042", "142", "242", "342", "442",
|
||||||
|
"542", "642", "742", "842", "942",
|
||||||
|
"052", "152", "252", "352", "452",
|
||||||
|
"552", "652", "752", "852", "952",
|
||||||
|
"062", "162", "262", "362", "462",
|
||||||
|
"562", "662", "762", "862", "962",
|
||||||
|
"072", "172", "272", "372", "472",
|
||||||
|
"572", "672", "772", "872", "972",
|
||||||
|
"082", "182", "282", "382", "482",
|
||||||
|
"582", "682", "782", "882", "982",
|
||||||
|
"092", "192", "292", "392", "492",
|
||||||
|
"592", "692", "792", "892", "992",
|
||||||
|
"003", "103", "203", "303", "403",
|
||||||
|
"503", "603", "703", "803", "903",
|
||||||
|
"013", "113", "213", "313", "413",
|
||||||
|
"513", "613", "713", "813", "913",
|
||||||
|
"023", "123", "223", "323", "423",
|
||||||
|
"523", "623", "723", "823", "923",
|
||||||
|
"033", "133", "233", "333", "433",
|
||||||
|
"533", "633", "733", "833", "933",
|
||||||
|
"043", "143", "243", "343", "443",
|
||||||
|
"543", "643", "743", "843", "943",
|
||||||
|
"053", "153", "253", "353", "453",
|
||||||
|
"553", "653", "753", "853", "953",
|
||||||
|
"063", "163", "263", "363", "463",
|
||||||
|
"563", "663", "763", "863", "963",
|
||||||
|
"073", "173", "273", "373", "473",
|
||||||
|
"573", "673", "773", "873", "973",
|
||||||
|
"083", "183", "283", "383", "483",
|
||||||
|
"583", "683", "783", "883", "983",
|
||||||
|
"093", "193", "293", "393", "493",
|
||||||
|
"593", "693", "793", "893", "993",
|
||||||
|
"004", "104", "204", "304", "404",
|
||||||
|
"504", "604", "704", "804", "904",
|
||||||
|
"014", "114", "214", "314", "414",
|
||||||
|
"514", "614", "714", "814", "914",
|
||||||
|
"024", "124", "224", "324", "424",
|
||||||
|
"524", "624", "724", "824", "924",
|
||||||
|
"034", "134", "234", "334", "434",
|
||||||
|
"534", "634", "734", "834", "934",
|
||||||
|
"044", "144", "244", "344", "444",
|
||||||
|
"544", "644", "744", "844", "944",
|
||||||
|
"054", "154", "254", "354", "454",
|
||||||
|
"554", "654", "754", "854", "954",
|
||||||
|
"064", "164", "264", "364", "464",
|
||||||
|
"564", "664", "764", "864", "964",
|
||||||
|
"074", "174", "274", "374", "474",
|
||||||
|
"574", "674", "774", "874", "974",
|
||||||
|
"084", "184", "284", "384", "484",
|
||||||
|
"584", "684", "784", "884", "984",
|
||||||
|
"094", "194", "294", "394", "494",
|
||||||
|
"594", "694", "794", "894", "994",
|
||||||
|
"005", "105", "205", "305", "405",
|
||||||
|
"505", "605", "705", "805", "905",
|
||||||
|
"015", "115", "215", "315", "415",
|
||||||
|
"515", "615", "715", "815", "915",
|
||||||
|
"025", "125", "225", "325", "425",
|
||||||
|
"525", "625", "725", "825", "925",
|
||||||
|
"035", "135", "235", "335", "435",
|
||||||
|
"535", "635", "735", "835", "935",
|
||||||
|
"045", "145", "245", "345", "445",
|
||||||
|
"545", "645", "745", "845", "945",
|
||||||
|
"055", "155", "255", "355", "455",
|
||||||
|
"555", "655", "755", "855", "955",
|
||||||
|
"065", "165", "265", "365", "465",
|
||||||
|
"565", "665", "765", "865", "965",
|
||||||
|
"075", "175", "275", "375", "475",
|
||||||
|
"575", "675", "775", "875", "975",
|
||||||
|
"085", "185", "285", "385", "485",
|
||||||
|
"585", "685", "785", "885", "985",
|
||||||
|
"095", "195", "295", "395", "495",
|
||||||
|
"595", "695", "795", "895", "995",
|
||||||
|
"006", "106", "206", "306", "406",
|
||||||
|
"506", "606", "706", "806", "906",
|
||||||
|
"016", "116", "216", "316", "416",
|
||||||
|
"516", "616", "716", "816", "916",
|
||||||
|
"026", "126", "226", "326", "426",
|
||||||
|
"526", "626", "726", "826", "926",
|
||||||
|
"036", "136", "236", "336", "436",
|
||||||
|
"536", "636", "736", "836", "936",
|
||||||
|
"046", "146", "246", "346", "446",
|
||||||
|
"546", "646", "746", "846", "946",
|
||||||
|
"056", "156", "256", "356", "456",
|
||||||
|
"556", "656", "756", "856", "956",
|
||||||
|
"066", "166", "266", "366", "466",
|
||||||
|
"566", "666", "766", "866", "966",
|
||||||
|
"076", "176", "276", "376", "476",
|
||||||
|
"576", "676", "776", "876", "976",
|
||||||
|
"086", "186", "286", "386", "486",
|
||||||
|
"586", "686", "786", "886", "986",
|
||||||
|
"096", "196", "296", "396", "496",
|
||||||
|
"596", "696", "796", "896", "996",
|
||||||
|
"007", "107", "207", "307", "407",
|
||||||
|
"507", "607", "707", "807", "907",
|
||||||
|
"017", "117", "217", "317", "417",
|
||||||
|
"517", "617", "717", "817", "917",
|
||||||
|
"027", "127", "227", "327", "427",
|
||||||
|
"527", "627", "727", "827", "927",
|
||||||
|
"037", "137", "237", "337", "437",
|
||||||
|
"537", "637", "737", "837", "937",
|
||||||
|
"047", "147", "247", "347", "447",
|
||||||
|
"547", "647", "747", "847", "947",
|
||||||
|
"057", "157", "257", "357", "457",
|
||||||
|
"557", "657", "757", "857", "957",
|
||||||
|
"067", "167", "267", "367", "467",
|
||||||
|
"567", "667", "767", "867", "967",
|
||||||
|
"077", "177", "277", "377", "477",
|
||||||
|
"577", "677", "777", "877", "977",
|
||||||
|
"087", "187", "287", "387", "487",
|
||||||
|
"587", "687", "787", "887", "987",
|
||||||
|
"097", "197", "297", "397", "497",
|
||||||
|
"597", "697", "797", "897", "997",
|
||||||
|
"008", "108", "208", "308", "408",
|
||||||
|
"508", "608", "708", "808", "908",
|
||||||
|
"018", "118", "218", "318", "418",
|
||||||
|
"518", "618", "718", "818", "918",
|
||||||
|
"028", "128", "228", "328", "428",
|
||||||
|
"528", "628", "728", "828", "928",
|
||||||
|
"038", "138", "238", "338", "438",
|
||||||
|
"538", "638", "738", "838", "938",
|
||||||
|
"048", "148", "248", "348", "448",
|
||||||
|
"548", "648", "748", "848", "948",
|
||||||
|
"058", "158", "258", "358", "458",
|
||||||
|
"558", "658", "758", "858", "958",
|
||||||
|
"068", "168", "268", "368", "468",
|
||||||
|
"568", "668", "768", "868", "968",
|
||||||
|
"078", "178", "278", "378", "478",
|
||||||
|
"578", "678", "778", "878", "978",
|
||||||
|
"088", "188", "288", "388", "488",
|
||||||
|
"588", "688", "788", "888", "988",
|
||||||
|
"098", "198", "298", "398", "498",
|
||||||
|
"598", "698", "798", "898", "998",
|
||||||
|
"009", "109", "209", "309", "409",
|
||||||
|
"509", "609", "709", "809", "909",
|
||||||
|
"019", "119", "219", "319", "419",
|
||||||
|
"519", "619", "719", "819", "919",
|
||||||
|
"029", "129", "229", "329", "429",
|
||||||
|
"529", "629", "729", "829", "929",
|
||||||
|
"039", "139", "239", "339", "439",
|
||||||
|
"539", "639", "739", "839", "939",
|
||||||
|
"049", "149", "249", "349", "449",
|
||||||
|
"549", "649", "749", "849", "949",
|
||||||
|
"059", "159", "259", "359", "459",
|
||||||
|
"559", "659", "759", "859", "959",
|
||||||
|
"069", "169", "269", "369", "469",
|
||||||
|
"569", "669", "769", "869", "969",
|
||||||
|
"079", "179", "279", "379", "479",
|
||||||
|
"579", "679", "779", "879", "979",
|
||||||
|
"089", "189", "289", "389", "489",
|
||||||
|
"589", "689", "789", "889", "989",
|
||||||
|
"099", "199", "299", "399", "499",
|
||||||
|
"599", "699", "799", "899", "999"
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since we calculate the right-most digits for %d %u etc first,
|
||||||
|
* we need a temporary buffer to store them in until we get
|
||||||
|
* to the left-most digits
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define TEMPBUF_MAX 20
|
||||||
|
|
||||||
|
static char TempBuffer[TEMPBUF_MAX];
|
||||||
|
|
||||||
|
/*
|
||||||
|
vSnprintf()
|
||||||
|
Backend to Snprintf() - performs the construction of 'dest'
|
||||||
|
using the string 'format' and the given arguments. Also makes sure
|
||||||
|
not more than 'bytes' characters are copied to 'dest'
|
||||||
|
|
||||||
|
We always allow room for a terminating \0 character, so at most,
|
||||||
|
bytes - 1 characters will be written to dest.
|
||||||
|
|
||||||
|
Return: Number of characters written, NOT including the terminating
|
||||||
|
\0 character which is *always* placed at the end of the string
|
||||||
|
|
||||||
|
NOTE: This function handles the following flags only:
|
||||||
|
%s %d %c %u %ld %lu
|
||||||
|
In addition, this function performs *NO* precision, padding,
|
||||||
|
or width formatting. If it receives an unknown % character,
|
||||||
|
it will call vsprintf() to complete the remainder of the
|
||||||
|
string.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
rs_vsnprintf(char *dest, const size_t bytes, const char *format, va_list args)
|
||||||
|
{
|
||||||
|
char ch;
|
||||||
|
int written = 0; /* bytes written so far */
|
||||||
|
int maxbytes = bytes - 1;
|
||||||
|
|
||||||
|
while((ch = *format++) && (written < maxbytes))
|
||||||
|
{
|
||||||
|
if(ch == '%')
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Advance past the %
|
||||||
|
*/
|
||||||
|
ch = *format++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Put the most common cases first - %s %d etc
|
||||||
|
*/
|
||||||
|
|
||||||
|
if(ch == 's')
|
||||||
|
{
|
||||||
|
const char *str = va_arg(args, const char *);
|
||||||
|
|
||||||
|
while((*dest = *str))
|
||||||
|
{
|
||||||
|
++dest;
|
||||||
|
++str;
|
||||||
|
|
||||||
|
if(++written >= maxbytes)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ch == 'd')
|
||||||
|
{
|
||||||
|
int num = va_arg(args, int);
|
||||||
|
int quotient;
|
||||||
|
const char *str;
|
||||||
|
char *digitptr = TempBuffer;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We have to special-case "0" unfortunately
|
||||||
|
*/
|
||||||
|
if(num == 0)
|
||||||
|
{
|
||||||
|
*dest++ = '0';
|
||||||
|
++written;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(num < 0)
|
||||||
|
{
|
||||||
|
*dest++ = '-';
|
||||||
|
if(++written >= maxbytes)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
num = -num;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
quotient = num / TABLE_MAX;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We'll start with the right-most digits of 'num'.
|
||||||
|
* Dividing by TABLE_MAX cuts off all but the X
|
||||||
|
* right-most digits, where X is such that:
|
||||||
|
*
|
||||||
|
* 10^X = TABLE_MAX
|
||||||
|
*
|
||||||
|
* For example, if num = 1200, and TABLE_MAX = 1000,
|
||||||
|
* quotient will be 1. Multiplying this by 1000 and
|
||||||
|
* subtracting from 1200 gives: 1200 - (1 * 1000) = 200.
|
||||||
|
* We then go right to slot 200 in our array and behold!
|
||||||
|
* The string "002" (200 backwards) is conveniently
|
||||||
|
* waiting for us. Then repeat the process with the
|
||||||
|
* digits left.
|
||||||
|
*
|
||||||
|
* The reason we need to have the integers written
|
||||||
|
* backwards, is because we don't know how many digits
|
||||||
|
* there are. If we want to express the number 12130
|
||||||
|
* for example, our first pass would leave us with 130,
|
||||||
|
* whose slot in the array yields "031", which we
|
||||||
|
* plug into our TempBuffer[]. The next pass gives us
|
||||||
|
* 12, whose slot yields "21" which we append to
|
||||||
|
* TempBuffer[], leaving us with "03121". This is the
|
||||||
|
* exact number we want, only backwards, so it is
|
||||||
|
* a simple matter to reverse the string. If we used
|
||||||
|
* straightfoward numbers, we would have a TempBuffer
|
||||||
|
* looking like this: "13012" which would be a nightmare
|
||||||
|
* to deal with.
|
||||||
|
*/
|
||||||
|
|
||||||
|
str = IntTable[num - (quotient * TABLE_MAX)];
|
||||||
|
|
||||||
|
while((*digitptr = *str))
|
||||||
|
{
|
||||||
|
++digitptr;
|
||||||
|
++str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while((num = quotient) != 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the last quotient was a 1 or 2 digit number, there
|
||||||
|
* will be one or more leading zeroes in TempBuffer[] -
|
||||||
|
* get rid of them.
|
||||||
|
*/
|
||||||
|
while(*(digitptr - 1) == '0')
|
||||||
|
--digitptr;
|
||||||
|
|
||||||
|
while(digitptr != TempBuffer)
|
||||||
|
{
|
||||||
|
*dest++ = *--digitptr;
|
||||||
|
if(++written >= maxbytes)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
} /* if (ch == 'd') */
|
||||||
|
|
||||||
|
if(ch == 'c')
|
||||||
|
{
|
||||||
|
*dest++ = va_arg(args, int);
|
||||||
|
|
||||||
|
++written;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
} /* if (ch == 'c') */
|
||||||
|
|
||||||
|
if(ch == 'u')
|
||||||
|
{
|
||||||
|
unsigned int num = va_arg(args, unsigned int);
|
||||||
|
unsigned int quotient;
|
||||||
|
const char *str;
|
||||||
|
char *digitptr = TempBuffer;
|
||||||
|
|
||||||
|
if(num == 0)
|
||||||
|
{
|
||||||
|
*dest++ = '0';
|
||||||
|
++written;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
quotient = num / TABLE_MAX;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Very similar to case 'd'
|
||||||
|
*/
|
||||||
|
|
||||||
|
str = IntTable[num - (quotient * TABLE_MAX)];
|
||||||
|
|
||||||
|
while((*digitptr = *str))
|
||||||
|
{
|
||||||
|
++digitptr;
|
||||||
|
++str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while((num = quotient) != 0);
|
||||||
|
|
||||||
|
while(*(digitptr - 1) == '0')
|
||||||
|
--digitptr;
|
||||||
|
|
||||||
|
while(digitptr != TempBuffer)
|
||||||
|
{
|
||||||
|
*dest++ = *--digitptr;
|
||||||
|
if(++written >= maxbytes)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
} /* if (ch == 'u') */
|
||||||
|
|
||||||
|
if(ch == 'Q')
|
||||||
|
{
|
||||||
|
const char *arg = va_arg(args, const char *);
|
||||||
|
|
||||||
|
if(arg == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const char *str = rsdb_quote(arg);
|
||||||
|
|
||||||
|
while((*dest = *str))
|
||||||
|
{
|
||||||
|
++dest;
|
||||||
|
++str;
|
||||||
|
|
||||||
|
if(++written >= maxbytes)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ch == 'l')
|
||||||
|
{
|
||||||
|
if(*format == 'u')
|
||||||
|
{
|
||||||
|
unsigned long num = va_arg(args, unsigned long);
|
||||||
|
unsigned long quotient;
|
||||||
|
const char *str;
|
||||||
|
char *digitptr = TempBuffer;
|
||||||
|
|
||||||
|
++format;
|
||||||
|
|
||||||
|
if(num == 0)
|
||||||
|
{
|
||||||
|
*dest++ = '0';
|
||||||
|
++written;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
quotient = num / TABLE_MAX;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Very similar to case 'u'
|
||||||
|
*/
|
||||||
|
|
||||||
|
str = IntTable[num - (quotient * TABLE_MAX)];
|
||||||
|
|
||||||
|
while((*digitptr = *str))
|
||||||
|
{
|
||||||
|
++digitptr;
|
||||||
|
++str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while((num = quotient) != 0);
|
||||||
|
|
||||||
|
while(*(digitptr - 1) == '0')
|
||||||
|
--digitptr;
|
||||||
|
|
||||||
|
while(digitptr != TempBuffer)
|
||||||
|
{
|
||||||
|
*dest++ = *--digitptr;
|
||||||
|
if(++written >= maxbytes)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* if (*format == 'u') */ if(*format == 'd')
|
||||||
|
{
|
||||||
|
long num = va_arg(args, long);
|
||||||
|
long quotient;
|
||||||
|
const char *str;
|
||||||
|
char *digitptr = TempBuffer;
|
||||||
|
|
||||||
|
++format;
|
||||||
|
|
||||||
|
if(num == 0)
|
||||||
|
{
|
||||||
|
*dest++ = '0';
|
||||||
|
++written;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(num < 0)
|
||||||
|
{
|
||||||
|
*dest++ = '-';
|
||||||
|
if(++written >= maxbytes)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
num = -num;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
quotient = num / TABLE_MAX;
|
||||||
|
|
||||||
|
str = IntTable[num - (quotient * TABLE_MAX)];
|
||||||
|
|
||||||
|
while((*digitptr = *str))
|
||||||
|
{
|
||||||
|
++digitptr;
|
||||||
|
++str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while((num = quotient) != 0);
|
||||||
|
|
||||||
|
while(*(digitptr - 1) == '0')
|
||||||
|
--digitptr;
|
||||||
|
|
||||||
|
while(digitptr != TempBuffer)
|
||||||
|
{
|
||||||
|
*dest++ = *--digitptr;
|
||||||
|
if(++written >= maxbytes)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else /* if (*format == 'd') */
|
||||||
|
{
|
||||||
|
/* XXX error */
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} /* if (ch == 'l') */
|
||||||
|
|
||||||
|
if(ch != '%')
|
||||||
|
{
|
||||||
|
/* XXX error */
|
||||||
|
exit(1);
|
||||||
|
} /* if (ch != '%') */
|
||||||
|
} /* if (ch == '%') */
|
||||||
|
|
||||||
|
*dest++ = ch;
|
||||||
|
++written;
|
||||||
|
} /* while ((ch = *format++) && (written < maxbytes)) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Terminate the destination buffer with a \0
|
||||||
|
*/
|
||||||
|
*dest = '\0';
|
||||||
|
|
||||||
|
return (written);
|
||||||
|
} /* vSnprintf() */
|
||||||
|
|
||||||
|
/*
|
||||||
|
rs_snprintf()
|
||||||
|
Optimized version of snprintf().
|
||||||
|
|
||||||
|
Inputs: dest - destination string
|
||||||
|
bytes - number of bytes to copy
|
||||||
|
format - formatted string
|
||||||
|
args - args to 'format'
|
||||||
|
|
||||||
|
Return: number of characters copied, NOT including the terminating
|
||||||
|
NULL which is always placed at the end of the string
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
rs_snprintf(char *dest, const size_t bytes, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
va_start(args, format);
|
||||||
|
|
||||||
|
count = rs_vsnprintf(dest, bytes, format, args);
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return (count);
|
||||||
|
} /* Snprintf() */
|
265
bandb/rsdb_sqlite3.c
Normal file
265
bandb/rsdb_sqlite3.c
Normal file
|
@ -0,0 +1,265 @@
|
||||||
|
/* src/rsdb_sqlite.h
|
||||||
|
* Contains the code for the sqlite database backend.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2003-2006 Lee Hardy <leeh@leeh.co.uk>
|
||||||
|
* Copyright (C) 2003-2006 ircd-ratbox development team
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* 1.Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2.Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3.The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $Id: rsdb_sqlite3.c 26182 2008-11-11 02:52:41Z androsyn $
|
||||||
|
*/
|
||||||
|
#include "stdinc.h"
|
||||||
|
#include "rsdb.h"
|
||||||
|
|
||||||
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
struct sqlite3 *rb_bandb;
|
||||||
|
|
||||||
|
rsdb_error_cb *error_cb;
|
||||||
|
|
||||||
|
static void
|
||||||
|
mlog(const char *errstr, ...)
|
||||||
|
{
|
||||||
|
if(error_cb != NULL)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, errstr);
|
||||||
|
rb_vsnprintf(buf, sizeof(buf), errstr, ap);
|
||||||
|
va_end(ap);
|
||||||
|
error_cb(buf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rsdb_init(rsdb_error_cb * ecb)
|
||||||
|
{
|
||||||
|
const char *bandb_dpath;
|
||||||
|
char dbpath[PATH_MAX];
|
||||||
|
char errbuf[128];
|
||||||
|
error_cb = ecb;
|
||||||
|
|
||||||
|
/* try a path from the environment first, useful for basedir overrides */
|
||||||
|
bandb_dpath = getenv("BANDB_DPATH");
|
||||||
|
|
||||||
|
if(bandb_dpath != NULL)
|
||||||
|
rb_snprintf(dbpath, sizeof(dbpath), "%s/etc/ban.db", bandb_dpath);
|
||||||
|
else
|
||||||
|
rb_strlcpy(dbpath, DBPATH, sizeof(dbpath));
|
||||||
|
|
||||||
|
if(sqlite3_open(dbpath, &rb_bandb) != SQLITE_OK)
|
||||||
|
{
|
||||||
|
rb_snprintf(errbuf, sizeof(errbuf), "Unable to open sqlite database: %s",
|
||||||
|
sqlite3_errmsg(rb_bandb));
|
||||||
|
mlog(errbuf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(access(dbpath, W_OK))
|
||||||
|
{
|
||||||
|
rb_snprintf(errbuf, sizeof(errbuf), "Unable to open sqlite database for write: %s", strerror(errno));
|
||||||
|
mlog(errbuf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rsdb_shutdown(void)
|
||||||
|
{
|
||||||
|
if(rb_bandb)
|
||||||
|
sqlite3_close(rb_bandb);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
rsdb_quote(const char *src)
|
||||||
|
{
|
||||||
|
static char buf[BUFSIZE * 4];
|
||||||
|
char *p = buf;
|
||||||
|
|
||||||
|
/* cheap and dirty length check.. */
|
||||||
|
if(strlen(src) >= (sizeof(buf) / 2))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while(*src)
|
||||||
|
{
|
||||||
|
if(*src == '\'')
|
||||||
|
*p++ = '\'';
|
||||||
|
|
||||||
|
*p++ = *src++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*p = '\0';
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rsdb_callback_func(void *cbfunc, int argc, char **argv, char **colnames)
|
||||||
|
{
|
||||||
|
rsdb_callback cb = (rsdb_callback)((uintptr_t)cbfunc);
|
||||||
|
(cb) (argc, (const char **)argv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rsdb_exec(rsdb_callback cb, const char *format, ...)
|
||||||
|
{
|
||||||
|
static char buf[BUFSIZE * 4];
|
||||||
|
va_list args;
|
||||||
|
char *errmsg;
|
||||||
|
unsigned int i;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
va_start(args, format);
|
||||||
|
i = rs_vsnprintf(buf, sizeof(buf), format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
if(i >= sizeof(buf))
|
||||||
|
{
|
||||||
|
mlog("fatal error: length problem with compiling sql");
|
||||||
|
}
|
||||||
|
|
||||||
|
if((i = sqlite3_exec(rb_bandb, buf, (cb ? rsdb_callback_func : NULL), (void *)((uintptr_t)cb), &errmsg)))
|
||||||
|
{
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case SQLITE_BUSY:
|
||||||
|
for(j = 0; j < 5; j++)
|
||||||
|
{
|
||||||
|
rb_sleep(0, 500000);
|
||||||
|
if(!sqlite3_exec
|
||||||
|
(rb_bandb, buf, (cb ? rsdb_callback_func : NULL), (void *)((uintptr_t)cb), &errmsg))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* failed, fall through to default */
|
||||||
|
mlog("fatal error: problem with db file: %s", errmsg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
mlog("fatal error: problem with db file: %s", errmsg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rsdb_exec_fetch(struct rsdb_table *table, const char *format, ...)
|
||||||
|
{
|
||||||
|
static char buf[BUFSIZE * 4];
|
||||||
|
va_list args;
|
||||||
|
char *errmsg;
|
||||||
|
char **data;
|
||||||
|
int pos;
|
||||||
|
unsigned int retval;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
va_start(args, format);
|
||||||
|
retval = rs_vsnprintf(buf, sizeof(buf), format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
if(retval >= sizeof(buf))
|
||||||
|
{
|
||||||
|
mlog("fatal error: length problem with compiling sql");
|
||||||
|
}
|
||||||
|
|
||||||
|
if((retval =
|
||||||
|
sqlite3_get_table(rb_bandb, buf, &data, &table->row_count, &table->col_count, &errmsg)))
|
||||||
|
{
|
||||||
|
int success = 0;
|
||||||
|
|
||||||
|
switch (retval)
|
||||||
|
{
|
||||||
|
case SQLITE_BUSY:
|
||||||
|
for(i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
rb_sleep(0, 500000);
|
||||||
|
if(!sqlite3_get_table
|
||||||
|
(rb_bandb, buf, &data, &table->row_count, &table->col_count,
|
||||||
|
&errmsg))
|
||||||
|
{
|
||||||
|
success++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(success)
|
||||||
|
break;
|
||||||
|
|
||||||
|
mlog("fatal error: problem with db file: %s", errmsg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
mlog("fatal error: problem with db file: %s", errmsg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we need to be able to free data afterward */
|
||||||
|
table->arg = data;
|
||||||
|
|
||||||
|
if(table->row_count == 0)
|
||||||
|
{
|
||||||
|
table->row = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sqlite puts the column names as the first row */
|
||||||
|
pos = table->col_count;
|
||||||
|
table->row = rb_malloc(sizeof(char **) * table->row_count);
|
||||||
|
for(i = 0; i < table->row_count; i++)
|
||||||
|
{
|
||||||
|
table->row[i] = rb_malloc(sizeof(char *) * table->col_count);
|
||||||
|
|
||||||
|
for(j = 0; j < table->col_count; j++)
|
||||||
|
{
|
||||||
|
table->row[i][j] = data[pos++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rsdb_exec_fetch_end(struct rsdb_table *table)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < table->row_count; i++)
|
||||||
|
{
|
||||||
|
rb_free(table->row[i]);
|
||||||
|
}
|
||||||
|
rb_free(table->row);
|
||||||
|
|
||||||
|
sqlite3_free_table((char **)table->arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rsdb_transaction(rsdb_transtype type)
|
||||||
|
{
|
||||||
|
if(type == RSDB_TRANS_START)
|
||||||
|
rsdb_exec(NULL, "BEGIN TRANSACTION");
|
||||||
|
else if(type == RSDB_TRANS_END)
|
||||||
|
rsdb_exec(NULL, "COMMIT TRANSACTION");
|
||||||
|
}
|
Loading…
Reference in a new issue