2003-12-10 15:09:40 +00:00
|
|
|
|
|
|
|
/***************************************************************
|
|
|
|
* Run Time Access
|
|
|
|
* Copyright (C) 2003 Robert W Smith (bsmith@linuxtoys.org)
|
|
|
|
*
|
|
|
|
* This program is distributed under the terms of the GNU LGPL.
|
|
|
|
* See the file COPYING file.
|
|
|
|
**************************************************************/
|
|
|
|
|
|
|
|
/***************************************************************
|
|
|
|
* api.c -- routines to provide a PostgreSQL DB API to
|
|
|
|
* embedded systems.
|
|
|
|
**************************************************************/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h> /* for mkstemp() */
|
2004-02-07 23:47:56 +00:00
|
|
|
#include <libgen.h> /* for dirname() */
|
2003-12-10 15:09:40 +00:00
|
|
|
#include <string.h> /* for strlen() */
|
|
|
|
#include <limits.h> /* for PATH_MAX */
|
The sql code is integrated with the conf file, socket code, and initilization portions so far.
its not yet setup to export any of NeoStats structs, but you can test with this release with the built in tables:
to test:
./configure --enable-sqlsrv
add a line to neostats.cfg:
SQLSRV_AUTH Fish!blah@127.0.0.*
(username Fish, pass blah, host 127.0.0.* (IP only, can use wildcards)
compile and start up NeoStats
Check for any errors about unable to bind to ports etc.... (if you need to run on a diff port, add SQLSRV_PORT <portnum> to the neostats.cfg
now that its running, from php/command line, connect to the BINDTO ip address (if using BINDTO) or 127.0.0.1 port 8888
eg: command line:
psql -U Fish -h localhost -p 8888
it should prompt with a password.
once connected, you can view available tables with:
"select * from rta_tables;"
some examples are:
"select * from pg_user;"
"select * from pg_conn;"
"select * from rta_stat;"
"select * from rta_dbg;"
"select * from rta_columns;"
Remember, only very basic SQL is supported
2003-12-11 15:37:05 +00:00
|
|
|
#ifdef SYSLOG
|
2003-12-10 15:09:40 +00:00
|
|
|
#include <syslog.h>
|
The sql code is integrated with the conf file, socket code, and initilization portions so far.
its not yet setup to export any of NeoStats structs, but you can test with this release with the built in tables:
to test:
./configure --enable-sqlsrv
add a line to neostats.cfg:
SQLSRV_AUTH Fish!blah@127.0.0.*
(username Fish, pass blah, host 127.0.0.* (IP only, can use wildcards)
compile and start up NeoStats
Check for any errors about unable to bind to ports etc.... (if you need to run on a diff port, add SQLSRV_PORT <portnum> to the neostats.cfg
now that its running, from php/command line, connect to the BINDTO ip address (if using BINDTO) or 127.0.0.1 port 8888
eg: command line:
psql -U Fish -h localhost -p 8888
it should prompt with a password.
once connected, you can view available tables with:
"select * from rta_tables;"
some examples are:
"select * from pg_user;"
"select * from pg_conn;"
"select * from rta_stat;"
"select * from rta_dbg;"
"select * from rta_columns;"
Remember, only very basic SQL is supported
2003-12-11 15:37:05 +00:00
|
|
|
#endif
|
2003-12-10 15:09:40 +00:00
|
|
|
#include <time.h>
|
|
|
|
#include "rta.h" /* for various constants */
|
|
|
|
#include "do_sql.h" /* for LOC */
|
|
|
|
|
|
|
|
/* Tbl and Col contain pointers to table and column
|
|
|
|
* definitions of all tables and columns in * the system.
|
|
|
|
* Ntbl and Ncol are the number of tables and columns in each
|
|
|
|
* list. These are used often enough that they are globals. */
|
|
|
|
TBLDEF *Tbl[MX_TBL];
|
|
|
|
int Ntbl;
|
|
|
|
COLDEF *Col[MX_COL];
|
|
|
|
int Ncol;
|
|
|
|
|
|
|
|
extern struct EpgDbg rtadbg;
|
|
|
|
|
|
|
|
EpgConn *getconndata(int id);
|
|
|
|
|
|
|
|
EpgConn *
|
|
|
|
getconndata(int id)
|
|
|
|
{
|
2003-12-28 07:23:42 +00:00
|
|
|
lnode_t *lnode;
|
|
|
|
EpgConn *conn;
|
2003-12-10 15:09:40 +00:00
|
|
|
|
2003-12-28 07:23:42 +00:00
|
|
|
lnode = list_first(pgconn);
|
|
|
|
while (lnode) {
|
|
|
|
conn = lnode_get(lnode);
|
|
|
|
if (conn->id == id)
|
|
|
|
return conn;
|
|
|
|
lnode = list_next(pgconn, lnode);
|
|
|
|
}
|
|
|
|
return NULL;
|
2003-12-10 15:09:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************
|
|
|
|
* rta_init(): - Initialize all internal system tables.
|
|
|
|
*
|
|
|
|
* Input: None.
|
|
|
|
* Output: None.
|
|
|
|
**************************************************************/
|
|
|
|
void
|
The sql code is integrated with the conf file, socket code, and initilization portions so far.
its not yet setup to export any of NeoStats structs, but you can test with this release with the built in tables:
to test:
./configure --enable-sqlsrv
add a line to neostats.cfg:
SQLSRV_AUTH Fish!blah@127.0.0.*
(username Fish, pass blah, host 127.0.0.* (IP only, can use wildcards)
compile and start up NeoStats
Check for any errors about unable to bind to ports etc.... (if you need to run on a diff port, add SQLSRV_PORT <portnum> to the neostats.cfg
now that its running, from php/command line, connect to the BINDTO ip address (if using BINDTO) or 127.0.0.1 port 8888
eg: command line:
psql -U Fish -h localhost -p 8888
it should prompt with a password.
once connected, you can view available tables with:
"select * from rta_tables;"
some examples are:
"select * from pg_user;"
"select * from pg_conn;"
"select * from rta_stat;"
"select * from rta_dbg;"
"select * from rta_columns;"
Remember, only very basic SQL is supported
2003-12-11 15:37:05 +00:00
|
|
|
rta_init(logcb logfunc)
|
2003-12-10 15:09:40 +00:00
|
|
|
{
|
|
|
|
int i; /* loop index */
|
|
|
|
extern TBLDEF pg_userTable;
|
|
|
|
extern TBLDEF rta_tablesTable;
|
|
|
|
extern TBLDEF rta_columnsTable;
|
2003-12-16 12:57:37 +00:00
|
|
|
#ifdef SHWDBGTBL
|
2003-12-10 15:09:40 +00:00
|
|
|
extern TBLDEF rta_dbgTable;
|
2003-12-16 12:57:37 +00:00
|
|
|
#endif
|
2003-12-10 15:09:40 +00:00
|
|
|
extern TBLDEF rta_statTable;
|
|
|
|
extern TBLDEF pg_connTable;
|
The sql code is integrated with the conf file, socket code, and initilization portions so far.
its not yet setup to export any of NeoStats structs, but you can test with this release with the built in tables:
to test:
./configure --enable-sqlsrv
add a line to neostats.cfg:
SQLSRV_AUTH Fish!blah@127.0.0.*
(username Fish, pass blah, host 127.0.0.* (IP only, can use wildcards)
compile and start up NeoStats
Check for any errors about unable to bind to ports etc.... (if you need to run on a diff port, add SQLSRV_PORT <portnum> to the neostats.cfg
now that its running, from php/command line, connect to the BINDTO ip address (if using BINDTO) or 127.0.0.1 port 8888
eg: command line:
psql -U Fish -h localhost -p 8888
it should prompt with a password.
once connected, you can view available tables with:
"select * from rta_tables;"
some examples are:
"select * from pg_user;"
"select * from pg_conn;"
"select * from rta_stat;"
"select * from rta_dbg;"
"select * from rta_columns;"
Remember, only very basic SQL is supported
2003-12-11 15:37:05 +00:00
|
|
|
#ifdef SYSLOG
|
2003-12-10 15:09:40 +00:00
|
|
|
extern void restart_syslog();
|
The sql code is integrated with the conf file, socket code, and initilization portions so far.
its not yet setup to export any of NeoStats structs, but you can test with this release with the built in tables:
to test:
./configure --enable-sqlsrv
add a line to neostats.cfg:
SQLSRV_AUTH Fish!blah@127.0.0.*
(username Fish, pass blah, host 127.0.0.* (IP only, can use wildcards)
compile and start up NeoStats
Check for any errors about unable to bind to ports etc.... (if you need to run on a diff port, add SQLSRV_PORT <portnum> to the neostats.cfg
now that its running, from php/command line, connect to the BINDTO ip address (if using BINDTO) or 127.0.0.1 port 8888
eg: command line:
psql -U Fish -h localhost -p 8888
it should prompt with a password.
once connected, you can view available tables with:
"select * from rta_tables;"
some examples are:
"select * from pg_user;"
"select * from pg_conn;"
"select * from rta_stat;"
"select * from rta_dbg;"
"select * from rta_columns;"
Remember, only very basic SQL is supported
2003-12-11 15:37:05 +00:00
|
|
|
#else
|
|
|
|
RTA_Conf.loggingfunc = logfunc;
|
|
|
|
#endif
|
2003-12-10 15:09:40 +00:00
|
|
|
|
|
|
|
for (i = 0; i < MX_TBL; i++)
|
|
|
|
{
|
|
|
|
Tbl[i] = (TBLDEF *) 0;
|
|
|
|
}
|
|
|
|
Ntbl = 0;
|
|
|
|
|
|
|
|
/* init the pgconn structure */
|
2003-12-28 07:23:42 +00:00
|
|
|
pgconn = list_create(-1);
|
2003-12-10 15:09:40 +00:00
|
|
|
pg_connTable.address = pgconn;
|
|
|
|
|
|
|
|
/* add system and internal tables here */
|
|
|
|
(void) rta_add_table(&rta_tablesTable);
|
|
|
|
(void) rta_add_table(&rta_columnsTable);
|
|
|
|
(void) rta_add_table(&pg_userTable);
|
|
|
|
(void) rta_add_table(&pg_connTable);
|
2003-12-16 12:57:37 +00:00
|
|
|
#ifdef SHWDBGTBL
|
2003-12-10 15:09:40 +00:00
|
|
|
(void) rta_add_table(&rta_dbgTable);
|
2003-12-16 12:57:37 +00:00
|
|
|
#endif
|
2003-12-10 15:09:40 +00:00
|
|
|
(void) rta_add_table(&rta_statTable);
|
The sql code is integrated with the conf file, socket code, and initilization portions so far.
its not yet setup to export any of NeoStats structs, but you can test with this release with the built in tables:
to test:
./configure --enable-sqlsrv
add a line to neostats.cfg:
SQLSRV_AUTH Fish!blah@127.0.0.*
(username Fish, pass blah, host 127.0.0.* (IP only, can use wildcards)
compile and start up NeoStats
Check for any errors about unable to bind to ports etc.... (if you need to run on a diff port, add SQLSRV_PORT <portnum> to the neostats.cfg
now that its running, from php/command line, connect to the BINDTO ip address (if using BINDTO) or 127.0.0.1 port 8888
eg: command line:
psql -U Fish -h localhost -p 8888
it should prompt with a password.
once connected, you can view available tables with:
"select * from rta_tables;"
some examples are:
"select * from pg_user;"
"select * from pg_conn;"
"select * from rta_stat;"
"select * from rta_dbg;"
"select * from rta_columns;"
Remember, only very basic SQL is supported
2003-12-11 15:37:05 +00:00
|
|
|
#ifdef SYSLOG
|
2003-12-10 15:09:40 +00:00
|
|
|
restart_syslog((char *) 0, (char *) 0, (char *) 0, 0);
|
The sql code is integrated with the conf file, socket code, and initilization portions so far.
its not yet setup to export any of NeoStats structs, but you can test with this release with the built in tables:
to test:
./configure --enable-sqlsrv
add a line to neostats.cfg:
SQLSRV_AUTH Fish!blah@127.0.0.*
(username Fish, pass blah, host 127.0.0.* (IP only, can use wildcards)
compile and start up NeoStats
Check for any errors about unable to bind to ports etc.... (if you need to run on a diff port, add SQLSRV_PORT <portnum> to the neostats.cfg
now that its running, from php/command line, connect to the BINDTO ip address (if using BINDTO) or 127.0.0.1 port 8888
eg: command line:
psql -U Fish -h localhost -p 8888
it should prompt with a password.
once connected, you can view available tables with:
"select * from rta_tables;"
some examples are:
"select * from pg_user;"
"select * from pg_conn;"
"select * from rta_stat;"
"select * from rta_dbg;"
"select * from rta_columns;"
Remember, only very basic SQL is supported
2003-12-11 15:37:05 +00:00
|
|
|
#endif
|
2003-12-10 15:09:40 +00:00
|
|
|
}
|
|
|
|
|
The sql code is integrated with the conf file, socket code, and initilization portions so far.
its not yet setup to export any of NeoStats structs, but you can test with this release with the built in tables:
to test:
./configure --enable-sqlsrv
add a line to neostats.cfg:
SQLSRV_AUTH Fish!blah@127.0.0.*
(username Fish, pass blah, host 127.0.0.* (IP only, can use wildcards)
compile and start up NeoStats
Check for any errors about unable to bind to ports etc.... (if you need to run on a diff port, add SQLSRV_PORT <portnum> to the neostats.cfg
now that its running, from php/command line, connect to the BINDTO ip address (if using BINDTO) or 127.0.0.1 port 8888
eg: command line:
psql -U Fish -h localhost -p 8888
it should prompt with a password.
once connected, you can view available tables with:
"select * from rta_tables;"
some examples are:
"select * from pg_user;"
"select * from pg_conn;"
"select * from rta_stat;"
"select * from rta_dbg;"
"select * from rta_columns;"
Remember, only very basic SQL is supported
2003-12-11 15:37:05 +00:00
|
|
|
|
|
|
|
|
2003-12-10 15:09:40 +00:00
|
|
|
/***************************************************************
|
|
|
|
* rta_add_table(): - Add one table to the list of
|
|
|
|
* tables in the system. If the table has an associated
|
|
|
|
* "savefile" we try to open the savefile and execute any SQL
|
|
|
|
* commands found there.
|
|
|
|
*
|
|
|
|
* Input: ptbl: pointer to the table to add
|
|
|
|
* Output: RTA_SUCCESS - Add successful
|
|
|
|
* RTA_DUP - Table is already in the list. (Note
|
|
|
|
* that this might not be an error since
|
|
|
|
* we can allow redefinition of a table)
|
|
|
|
* RTA_ERROR - The passed table definition has a
|
|
|
|
* problem which prevents its addition.
|
|
|
|
* A syslog error message describes the
|
|
|
|
* problem
|
|
|
|
**************************************************************/
|
|
|
|
int
|
|
|
|
rta_add_table(TBLDEF *ptbl)
|
|
|
|
{
|
|
|
|
extern struct EpgStat rtastat;
|
|
|
|
extern TBLDEF rta_columnsTable;
|
|
|
|
int i, j; /* a loop index */
|
|
|
|
|
|
|
|
/* Error if at Ntbl limit */
|
|
|
|
if (Ntbl == MX_TBL)
|
|
|
|
{
|
|
|
|
rtastat.nrtaerr++;
|
|
|
|
if (rtadbg.rtaerr)
|
|
|
|
rtalog(LOC, Er_Max_Tbls);
|
|
|
|
return (RTA_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* verify that table name is unique */
|
|
|
|
i = 0;
|
|
|
|
while (i < Ntbl)
|
|
|
|
{
|
|
|
|
if (!strncmp(ptbl->name, Tbl[i]->name, MXTBLNAME))
|
|
|
|
{
|
|
|
|
rtastat.nrtaerr++;
|
|
|
|
if (rtadbg.rtaerr)
|
|
|
|
rtalog(LOC, Er_Tbl_Dup, ptbl->name);
|
|
|
|
return (RTA_ERROR);
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* verify lenght of table name */
|
|
|
|
if (strlen(ptbl->name) > MXTBLNAME)
|
|
|
|
{
|
|
|
|
rtastat.nrtaerr++;
|
|
|
|
if (rtadbg.rtaerr)
|
|
|
|
rtalog(LOC, Er_Tname_Big, ptbl->name);
|
|
|
|
return (RTA_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* verify savefile name is a valid pointer */
|
|
|
|
if (ptbl->savefile == (char *) 0)
|
|
|
|
{
|
|
|
|
rtastat.nrtaerr++;
|
|
|
|
if (rtadbg.rtaerr)
|
|
|
|
rtalog(LOC, Er_Col_Type, "savefile");
|
|
|
|
return (RTA_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check the upper bound on # columns / table */
|
|
|
|
if (ptbl->ncol > NCMDCOLS)
|
|
|
|
{
|
|
|
|
rtastat.nrtaerr++;
|
|
|
|
if (rtadbg.rtaerr)
|
|
|
|
rtalog(LOC, Er_Cmd_Cols, ptbl->name);
|
|
|
|
return (RTA_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* verify that column names are unique within table */
|
|
|
|
for (i = 0; i < ptbl->ncol; i++)
|
|
|
|
{
|
|
|
|
for (j = 0; j < i; j++)
|
|
|
|
{
|
|
|
|
if (!strncmp(ptbl->cols[i].name, ptbl->cols[j].name, MXCOLNAME))
|
|
|
|
{
|
|
|
|
rtastat.nrtaerr++;
|
|
|
|
if (rtadbg.rtaerr)
|
|
|
|
rtalog(LOC, Er_Col_Dup, ptbl->cols[i].name);
|
|
|
|
return (RTA_ERROR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* verify column name length, help length, data type, and flag
|
|
|
|
contents */
|
|
|
|
for (i = 0; i < ptbl->ncol; i++)
|
|
|
|
{
|
|
|
|
if (strlen(ptbl->cols[i].name) > MXCOLNAME)
|
|
|
|
{
|
|
|
|
rtastat.nrtaerr++;
|
|
|
|
if (rtadbg.rtaerr)
|
|
|
|
rtalog(LOC, Er_Cname_Big, ptbl->cols[i].name);
|
|
|
|
return (RTA_ERROR);
|
|
|
|
}
|
|
|
|
if (strlen(ptbl->cols[i].help) > MXHELPSTR)
|
|
|
|
{
|
|
|
|
rtastat.nrtaerr++;
|
|
|
|
if (rtadbg.rtaerr)
|
|
|
|
rtalog(LOC, Er_Hname_Big, ptbl->cols[i].name);
|
|
|
|
return (RTA_ERROR);
|
|
|
|
}
|
|
|
|
if (ptbl->cols[i].type > MXCOLTYPE)
|
|
|
|
{
|
|
|
|
rtastat.nrtaerr++;
|
|
|
|
if (rtadbg.rtaerr)
|
|
|
|
rtalog(LOC, Er_Col_Type, ptbl->cols[i].name);
|
|
|
|
return (RTA_ERROR);
|
|
|
|
}
|
|
|
|
if (ptbl->cols[i].flags > RTA_DISKSAVE + RTA_READONLY)
|
|
|
|
{
|
|
|
|
rtastat.nrtaerr++;
|
|
|
|
if (rtadbg.rtaerr)
|
|
|
|
rtalog(LOC, Er_Col_Flag, ptbl->cols[i].name);
|
|
|
|
return (RTA_ERROR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify that we can add the columns */
|
|
|
|
if ((Ncol + ptbl->ncol) >= MX_COL)
|
|
|
|
{
|
|
|
|
rtastat.nrtaerr++;
|
|
|
|
if (rtadbg.rtaerr)
|
|
|
|
rtalog(LOC, Er_Max_Cols);
|
|
|
|
return (RTA_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Everything looks OK. Add table and columns */
|
|
|
|
Tbl[Ntbl++] = ptbl;
|
|
|
|
Tbl[0]->nrows = Ntbl;
|
|
|
|
|
|
|
|
/* Add columns to list of column pointers */
|
|
|
|
for (i = 0; i < ptbl->ncol; i++)
|
|
|
|
{
|
|
|
|
Col[Ncol++] = &(ptbl->cols[i]);
|
|
|
|
}
|
|
|
|
rta_columnsTable.nrows += ptbl->ncol;
|
|
|
|
|
|
|
|
/* Execute commands in the save file to restore */
|
|
|
|
if (ptbl->savefile && strlen(ptbl->savefile) > 0)
|
|
|
|
(void) rta_load(ptbl, ptbl->savefile);
|
|
|
|
|
|
|
|
return (RTA_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************
|
|
|
|
* Postgres "packets" are identified by their first few bytes.
|
|
|
|
* The newer protocol used a single ASCII byte to identify the
|
|
|
|
* packet type, while the older protocol has a 32 bit length
|
|
|
|
* field at the start of the packet. Note that multi-byte data
|
|
|
|
* is sent with the most significant byte first. Please see the
|
|
|
|
* full documentation in "PostgreSQL 7.2.1 Developer's Guide"
|
|
|
|
* at http://www.postgresql.org/idocs/
|
|
|
|
*
|
|
|
|
* The Postgres protocol from client to server has about six
|
|
|
|
* request types. We use three of the request types in our
|
|
|
|
* basic implementation. The six packet types.....
|
|
|
|
* BYTE0 BYTE1 BYTE2 BYTE3
|
|
|
|
* 0 0 0x1 0x18 Startup packet to open connection
|
|
|
|
* 0 ? ? ? Encrypted password packet
|
|
|
|
* 0 0 0 0x10 Cancel pending request
|
|
|
|
* 'F' Function call
|
|
|
|
* 'Q' Query
|
|
|
|
* 'X' Terminate connection
|
|
|
|
*
|
|
|
|
**************************************************************/
|
|
|
|
|
|
|
|
/***************************************************************
|
|
|
|
* dbcommand(): - Depacketize and execute any Postgres
|
|
|
|
* commands in the input buffer.
|
|
|
|
*
|
|
|
|
* Input: buf - the buffer with the Postgres packet
|
|
|
|
* nin - on entry, the number of bytes in 'buf',
|
|
|
|
* on exit, the number of bytes remaining in buf
|
|
|
|
* out - the buffer to hold responses back to client
|
|
|
|
* nout - on entry, the number of free bytes in 'out'
|
|
|
|
* on exit, the number of remaining free bytes
|
|
|
|
* Return: RTA_SUCCESS - executed one command
|
|
|
|
* RTA_NOCMD - input did not have a full cmd
|
|
|
|
* RTA_ERROR - some kind of error
|
|
|
|
* RTA_CLOSE - client requests a orderly close
|
|
|
|
**************************************************************/
|
|
|
|
int
|
2003-12-28 07:23:42 +00:00
|
|
|
dbcommand(char *buf, int *nin, char *out, int *nout, int connid)
|
2003-12-10 15:09:40 +00:00
|
|
|
{
|
|
|
|
extern struct EpgStat rtastat;
|
|
|
|
int length; /* lenght of the packet if old protocol */
|
|
|
|
int i; /* a temp integer */
|
2003-12-28 07:23:42 +00:00
|
|
|
lnode_t *lnode;
|
2003-12-10 15:09:40 +00:00
|
|
|
EpgConn *conn;
|
|
|
|
char line[MX_LN_SZ]; /* input line from file */
|
|
|
|
char reply[MX_LN_SZ]; /* response from SQL process */
|
|
|
|
int nreply; /* number of free bytes in reply */
|
|
|
|
|
2003-12-28 07:23:42 +00:00
|
|
|
|
2003-12-10 15:09:40 +00:00
|
|
|
/* old style packet if first byte is zero */
|
|
|
|
if ((int) buf[0] == 0)
|
|
|
|
{
|
|
|
|
/* get length. Enough bytes for a length? if not, consume no
|
|
|
|
input, write no output */
|
|
|
|
if (*nin < 4)
|
|
|
|
{
|
|
|
|
return (RTA_NOCMD);
|
|
|
|
}
|
|
|
|
length = (int) (buf[3] + (buf[2] << 8) + (buf[1] << 16));
|
|
|
|
|
|
|
|
/* Is the whole packet here? If not, consume no input, write no
|
|
|
|
output */
|
|
|
|
if (*nin < length)
|
|
|
|
{
|
|
|
|
return (RTA_NOCMD);
|
|
|
|
}
|
|
|
|
if (length == 296) /* a startup request */
|
|
|
|
{
|
|
|
|
/* we key on a non-null user name to send AuthOK. The protocol
|
|
|
|
packet has an int32 for the length, an int32 for the protocol
|
|
|
|
version, a 64 char string for the DB name and at byte 72 the
|
|
|
|
start of a 32 char user name. */
|
|
|
|
if (buf[72] == (char) 0)
|
|
|
|
{
|
|
|
|
*nin -= length;
|
|
|
|
out[0] = 'N'; /* "Notice" response */
|
|
|
|
*nout -= 1;
|
|
|
|
rtastat.nauth++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* first thing we do is find the hash for this struct? */
|
2003-12-28 07:23:42 +00:00
|
|
|
conn = getconndata(connid);
|
|
|
|
if (conn)
|
2003-12-10 15:09:40 +00:00
|
|
|
{
|
|
|
|
snprintf(conn->cmd, 1000, "Re-Authenticating");
|
|
|
|
snprintf((char *) conn->username, 32, "%s", &buf[72]);
|
|
|
|
conn->rsp[0] = '\0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
conn = malloc(sizeof(EpgConn));
|
|
|
|
bzero(conn, sizeof(EpgConn));
|
|
|
|
snprintf(conn->cmd, 1000, "Authenticating");
|
|
|
|
snprintf((char *) conn->username, 32, "%s", &buf[72]);
|
2003-12-28 07:23:42 +00:00
|
|
|
conn->id = connid;
|
2003-12-10 15:09:40 +00:00
|
|
|
conn->ctm = time(NULL);
|
2003-12-28 07:23:42 +00:00
|
|
|
lnode = lnode_create(conn);
|
|
|
|
list_append(pgconn, lnode);
|
2003-12-10 15:09:40 +00:00
|
|
|
}
|
|
|
|
*nin -= length;
|
|
|
|
out[0] = 'R';
|
|
|
|
out[1] = 0;
|
|
|
|
out[2] = 0;
|
|
|
|
out[3] = 0;
|
|
|
|
out[4] = 3;
|
|
|
|
// out[5] = 'Z';
|
|
|
|
// *out++ = 'R';
|
|
|
|
// ad_int4 (&buf, 0);
|
|
|
|
// *out++ = 'Z';
|
|
|
|
*nout -= 5;
|
|
|
|
}
|
|
|
|
return (RTA_SUCCESS);
|
|
|
|
}
|
|
|
|
else if (length == 16) /* a cancel request */
|
|
|
|
{
|
|
|
|
/* ignore the request for now */
|
2003-12-28 07:23:42 +00:00
|
|
|
conn = getconndata(connid);
|
2003-12-10 15:09:40 +00:00
|
|
|
if (conn)
|
|
|
|
{
|
|
|
|
snprintf((char *) conn->cmd, 1000, "Cancel Call");
|
|
|
|
conn->rsp[0] = '\0';
|
|
|
|
}
|
|
|
|
*nin -= length;
|
|
|
|
return (RTA_SUCCESS);
|
|
|
|
}
|
|
|
|
else /* should be a password */
|
|
|
|
{
|
2003-12-28 07:23:42 +00:00
|
|
|
conn = getconndata(connid);
|
2003-12-10 15:09:40 +00:00
|
|
|
if (!conn)
|
|
|
|
{
|
|
|
|
/* pass before username (and thus conn?) Bah */
|
|
|
|
return (RTA_CLOSE);
|
|
|
|
}
|
|
|
|
snprintf((char *) conn->password, 32, "%s", &buf[4]);
|
|
|
|
nreply = MX_LN_SZ;
|
|
|
|
snprintf(line, MX_LN_SZ,
|
|
|
|
"select * from pg_user where usename=\"%s\" and passwd = \"%s\"",
|
|
|
|
conn->username, conn->password);
|
|
|
|
SQL_string(line, reply, &nreply);
|
|
|
|
if (nreply != 1279)
|
|
|
|
{
|
|
|
|
/* SQL command failed! Report error */
|
|
|
|
rtastat.nsyserr++;
|
|
|
|
if (rtadbg.syserr)
|
|
|
|
rtalog(LOC, Er_BadPass);
|
|
|
|
*nin -= length;
|
|
|
|
out[0] = 'E';
|
|
|
|
out[1] = 'B';
|
|
|
|
out[2] = 'A';
|
|
|
|
out[3] = 'D';
|
|
|
|
out[4] = ' ';
|
|
|
|
out[5] = 'U';
|
|
|
|
out[6] = 'S';
|
|
|
|
out[7] = 'E';
|
|
|
|
out[8] = 'R';
|
|
|
|
out[9] = '/';
|
|
|
|
out[10] = 'P';
|
|
|
|
out[11] = 'A';
|
|
|
|
out[12] = 'S';
|
|
|
|
out[13] = 'S';
|
|
|
|
out[14] = 0;
|
|
|
|
*nout -= 15;
|
|
|
|
|
|
|
|
return (RTA_CLOSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX validate it */
|
|
|
|
*nin -= length;
|
|
|
|
out[0] = 'R';
|
|
|
|
out[1] = 0;
|
|
|
|
out[2] = 0;
|
|
|
|
out[3] = 0;
|
|
|
|
out[4] = 0;
|
|
|
|
out[5] = 'Z';
|
|
|
|
*nout -= 6;
|
|
|
|
return (RTA_SUCCESS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (buf[0] == 'Q') /* a query request */
|
|
|
|
{
|
2003-12-28 07:23:42 +00:00
|
|
|
conn = getconndata(connid);
|
2003-12-10 15:09:40 +00:00
|
|
|
/* check for a complete command */
|
|
|
|
for (i = 0; i < *nin; i++)
|
|
|
|
{
|
|
|
|
if (buf[i] == (char) 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == *nin)
|
|
|
|
{
|
|
|
|
if (conn)
|
|
|
|
snprintf(conn->cmd, 50000, "Reading Query");
|
|
|
|
return (RTA_NOCMD);
|
|
|
|
}
|
|
|
|
/* Got a null terminated command; do it. (buf[1] since the SQL
|
|
|
|
follows the 'Q') */
|
|
|
|
if (!conn)
|
|
|
|
{
|
|
|
|
return (RTA_CLOSE);
|
|
|
|
}
|
|
|
|
snprintf((char *) conn->cmd, 1000, "Query: %s", &buf[1]);
|
|
|
|
SQL_string(&buf[1], out, nout);
|
|
|
|
snprintf((char *) conn->rsp, 50000, "%s", out);
|
|
|
|
*nin -= strlen(buf); /* to swallow the cmd */
|
|
|
|
(*nin)--; /* to swallow the null */
|
|
|
|
return (RTA_SUCCESS);
|
|
|
|
}
|
|
|
|
else if (buf[0] == 'X') /* a terminate request */
|
|
|
|
{
|
2003-12-28 07:23:42 +00:00
|
|
|
conn = getconndata(connid);
|
2003-12-10 15:09:40 +00:00
|
|
|
if (conn)
|
|
|
|
snprintf(conn->cmd, 1000, "Disconnecting");
|
|
|
|
return (RTA_CLOSE);
|
|
|
|
}
|
|
|
|
else if (buf[0] == 'F') /* a function request */
|
|
|
|
{
|
2003-12-28 07:23:42 +00:00
|
|
|
conn = getconndata(connid);
|
2003-12-10 15:09:40 +00:00
|
|
|
if (conn)
|
|
|
|
snprintf(conn->cmd, 1000,
|
|
|
|
"Unsupported Function Call. Disconnecting");
|
|
|
|
return (RTA_CLOSE);
|
|
|
|
}
|
2003-12-28 07:23:42 +00:00
|
|
|
conn = getconndata(connid);
|
2003-12-10 15:09:40 +00:00
|
|
|
if (conn)
|
|
|
|
snprintf(conn->cmd, 1000, "Unsupported Call. Disconnecting");
|
|
|
|
|
|
|
|
/* an unknown request (should be logged?) */
|
|
|
|
return (RTA_CLOSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
deldbconnection(int connid)
|
|
|
|
{
|
2003-12-28 07:23:42 +00:00
|
|
|
lnode_t *lnode;
|
|
|
|
EpgConn *conn;
|
2003-12-10 15:09:40 +00:00
|
|
|
|
2003-12-28 07:23:42 +00:00
|
|
|
lnode = list_first(pgconn);
|
|
|
|
while (lnode)
|
2003-12-10 15:09:40 +00:00
|
|
|
{
|
2003-12-28 07:23:42 +00:00
|
|
|
conn = lnode_get(lnode);
|
|
|
|
if (conn->id == connid) {
|
|
|
|
list_delete(pgconn, lnode);
|
|
|
|
lnode_destroy(lnode);
|
|
|
|
free(conn);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
lnode = list_next(pgconn, lnode);
|
2003-12-10 15:09:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************
|
|
|
|
* rta_save(): - Save a table to file. The save format is a
|
|
|
|
* series of UPDATE commands saved in the file specified. The
|
|
|
|
* file is typically read in later and executed one line at a
|
|
|
|
* time.
|
|
|
|
*
|
|
|
|
* Input: ptbl - pointer to the table to be saved
|
|
|
|
* fname - string with name of the save file
|
|
|
|
*
|
|
|
|
* Return: RTA_SUCCESS - table saved
|
|
|
|
* RTA_ERROR - some kind of error
|
|
|
|
**************************************************************/
|
|
|
|
int
|
|
|
|
rta_save(TBLDEF *ptbl, char *fname)
|
|
|
|
{
|
|
|
|
extern struct EpgStat rtastat;
|
|
|
|
int sr; /* the Size of each Row in the table */
|
|
|
|
int rx; /* Row indeX in for() loop */
|
|
|
|
void *pd; /* Pointer to the Data in the table/column */
|
|
|
|
int cx; /* Column index while building Data pkt */
|
|
|
|
char tfile[PATH_MAX];
|
|
|
|
char path[PATH_MAX];
|
|
|
|
int fd; /* file descriptor of temp file */
|
|
|
|
FILE *ftmp; /* FILE handle to the temp file */
|
|
|
|
int did_header; /* == 1 if printed UPDATE part */
|
|
|
|
int did_1_col; /* == 1 if at least one col printed */
|
|
|
|
|
|
|
|
/* Open a temp file in the same directory as the users target file */
|
|
|
|
(void) strncpy(path, fname, PATH_MAX);
|
2004-02-07 23:47:56 +00:00
|
|
|
(void) strncpy(tfile, dirname(path), PATH_MAX);
|
2003-12-10 15:09:40 +00:00
|
|
|
(void) strcat(tfile, "/tmpXXXXXX");
|
|
|
|
fd = mkstemp(tfile);
|
|
|
|
if (fd < 0)
|
|
|
|
{
|
|
|
|
rtastat.nsyserr++;
|
|
|
|
if (rtadbg.syserr)
|
|
|
|
rtalog(LOC, Er_No_Save, tfile);
|
|
|
|
return (RTA_ERROR);
|
|
|
|
}
|
|
|
|
ftmp = fdopen(fd, "w");
|
|
|
|
if (ftmp == (FILE *) 0)
|
|
|
|
{
|
|
|
|
rtastat.nsyserr++;
|
|
|
|
if (rtadbg.syserr)
|
|
|
|
rtalog(LOC, Er_No_Save, tfile);
|
|
|
|
return (RTA_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* OK, temp file is open and ready to receive table data */
|
|
|
|
sr = ptbl->rowlen;
|
|
|
|
|
|
|
|
for (rx = 0; rx < ptbl->nrows; rx++)
|
|
|
|
{
|
|
|
|
did_header = 0;
|
|
|
|
did_1_col = 0;
|
|
|
|
for (cx = 0; cx < ptbl->ncol; cx++)
|
|
|
|
{
|
|
|
|
if (!ptbl->cols[cx].flags & RTA_DISKSAVE)
|
|
|
|
continue;
|
|
|
|
if (!did_header)
|
|
|
|
{
|
|
|
|
fprintf(ftmp, "UPDATE %s SET", ptbl->name);
|
|
|
|
did_header = 1;
|
|
|
|
}
|
|
|
|
if (!did_1_col)
|
|
|
|
fprintf(ftmp, " %s ", ptbl->cols[cx].name);
|
|
|
|
else
|
|
|
|
fprintf(ftmp, ", %s ", ptbl->cols[cx].name);
|
|
|
|
|
|
|
|
/* compute pointer to actual data */
|
|
|
|
pd = ptbl->address + (rx * sr) + ptbl->cols[cx].offset;
|
|
|
|
switch ((ptbl->cols[cx]).type)
|
|
|
|
{
|
|
|
|
case RTA_STR:
|
|
|
|
if (memchr((char *) pd, '"', ptbl->cols[cx].length))
|
|
|
|
fprintf(ftmp, "= \'%s\'", (char *) pd);
|
|
|
|
else
|
|
|
|
fprintf(ftmp, "= \"%s\"", (char *) pd);
|
|
|
|
break;
|
|
|
|
case RTA_PSTR:
|
|
|
|
if (memchr((char *) pd, '"', ptbl->cols[cx].length))
|
|
|
|
fprintf(ftmp, "= \'%s\'", *(char **) pd);
|
|
|
|
else
|
|
|
|
fprintf(ftmp, "= \"%s\"", *(char **) pd);
|
|
|
|
break;
|
|
|
|
case RTA_INT:
|
|
|
|
fprintf(ftmp, "= %d", *((int *) pd));
|
|
|
|
break;
|
|
|
|
case RTA_PINT:
|
|
|
|
fprintf(ftmp, "= %d", **((int **) pd));
|
|
|
|
break;
|
|
|
|
case RTA_LONG:
|
|
|
|
fprintf(ftmp, "= %lld", *((long long *) pd));
|
|
|
|
break;
|
|
|
|
case RTA_PLONG:
|
|
|
|
fprintf(ftmp, "= %lld", **((long long **) pd));
|
|
|
|
break;
|
|
|
|
case RTA_PTR:
|
|
|
|
|
|
|
|
/* works only if INT and PTR are same size */
|
|
|
|
fprintf(ftmp, "= %d", *((int *) pd));
|
|
|
|
break;
|
|
|
|
case RTA_FLOAT:
|
|
|
|
fprintf(ftmp, "= %20.10f", *((float *) pd));
|
|
|
|
break;
|
|
|
|
case RTA_PFLOAT:
|
|
|
|
fprintf(ftmp, "= %20.10f", **((float **) pd));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
did_1_col = 1;
|
|
|
|
}
|
|
|
|
if (did_header)
|
|
|
|
fprintf(ftmp, " LIMIT 1 OFFSET %d\n", rx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Done saving the data. Close the file and rename it to the
|
|
|
|
location the user requested */
|
|
|
|
|
|
|
|
/* (BTW: we use rename() because it is guaranteed to be atomic.
|
|
|
|
Rename() requires that both files be on the same partition; hence
|
|
|
|
our effort to put the temp file in the same directory as the
|
|
|
|
target file.) */
|
|
|
|
(void) fclose(ftmp);
|
|
|
|
if (rename(tfile, fname) != 0)
|
|
|
|
{
|
|
|
|
rtastat.nsyserr++;
|
|
|
|
if (rtadbg.syserr)
|
|
|
|
rtalog(LOC, Er_No_Save, fname);
|
|
|
|
return (RTA_ERROR);
|
|
|
|
}
|
|
|
|
return (RTA_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************
|
|
|
|
* rta_load(): - Load a table from a file of UPDATE commands.
|
|
|
|
*
|
|
|
|
* Input: ptbl - pointer to the table to be loaded
|
|
|
|
* fname - string with name of the load file
|
|
|
|
*
|
|
|
|
* Return: RTA_SUCCESS - table loaded
|
|
|
|
* RTA_ERROR - some kind of error
|
|
|
|
**************************************************************/
|
|
|
|
int
|
|
|
|
rta_load(TBLDEF *ptbl, char *fname)
|
|
|
|
{
|
|
|
|
extern struct EpgStat rtastat;
|
|
|
|
FILE *fp; /* FILE handle to the load file */
|
|
|
|
char *savefilename; /* table's savefile name */
|
|
|
|
char line[MX_LN_SZ]; /* input line from file */
|
|
|
|
char reply[MX_LN_SZ]; /* response from SQL process */
|
|
|
|
int nreply; /* number of free bytes in reply */
|
|
|
|
|
|
|
|
/* We open the load file and read it one line at a time, executing
|
|
|
|
each line that contains "UPDATE" as the first word. (Lines not
|
|
|
|
starting with UPDATE are comments.) Note that any write callbacks
|
|
|
|
associated with the table will be invoked. We hide the table's
|
|
|
|
save file name, if any, in order to prevent the system from trying
|
|
|
|
to save the table before we are done loading it. */
|
|
|
|
fp = fopen(fname, "r");
|
|
|
|
if (fp == (FILE *) 0)
|
|
|
|
{
|
|
|
|
rtastat.nsyserr++;
|
|
|
|
if (rtadbg.syserr)
|
|
|
|
rtalog(LOC, Er_No_Load, fname);
|
|
|
|
return (RTA_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't let the DB try to save changes right now */
|
|
|
|
savefilename = ptbl->savefile;
|
|
|
|
ptbl->savefile = (char *) 0;
|
|
|
|
|
|
|
|
/* process each line in the file */
|
|
|
|
while (fgets(line, MX_LN_SZ, fp))
|
|
|
|
{
|
|
|
|
/* A comment if first word is not "UPDATE " */
|
|
|
|
if (strncmp(line, "UPDATE ", 7))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
nreply = MX_LN_SZ;
|
|
|
|
SQL_string(line, reply, &nreply);
|
|
|
|
if (!strncmp(line, "UPDATE 1", 8))
|
|
|
|
{
|
|
|
|
/* SQL command failed! Report error */
|
|
|
|
rtastat.nsyserr++;
|
|
|
|
if (rtadbg.syserr)
|
|
|
|
rtalog(LOC, Er_No_Load, fname);
|
|
|
|
return (RTA_ERROR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ptbl->savefile = savefilename;
|
|
|
|
|
|
|
|
return (RTA_SUCCESS);
|
|
|
|
}
|