mod_pgsql.c
上传用户:pycemail
上传日期:2007-01-04
资源大小:329k
文件大小:7k
源码类别:

Ftp客户端

开发平台:

Unix_Linux

  1. /*
  2.  * ProFTPD: mod_pgsql -- Support for connecting to postgresql databases.
  3.  * Time-stamp: <1999-10-04 03:22:02 root>
  4.  * Copyright (c) 1999 Johnie Ingram.
  5.  *  
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
  19.  */
  20. #define MOD_PGSQL_VERSION "mod_pgsql/1.0"
  21. /* -- DO NOT MODIFY THE LINE BELOW UNLESS YOU FEEL LIKE IT --
  22.  * $Libraries: -lm -lpq $
  23.  */
  24. /* This is mod_pgsql, contrib software for proftpd 1.2.0pre7 and above.
  25.    For more information contact Johnie Ingram <johnie@netgod.net>.
  26.    History Log:
  27.    * 1999-09-19: v1.0: Initial attempted (modelled off mod_mysql).
  28. */
  29. #include "conf.h"
  30. #include <pgsql/libpq-fe.h>
  31. /* *INDENT-OFF* */
  32. static PGconn *conn = 0;
  33. /* Maximum username field to expect, etc. */
  34. #define ARBITRARY_MAX                   128
  35. #define MODPG_TTY NULL
  36. #define MODPG_OPTIONS NULL
  37. static struct
  38. {
  39.   char *sql_host; /* Data for connecting, from PostgresInfo. */
  40.   char *sql_user;
  41.   char *sql_pass;
  42.   char *sql_dbname;
  43.   char *sql_dbport;
  44.   char *sql_usertable;
  45.   char *sql_userid;
  46.   char *sql_passwd;
  47.   int ok;
  48.   int opens;
  49.   PGresult *res;
  50. } g;
  51. /* *INDENT-ON* */
  52. /* **************************************************************** */
  53. MODRET
  54. sql_cmd_close (cmd_rec * cmd)
  55. {
  56.   log_debug (DEBUG5, "pgsql: close [%i] for %s", g.opens, cmd->argv[0]);
  57.   if (!g.ok || g.opens--)
  58.     return DECLINED (cmd);
  59.   if (conn)
  60.     {
  61.       log_debug (DEBUG4, "pgsql: disconnecting: %s/%s",
  62.  g.sql_host, g.sql_dbname);
  63.       PQfinish (conn);
  64.     }
  65.   conn = NULL;
  66.   return DECLINED (cmd);
  67. }
  68. MODRET
  69. sql_cmd_open (cmd_rec * cmd)
  70. {
  71.   if (!g.ok)
  72.     return DECLINED (cmd);
  73.   g.opens++;
  74.   log_debug (DEBUG5, "pgsql: open [%i] for %s", g.opens, cmd->argv[0]);
  75.   if (g.opens > 1)
  76.     return HANDLED (cmd);
  77.   if (g.sql_user)
  78.     conn = PQsetdbLogin (g.sql_host, g.sql_dbport, MODPG_OPTIONS, MODPG_TTY,
  79.  g.sql_dbname, g.sql_user, g.sql_pass);
  80.   else
  81.     conn = PQsetdb (g.sql_host, g.sql_dbport, MODPG_OPTIONS, MODPG_TTY,
  82.     g.sql_dbname);
  83.   if (PQstatus (conn) == CONNECTION_BAD)
  84.     {
  85.       log_pri (LOG_ERR, "pgsql: connect FAILED to %s/%s",
  86.        g.sql_host, g.sql_dbname);
  87.       PQfinish (conn);
  88.       g.ok = FALSE;
  89.       conn = NULL;
  90.       g.opens = 0;
  91.       return DECLINED (cmd);
  92.     }
  93.   log_debug (DEBUG5, "pgsql: connect OK (%s/%s)", g.sql_host, g.sql_dbname);
  94.   return HANDLED (cmd);
  95. }
  96. MODRET
  97. _do_query (cmd_rec * cmd, const char *query, int update)
  98. {
  99.   PGnotify *not;
  100.   if (!g.ok)
  101.     return DECLINED (cmd);
  102.   block_signals ();
  103.   PQconsumeInput (conn);
  104.   while ((not = PQnotifies (conn)) != NULL)
  105.     {
  106.       log_pri (DEBUG3, "pgsql: async NOTIFY of '%s' from backend pid '%d'",
  107.        not->relname, not->be_pid);
  108.       free (not);
  109.     }
  110.   g.res = PQexec (conn, query);
  111.   if (!g.res || PQstatus (conn) == CONNECTION_BAD)
  112.     {
  113.       /* We need to restart the server link. */
  114.       if (conn)
  115. log_pri (LOG_ERR, "pgsql: server has wandered off (%s/%s)",
  116.  g.sql_host, g.sql_dbname);
  117.       sql_cmd_open (cmd);
  118.       if (!conn)
  119. return DECLINED (cmd);
  120.       g.res = PQexec (conn, query);
  121.     }
  122.   unblock_signals ();
  123.   if (update)
  124.     {
  125.       if (PQresultStatus (g.res) != PGRES_COMMAND_OK)
  126. {
  127.   /* Absorb the ugly newline. */
  128.   char errbuf[ARBITRARY_MAX];
  129.   sstrncpy (errbuf, PQerrorMessage (conn), sizeof(errbuf));
  130.   log_debug (DEBUG4, "pgsql: update failed: "%s": %s",
  131.      query, errbuf);
  132.   return DECLINED (cmd);
  133. }
  134.     }
  135.   else
  136.     {
  137.       if (PQresultStatus (g.res) != PGRES_TUPLES_OK)
  138. {
  139.   log_debug (DEBUG4, "pgsql: select failed: "%s": %s",
  140.      query, PQerrorMessage (conn));
  141.   return DECLINED (cmd);
  142. }
  143.     }
  144.   log_debug (DEBUG5, "pgsql: %s OK: [%s] "%s"",
  145.      (update) ? "update" : "select", g.sql_dbname, query);
  146.   return HANDLED (cmd);
  147. }
  148. MODRET
  149. sql_cmd_update (cmd_rec * cmd)
  150. {
  151.   MODRET mr;
  152.   mr = _do_query (cmd, cmd->argv[1], TRUE);
  153.   PQclear (g.res);
  154.   return mr;
  155. }
  156. MODRET
  157. sql_cmd_select (cmd_rec * cmd)
  158. {
  159.   MODRET mr;
  160.   int i, j;
  161.   mr = _do_query (cmd, cmd->argv[1], FALSE);
  162.   if (!MODRET_ISHANDLED (mr))
  163.     return DECLINED (mr);
  164.   if (PQresultStatus (g.res) == PGRES_TUPLES_OK)
  165.     {
  166.       int tcount = PQntuples (g.res);
  167.       int fcount = PQnfields (g.res);
  168.       int count = tcount * fcount;
  169.       char **data = pcalloc (cmd->tmp_pool, sizeof (char *) * (count + 1));
  170.       count = 0;
  171.       /* Huh? j - 1? whatever.... */
  172.       for (i = 0; i < tcount; i++)
  173. {
  174.   for (j = 0; j < fcount; j++)
  175.     {
  176.       data[count++] = pstrdup (cmd->tmp_pool,
  177.        PQgetvalue (g.res, i, j));
  178.     }
  179. }
  180.       data[count] = NULL;
  181.       mr->data = data;
  182.     }
  183.   PQclear (g.res);
  184.   return mr;
  185. }
  186. static authtable pgsql_authtab[] = {
  187.   {0, "dbd_open", sql_cmd_open},
  188.   {0, "dbd_close", sql_cmd_close},
  189.   {0, "dbd_update", sql_cmd_update},
  190.   {0, "dbd_select", sql_cmd_select},
  191.   {0, NULL, NULL}
  192. };
  193. /* **************************************************************** */
  194. MODRET set_sqlinfo (cmd_rec * cmd)
  195. {
  196.   CHECK_CONF (cmd, CONF_ROOT | CONF_GLOBAL | CONF_VIRTUAL);
  197.   switch (cmd->argc - 1)
  198.     {
  199.     default:
  200.       CONF_ERROR (cmd, "requires 2 or 4 items: " "host [user pass] dbname");
  201.     case 2:
  202.       add_config_param_str ("PostgresInfo", 4,
  203.     (void *) cmd->argv[1], 0, 0,
  204.     (void *) cmd->argv[2]);
  205.       break;
  206.     case 4:
  207.       add_config_param_str ("PostgresInfo", 4,
  208.     (void *) cmd->argv[1], (void *) cmd->argv[2],
  209.     (void *) cmd->argv[3], (void *) cmd->argv[4]);
  210.     }
  211.   return HANDLED (cmd);
  212. }
  213. MODRET
  214. add_globalstr (cmd_rec * cmd)
  215. {
  216.   CHECK_ARGS (cmd, 1);
  217.   CHECK_CONF (cmd, CONF_ROOT | CONF_GLOBAL | CONF_VIRTUAL);
  218.   add_config_param_str (cmd->argv[0], 1, (void *) cmd->argv[1]);
  219.   return HANDLED (cmd);
  220. }
  221. static conftable pgsql_conftab[] = {
  222. /* *INDENT-OFF* */
  223.   { "PostgresInfo",              set_sqlinfo,       NULL },
  224.   { "PostgresPort",              add_globalstr,     NULL },
  225.   { 0,       NULL }
  226. /* *INDENT-ON* */
  227. };
  228. /* **************************************************************** */
  229. static int
  230. pgsql_modinit ()
  231. {
  232.   config_rec *c;
  233.   memset (&g, 0, sizeof (g));
  234.   if (!(c = find_config (CURRENT_CONF, CONF_PARAM, "PostgresInfo", FALSE)))
  235.     return 0;
  236.   /* Default left at 0 for unix socket. */
  237.   g.sql_dbport = get_param_ptr (CURRENT_CONF, "PostgresPort", FALSE);
  238.   g.sql_host = pstrdup (session.pool, c->argv[0]);
  239.   g.sql_user = pstrdup (session.pool, c->argv[1]);
  240.   g.sql_pass = pstrdup (session.pool, c->argv[2]);
  241.   g.sql_dbname = pstrdup (session.pool, c->argv[3]);
  242.   g.ok = TRUE;
  243.   log_debug (DEBUG5, "%s: configured: db %s at %s port %s",
  244.      MOD_PGSQL_VERSION, g.sql_dbname, g.sql_host, g.sql_dbport);
  245.   return 0;
  246. }
  247. module pgsql_module = {
  248.   NULL, NULL, /* Always NULL */
  249.   0x20, /* API Version 2.0 */
  250.   "pgsql",
  251.   pgsql_conftab, /* SQL configuration handler table */
  252.   NULL, /* SQL command handler table */
  253.   pgsql_authtab, /* SQL authentication handler table */
  254.   pgsql_modinit, /* Pre-fork "parent-mode" init */
  255.   pgsql_modinit /* Post-fork "child mode" init */
  256. };