mod_pgsql.c
上传用户:pycemail
上传日期:2007-01-04
资源大小:329k
文件大小:7k
- /*
- * ProFTPD: mod_pgsql -- Support for connecting to postgresql databases.
- * Time-stamp: <1999-10-04 03:22:02 root>
- * Copyright (c) 1999 Johnie Ingram.
- *
- * 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.
- */
- #define MOD_PGSQL_VERSION "mod_pgsql/1.0"
- /* -- DO NOT MODIFY THE LINE BELOW UNLESS YOU FEEL LIKE IT --
- * $Libraries: -lm -lpq $
- */
- /* This is mod_pgsql, contrib software for proftpd 1.2.0pre7 and above.
- For more information contact Johnie Ingram <johnie@netgod.net>.
- History Log:
- * 1999-09-19: v1.0: Initial attempted (modelled off mod_mysql).
- */
- #include "conf.h"
- #include <pgsql/libpq-fe.h>
- /* *INDENT-OFF* */
- static PGconn *conn = 0;
- /* Maximum username field to expect, etc. */
- #define ARBITRARY_MAX 128
- #define MODPG_TTY NULL
- #define MODPG_OPTIONS NULL
- static struct
- {
- char *sql_host; /* Data for connecting, from PostgresInfo. */
- char *sql_user;
- char *sql_pass;
- char *sql_dbname;
- char *sql_dbport;
- char *sql_usertable;
- char *sql_userid;
- char *sql_passwd;
- int ok;
- int opens;
- PGresult *res;
- } g;
- /* *INDENT-ON* */
- /* **************************************************************** */
- MODRET
- sql_cmd_close (cmd_rec * cmd)
- {
- log_debug (DEBUG5, "pgsql: close [%i] for %s", g.opens, cmd->argv[0]);
- if (!g.ok || g.opens--)
- return DECLINED (cmd);
- if (conn)
- {
- log_debug (DEBUG4, "pgsql: disconnecting: %s/%s",
- g.sql_host, g.sql_dbname);
- PQfinish (conn);
- }
- conn = NULL;
- return DECLINED (cmd);
- }
- MODRET
- sql_cmd_open (cmd_rec * cmd)
- {
- if (!g.ok)
- return DECLINED (cmd);
- g.opens++;
- log_debug (DEBUG5, "pgsql: open [%i] for %s", g.opens, cmd->argv[0]);
- if (g.opens > 1)
- return HANDLED (cmd);
- if (g.sql_user)
- conn = PQsetdbLogin (g.sql_host, g.sql_dbport, MODPG_OPTIONS, MODPG_TTY,
- g.sql_dbname, g.sql_user, g.sql_pass);
- else
- conn = PQsetdb (g.sql_host, g.sql_dbport, MODPG_OPTIONS, MODPG_TTY,
- g.sql_dbname);
- if (PQstatus (conn) == CONNECTION_BAD)
- {
- log_pri (LOG_ERR, "pgsql: connect FAILED to %s/%s",
- g.sql_host, g.sql_dbname);
- PQfinish (conn);
- g.ok = FALSE;
- conn = NULL;
- g.opens = 0;
- return DECLINED (cmd);
- }
- log_debug (DEBUG5, "pgsql: connect OK (%s/%s)", g.sql_host, g.sql_dbname);
- return HANDLED (cmd);
- }
- MODRET
- _do_query (cmd_rec * cmd, const char *query, int update)
- {
- PGnotify *not;
- if (!g.ok)
- return DECLINED (cmd);
- block_signals ();
- PQconsumeInput (conn);
- while ((not = PQnotifies (conn)) != NULL)
- {
- log_pri (DEBUG3, "pgsql: async NOTIFY of '%s' from backend pid '%d'",
- not->relname, not->be_pid);
- free (not);
- }
- g.res = PQexec (conn, query);
- if (!g.res || PQstatus (conn) == CONNECTION_BAD)
- {
- /* We need to restart the server link. */
- if (conn)
- log_pri (LOG_ERR, "pgsql: server has wandered off (%s/%s)",
- g.sql_host, g.sql_dbname);
- sql_cmd_open (cmd);
- if (!conn)
- return DECLINED (cmd);
- g.res = PQexec (conn, query);
- }
- unblock_signals ();
- if (update)
- {
- if (PQresultStatus (g.res) != PGRES_COMMAND_OK)
- {
- /* Absorb the ugly newline. */
- char errbuf[ARBITRARY_MAX];
- sstrncpy (errbuf, PQerrorMessage (conn), sizeof(errbuf));
- log_debug (DEBUG4, "pgsql: update failed: "%s": %s",
- query, errbuf);
- return DECLINED (cmd);
- }
- }
- else
- {
- if (PQresultStatus (g.res) != PGRES_TUPLES_OK)
- {
- log_debug (DEBUG4, "pgsql: select failed: "%s": %s",
- query, PQerrorMessage (conn));
- return DECLINED (cmd);
- }
- }
- log_debug (DEBUG5, "pgsql: %s OK: [%s] "%s"",
- (update) ? "update" : "select", g.sql_dbname, query);
- return HANDLED (cmd);
- }
- MODRET
- sql_cmd_update (cmd_rec * cmd)
- {
- MODRET mr;
- mr = _do_query (cmd, cmd->argv[1], TRUE);
- PQclear (g.res);
- return mr;
- }
- MODRET
- sql_cmd_select (cmd_rec * cmd)
- {
- MODRET mr;
- int i, j;
- mr = _do_query (cmd, cmd->argv[1], FALSE);
- if (!MODRET_ISHANDLED (mr))
- return DECLINED (mr);
- if (PQresultStatus (g.res) == PGRES_TUPLES_OK)
- {
- int tcount = PQntuples (g.res);
- int fcount = PQnfields (g.res);
- int count = tcount * fcount;
- char **data = pcalloc (cmd->tmp_pool, sizeof (char *) * (count + 1));
- count = 0;
- /* Huh? j - 1? whatever.... */
- for (i = 0; i < tcount; i++)
- {
- for (j = 0; j < fcount; j++)
- {
- data[count++] = pstrdup (cmd->tmp_pool,
- PQgetvalue (g.res, i, j));
- }
- }
- data[count] = NULL;
- mr->data = data;
- }
- PQclear (g.res);
- return mr;
- }
- static authtable pgsql_authtab[] = {
- {0, "dbd_open", sql_cmd_open},
- {0, "dbd_close", sql_cmd_close},
- {0, "dbd_update", sql_cmd_update},
- {0, "dbd_select", sql_cmd_select},
- {0, NULL, NULL}
- };
- /* **************************************************************** */
- MODRET set_sqlinfo (cmd_rec * cmd)
- {
- CHECK_CONF (cmd, CONF_ROOT | CONF_GLOBAL | CONF_VIRTUAL);
- switch (cmd->argc - 1)
- {
- default:
- CONF_ERROR (cmd, "requires 2 or 4 items: " "host [user pass] dbname");
- case 2:
- add_config_param_str ("PostgresInfo", 4,
- (void *) cmd->argv[1], 0, 0,
- (void *) cmd->argv[2]);
- break;
- case 4:
- add_config_param_str ("PostgresInfo", 4,
- (void *) cmd->argv[1], (void *) cmd->argv[2],
- (void *) cmd->argv[3], (void *) cmd->argv[4]);
- }
- return HANDLED (cmd);
- }
- MODRET
- add_globalstr (cmd_rec * cmd)
- {
- CHECK_ARGS (cmd, 1);
- CHECK_CONF (cmd, CONF_ROOT | CONF_GLOBAL | CONF_VIRTUAL);
- add_config_param_str (cmd->argv[0], 1, (void *) cmd->argv[1]);
- return HANDLED (cmd);
- }
- static conftable pgsql_conftab[] = {
- /* *INDENT-OFF* */
- { "PostgresInfo", set_sqlinfo, NULL },
- { "PostgresPort", add_globalstr, NULL },
- { 0, NULL }
- /* *INDENT-ON* */
- };
- /* **************************************************************** */
- static int
- pgsql_modinit ()
- {
- config_rec *c;
- memset (&g, 0, sizeof (g));
- if (!(c = find_config (CURRENT_CONF, CONF_PARAM, "PostgresInfo", FALSE)))
- return 0;
- /* Default left at 0 for unix socket. */
- g.sql_dbport = get_param_ptr (CURRENT_CONF, "PostgresPort", FALSE);
- g.sql_host = pstrdup (session.pool, c->argv[0]);
- g.sql_user = pstrdup (session.pool, c->argv[1]);
- g.sql_pass = pstrdup (session.pool, c->argv[2]);
- g.sql_dbname = pstrdup (session.pool, c->argv[3]);
- g.ok = TRUE;
- log_debug (DEBUG5, "%s: configured: db %s at %s port %s",
- MOD_PGSQL_VERSION, g.sql_dbname, g.sql_host, g.sql_dbport);
- return 0;
- }
- module pgsql_module = {
- NULL, NULL, /* Always NULL */
- 0x20, /* API Version 2.0 */
- "pgsql",
- pgsql_conftab, /* SQL configuration handler table */
- NULL, /* SQL command handler table */
- pgsql_authtab, /* SQL authentication handler table */
- pgsql_modinit, /* Pre-fork "parent-mode" init */
- pgsql_modinit /* Post-fork "child mode" init */
- };