#include "mysql/mysql.h"
#include "auto_qmail.h"
#include "fmt.h"
#include "qsutil.h"
#include "readwrite.h"
#include "scan.h"
#include "str.h"
#include "stralloc.h"
#include "subfd.h"
#include "substdio.h"
#define SQLSERVER "sqlserver"
#define TRIES 3
MYSQL dbh, *mysql;
MYSQL_RES *result;
int connect_mysql() {
/* if database handle is available AND it pings then there's nothing to do */
DEBUG_SAY("connect_mysql(): checking existing connection\n");
if (mysql) if (! mysql_ping(&dbh)) return 1;
DEBUG_SAY("no connection, must reconnect\n");
return init_mysql();
}
/* try to connect to database with the username/password from config file */
/* returns 1 if we were already connected or we connected successfully */
/* returns 0 if we could not connect */
int init_mysql() {
int i, tries;
unsigned long portnum;
stralloc host = { 0 };
stralloc user = { 0 };
stralloc pass = { 0 };
stralloc name = { 0 };
stralloc port = { 0 };
stralloc sock = { 0 };
/* already used tries AND it has four letters :-) */
stralloc fois = { 0 };
DEBUG_SAY("calling mysql_init()\n");
mysql = mysql_init(&dbh);
if (! mysql) return 0;
DEBUG_SAY("mysql_init() returned successfully\n");
DEBUG_SAY("calling read_config_file()\n");
if (! read_config_file(&host, &user, &pass, &name, &port, &sock, &fois, &portnum, &tries)) {
log1("error: without a valid config file we can't access the database!\n");
return 0;
}
DEBUG_SAY("read_config_file() returned successfully\n");
/* have several goes attempting to the database */
for (i = 0; i < tries; i++) {
DEBUG_SAY("earth to mysqld, come in please mysqld\n");
mysql = mysql_real_connect(&dbh, host.s, user.s, pass.s, name.s,
portnum, sock.s, 0);
if (mysql) {
#ifndef O_NOT_LOG_CONNECTS
log3("connected to '", name.s, "' database\n");
#endif
break;
}
log3("error: ", mysql_error(&dbh), "\n");
sleep(3);
}
stralloc_free(&host);
stralloc_free(&user);
stralloc_free(&pass);
stralloc_free(&port);
stralloc_free(&sock);
stralloc_free(&fois);
if (! mysql) {
log3("giving up on connection to '", name.s, "' database\n");
stralloc_free(&name);
return 0;
}
stralloc_free(&name);
return 1;
}
void disconnect_mysql() {
mysql_close(&dbh);
}
int read_config_file(stralloc *host, stralloc *user, stralloc *pass, stralloc *name, stralloc *port, stralloc *sock, stralloc *fois, unsigned long *portnum, int *tries) {
int error, i, file, match;
substdio ss;
stralloc filename = { 0 };
stralloc buf = { 0 };
char inbuf[64];
/* get the filename of the sqlserver control file */
DEBUG_SAY("figuring out sqlserver path\n");
i = str_len(SQLSERVER) + str_len(auto_qmail) + 10;
if (! stralloc_ready(&filename, i)) return 0;
if (! stralloc_cats(&filename, auto_qmail)) return 0;
if (! stralloc_cats(&filename, "/control/")) return 0;
if (! stralloc_cats(&filename, SQLSERVER)) return 0;
if (! stralloc_0(&filename)) return 0;
DEBUG_PUT("sqlserver file is \"");
DEBUG_PUT(filename.s);
DEBUG_SAY("\"\n");
DEBUG_SAY("stand by, we're trying the file\n");
file = open_read(filename.s);
if (file == -1) {
log3("error: could not open sqlserver file \"", filename.s, "\"\n");
stralloc_free(&filename);
stralloc_free(&buf);
return 0;
}
substdio_fdbuf(&ss, read, file, inbuf, sizeof(inbuf));
while (getln(&ss, &buf, &match, '\n') != -1) {
if (! match && ! buf.len) break;
buf.len--;
if (! stralloc_0(&buf)) break;
/* we consider only lines starting with the letters h, s,l,p,d or t */
switch (buf.s[0]) {
case 'h': error = getconfig(&buf, "host", host); break;
case 's':
if (buf.s[1] == 'e') error = getconfig(&buf, "server", host);
else error = getconfig(&buf, "socket", sock);
break;
case 'l': error = getconfig(&buf, "login", user); break;
case 'p':
if (buf.s[1] == 'a') error = getconfig(&buf, "password", pass);
else error = getconfig(&buf, "port", port);
break;
case 'd': error = getconfig(&buf, "db", name); break;
case 't': error = getconfig(&buf, "tries", fois); break;
default: continue;
}
if (error == -1) continue;
if (! match) break;
}
DEBUG_SAY("closing configuration file\n");
close(file);
stralloc_free(&filename);
stralloc_free(&buf);
/* if a port is provided it must be a valid number */
if (port->a > 0) {
DEBUG_SAY("checking validity of provided port number\n");
i = scan_ulong(port->s, portnum);
if (! i || port->s[i]) {
log3("error: bogus port number: \"", port->s, "\"\n");
return 0;
}
}
else *portnum = 0;
/* specific number of connection attempts */
if (fois->a > 0) {
DEBUG_SAY("checking validity of requested connection attempts\n");
i = scan_ulong(fois->s, tries);
if (! i || fois->s[i]) {
log3("warning: bogus connection attempts number: \"", fois->s, "\"\n");
if (stralloc_ready(fois, FMT_ULONG)) {
fois->s[fmt_ulong(fois->s, TRIES)] = '\0';
log3("warning: using default ", fois->s, "\n");
}
*tries = TRIES;
}
else {
if (*tries == 0) {
log1("error: we must make at least one connection attempt\n");
return 0;
}
DEBUG_PUT("we will try ");
if (*tries == 1) DEBUG_PUT("once (only) ");
else {
DEBUG_PUT(fois->s);
DEBUG_PUT(" times ");
}
DEBUG_SAY("to connect to the database\n");
}
}
else *tries = TRIES;
/* we must have at least a username */
if (! user->a) {
log3("error: no username provided in \"", filename.s, "\"\n");
return 0;
}
if (host->a) {
DEBUG_PUT("host is \"");
DEBUG_PUT(host->s);
DEBUG_SAY("\"\n");
}
if (port->a) {
if (sock->a) {
log3("error: you can't specify a port number AND a socket\n");
return 0;
}
DEBUG_PUT("port is ");
DEBUG_PUT(port->s);
DEBUG_SAY("\n");
}
DEBUG_PUT("user is \"");
DEBUG_PUT(user->s);
DEBUG_SAY("\"\n");
if (pass->a) DEBUG_SAY("a password was provided\n");
return 1;
}
/* read lines in the config file and grok entries of the form "x=y" or "x y" */
/* got is the line in the file, expected is the parmeter we're checking for */
/* and store is a stralloc to put the result into if it was found */
int getconfig(stralloc *got, char *expected, stralloc *store) {
char *value, *x;
x = got->s + str_len(expected);
value = x + 1;
/* we got a meaningful value */
if (! stralloc_starts(&got, expected) && (*x == ' ' || *x == '\t' || *x == '=') && str_len(value) > 0) {
if (! stralloc_ready(store, str_len(value) + 1)) return -1;
if (! stralloc_cats(store, value)) return -1;
if (! stralloc_0(store)) return -1;
return 0;
}
/* oh dear, the line we got didn't contain what we expected it to */
log3("error: reading sqlserver file, expected \"", expected, "\" but got \"");
log2(got, "\"\n");
/* of course, we might have been expecting the wrong thing... */
return -1;
}
syntax highlighted by Code2HTML, v. 0.9.1