source: npl/mailserver/dspam/dspam-3.10.2/src/tools.pgsql_drv/dspam_pg2int8.c

Last change on this file was c5c522c, checked in by Edwin Eefting <edwin@datux.nl>, 8 years ago

initial commit, transferred from cleaned syn3 svn tree

  • Property mode set to 100644
File size: 10.5 KB
Line 
1/* $Id: dspam_pg2int8.c,v 1.15 2011/06/28 00:13:48 sbajic Exp $ */
2
3/*
4 DSPAM
5 COPYRIGHT (C) 2002-2012 DSPAM PROJECT
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Affero General Public License as
9 published by the Free Software Foundation, either version 3 of the
10 License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU Affero General Public License for more details.
16
17 You should have received a copy of the GNU Affero General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20*/
21
22#ifdef HAVE_CONFIG_H
23#include <auto-config.h>
24#endif
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <fcntl.h>
30#include <dirent.h>
31#include <ctype.h>
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <errno.h>
35#include <pwd.h>
36#include <signal.h>
37
38#include "libdspam.h"
39#include "util.h"
40#include "read_config.h"
41#include "config_api.h"
42#include "language.h"
43#include "storage_driver.h"
44#include "pgsql_drv.h"
45
46DSPAM_CTX *open_ctx, *open_mtx;
47
48int opt_humanfriendly;
49
50void dieout (int signal);
51void usage (void);
52void GenSQL (PGconn *dbh,const char *file);
53void OutputMessage(DSPAM_CTX *open_ctx,char *sqlfile);
54
55#ifndef PATH_MAX
56# define PATH_MAX 1024
57#endif
58
59/*
60** Type OIDs; values come from postgresql/include/server/catalog/pg_type.h
61*/
62
63#ifndef NUMERICOID
64# define NUMERICOID 1700
65#endif
66#ifndef INT8OID
67# define INT8OID    20
68#endif
69#define BIGINTOID   INT8OID
70
71int
72main (int argc, char **argv)
73{
74#ifndef _WIN32
75#ifdef TRUSTED_USER_SECURITY
76  struct passwd *p = getpwuid (getuid ());
77#endif
78#endif
79  struct _pgsql_drv_storage *store;
80  char file[PATH_MAX+1];
81  int i, ch;
82#ifndef HAVE_GETOPT
83  int optind = 1;
84#endif
85
86  /* Read dspam.conf */
87
88  agent_config = read_config(NULL);
89  if (!agent_config) {
90    LOG(LOG_ERR, ERR_AGENT_READ_CONFIG);
91    exit(EXIT_FAILURE);
92  }
93
94  if (!_ds_read_attribute(agent_config, "Home")) {
95    LOG(LOG_ERR, ERR_AGENT_DSPAM_HOME);
96    _ds_destroy_config(agent_config);
97    exit(EXIT_FAILURE);
98  }
99
100#ifndef _WIN32
101#ifdef TRUSTED_USER_SECURITY
102  if (!_ds_match_attribute(agent_config, "Trust", p->pw_name) && p->pw_uid) {
103    fprintf(stderr, ERR_TRUSTED_MODE "\n");
104    _ds_destroy_config(agent_config);
105    exit(EXIT_FAILURE);
106  }
107#endif
108#endif
109
110  for(i=0;i<argc;i++) {
111                                                                               
112    if (!strncmp (argv[i], "--profile=", 10))
113    {
114      if (!_ds_match_attribute(agent_config, "Profile", argv[i]+10)) {
115        LOG(LOG_ERR, ERR_AGENT_NO_SUCH_PROFILE, argv[i]+10);
116        _ds_destroy_config(agent_config);
117        exit(EXIT_FAILURE);
118      } else {
119        _ds_overwrite_attribute(agent_config, "DefaultProfile", argv[i]+10);
120      }
121      break;
122    }
123  }
124
125  open_ctx = open_mtx = NULL;
126
127  signal (SIGINT, dieout);
128  signal (SIGPIPE, dieout);
129  signal (SIGTERM, dieout);
130
131  /* Process command line */
132  ch = 0;
133#ifdef HAVE_GETOPT
134  while((ch = getopt(argc, argv, "h")) != -1)
135#else
136  while ( argv[optind] &&
137            argv[optind][0] == '-' &&
138              (ch = argv[optind][1]) &&
139                argv[optind][2] == '\0' )
140#endif
141  {
142    switch(ch) {
143      case 'h':
144        /* print help, and then exit. usage exits for us */
145        usage();
146        break;
147
148#ifndef HAVE_GETOPT
149      default:
150        fprintf(stderr, "%s: unknown option \"%s\".\n",
151                argv[0], argv[optind] + 1);
152        usage();
153#endif
154    }
155#ifndef HAVE_GETOPT
156    optind++;
157#endif
158  }
159  /* reset our option array and index to where we are after getopt */
160  argv += optind;
161  argc -= optind;
162
163  if (argc == 0) {
164    fprintf(stderr,"Must specify an output file\n");
165    usage();
166  }
167
168  memset((void *)file, 0, PATH_MAX+1);
169  strncpy(file, argv[0], PATH_MAX);
170
171  open_ctx = dspam_create(NULL,NULL,_ds_read_attribute(agent_config, "Home"), DSM_TOOLS, 0);
172  if (open_ctx == NULL) {
173    fprintf(stderr, "Could not initialize context: %s\n", strerror (errno));
174    exit(EXIT_FAILURE);
175  }
176
177  set_libdspam_attributes(open_ctx);
178  if (dspam_attach(open_ctx, NULL)) {
179    fprintf(stderr,"Failed to init link to PostgreSQL\n");
180    dspam_destroy(open_ctx);
181    exit(EXIT_FAILURE);
182  }
183 
184  store = (struct _pgsql_drv_storage *)(open_ctx->storage);
185  GenSQL(store->dbh,file);
186  //PQfinish(store->dbh);
187
188  OutputMessage(open_ctx,file);
189
190  if (open_ctx != NULL)
191    dspam_destroy (open_ctx);
192  if (open_mtx != NULL)
193    dspam_destroy (open_mtx);
194  _ds_destroy_config(agent_config);
195  exit (EXIT_SUCCESS);
196}
197
198#define TOKEN_TYPE_LEN 20
199#define TOKEN_DATA_LEN 30
200
201void
202GenSQL (PGconn *dbh,const char *file)
203{
204  int i,ntuples;
205  int reverse=0;
206  int type_check=0;
207  int preamble=0;
208  PGresult *result;
209  Oid col_type;
210  FILE *out;
211  char token_data[TOKEN_DATA_LEN+1];
212  char token_type[TOKEN_TYPE_LEN+1];
213  unsigned long long token;
214  memset((void *)token_type, 0, TOKEN_TYPE_LEN+1);
215  memset((void *)token_data, 0, TOKEN_DATA_LEN+1);
216
217  if (strncmp(file,"-",1)==0) {
218    out=stdout;
219  } else {
220    if ( (out = fopen(file,"w+")) == NULL ) {
221      fprintf(stderr, "Failed to open file %s for writing - %s\n",
222              file, strerror(errno));
223      PQfinish(dbh);
224      exit(EXIT_FAILURE);
225    }
226  }
227  result = PQexec(dbh, "SELECT uid, token, spam_hits, innocent_hits, last_hit "
228                       "FROM dspam_token_data");
229  if (! result || PQresultStatus(result) != PGRES_TUPLES_OK) {
230    fprintf(stderr, "Failed to run result: %s\n", PQresultErrorMessage(result));
231    if (result) PQclear(result);
232    PQfinish(dbh);
233    fclose (out);
234    exit(EXIT_FAILURE);
235  }
236
237  ntuples = PQntuples(result);
238  for (i=0; i<ntuples; i++)
239  {
240    if (!type_check)
241    {
242      type_check = 1;
243      col_type = PQftype(result, 1);
244
245      if (col_type == BIGINTOID)
246      {
247        fprintf(stderr, "Datatype of dspam_token_data.token *not* NUMERIC;\n"
248           "assuming that you want to revert back to NUMERIC(20) type from BIGINT type\n");
249        reverse=1;
250      } else if (col_type != NUMERICOID)
251      {
252        fprintf(stderr, "Type of dspam_token_data.token is not BIGINT *or* NUMERIC(20)!\n"
253           "I have got no clue of how to deal with this and I am going to sulk now.\n");
254        if (result) PQclear(result);
255        PQfinish(dbh);
256        fclose (out);
257        exit(EXIT_FAILURE);
258      }
259    }
260    if (!preamble)
261    {
262      preamble = 1;
263      if (reverse == 0) {
264        snprintf(token_type, TOKEN_TYPE_LEN, "bigint");
265      } else {
266        snprintf(token_type, TOKEN_TYPE_LEN, "numeric(20)");
267      }
268      fprintf(out,"BEGIN;\n"
269                  "DROP TABLE dspam_token_data;\n"
270                  "COMMIT;\n"
271                  "BEGIN;\n"
272                  "CREATE TABLE dspam_token_data (\n"
273                  "  uid smallint,\n"
274                  "  token %s,\n"
275                  "  spam_hits int,\n"
276                  "  innocent_hits int,\n"
277                  "  last_hit date,\n"
278                  "  UNIQUE (token, uid)\n"
279                  ") WITHOUT OIDS;\n"
280                  "COMMIT;\n"
281                  "BEGIN;\n"
282                  "COPY dspam_token_data (uid,token,spam_hits,innocent_hits,last_hit) FROM stdin;\n"
283                  , token_type);
284    }
285    if (!reverse) {
286      token = strtoull( PQgetvalue(result,i,1), NULL, 0);
287      snprintf(token_data, TOKEN_DATA_LEN, "%lld", token);
288    } else {
289      token = (unsigned long long) strtoll( PQgetvalue(result,i,1), NULL, 0);
290      snprintf(token_data, TOKEN_DATA_LEN, "%llu", token);
291    }
292    fprintf(out,"%s\t%s\t%s\t%s\t%s\n",
293                PQgetvalue(result,i,0), token_data,
294                PQgetvalue(result,i,2),
295                PQgetvalue(result,i,3),
296                PQgetvalue(result,i,4) );
297  }
298  if (result) PQclear(result);
299  fprintf(out, "\\.\n\n"
300               "COMMIT;\n"
301               "BEGIN;\n"
302               "CREATE INDEX id_token_data_03 ON dspam_token_data(token);\n"
303               "CREATE INDEX id_token_data_04 ON dspam_token_data(uid);\n"
304               "COMMIT;\n"
305               "ANALYSE;\n");
306  fclose (out);
307}
308
309/*
310** Code taken from pgsql_drv.c
311*/
312void OutputMessage(DSPAM_CTX *open_ctx,char *sqlfile)
313{
314  FILE *file;
315  char filename[MAX_FILENAME_LENGTH];
316  char buffer[256];
317  char hostname[128] = "";
318  char user[64] = "";
319  char db[64] = "";
320  int port = 5432, i = 0;
321  if (_ds_read_attribute(open_ctx->config->attributes, "PgSQLServer")) {
322    char *p;
323
324    strlcpy(hostname,
325           _ds_read_attribute(open_ctx->config->attributes, "PgSQLServer"),
326            sizeof(hostname));
327
328    if (_ds_read_attribute(open_ctx->config->attributes, "PgSQLPort"))
329      port = atoi(_ds_read_attribute(open_ctx->config->attributes, "PgSQLPort"));
330    else
331      port = 0;
332
333    if ((p = _ds_read_attribute(open_ctx->config->attributes, "PgSQLUser")))
334      strlcpy(user, p, sizeof(user));
335    if ((p = _ds_read_attribute(open_ctx->config->attributes, "PgSQLDb")))
336      strlcpy(db, p, sizeof(db));
337
338  } else {
339    snprintf (filename, MAX_FILENAME_LENGTH, "%s/pgsql.data", open_ctx->home);
340    file = fopen (filename, "r");
341    if (file == NULL)
342    {
343      fprintf(stderr, "Failed to open config file %s - %s\n",
344              filename, strerror(errno));
345      dieout(0);
346    }
347 
348    db[0] = 0;
349 
350    while (fgets (buffer, sizeof (buffer), file) != NULL)
351    {
352      chomp (buffer);
353      if (!i)
354        strlcpy (hostname, buffer, sizeof (hostname));
355      else if (i == 1)
356        port = atoi (buffer);
357      else if (i == 2)
358        strlcpy (user, buffer, sizeof (user));
359      else if (i == 4)
360        strlcpy (db, buffer, sizeof (db));
361      i++;
362    }
363    fclose (file);
364  }
365
366  if (db[0] == 0)
367  {
368    fprintf(stderr, "file %s: incomplete pgsql connect data", filename);
369    dieout(0);
370  }
371
372  if (port == 0) port = 5432;
373
374  fprintf(stderr, "Created SQL in %s; run using:\n", sqlfile);
375 
376  if ( strlen(hostname) == 0 )
377    fprintf(stderr, "\tpsql -q -p %d -U %s -d %s -f %s -v AUTOCOMMIT=off\n",
378                    port, user, db, sqlfile);
379  else
380    fprintf(stderr, "\tpsql -q -h %s -p %d -U %s -d %s -f %s -v AUTOCOMMIT=off\n",
381                    hostname, port, user, db, sqlfile);
382
383}
384
385void
386dieout (int signal)
387{
388  fprintf (stderr, "terminated.\n");
389  if (open_ctx != NULL)
390    dspam_destroy (open_ctx);
391  if (open_mtx != NULL)
392    dspam_destroy (open_mtx);
393  _ds_destroy_config(agent_config);
394  exit (EXIT_SUCCESS);
395}
396
397void
398usage (void)
399{
400  (void)fprintf (stderr, "Usage: dspam_pg2int8 [-h] file\n"
401      "\tCreates SQL file to migrate from NUMERIC to BIGINT type and vice-versa in PostgreSQL.\n"
402      "\t-h: print this message\n");
403  _ds_destroy_config(agent_config);
404  exit(EXIT_FAILURE);
405}
406
Note: See TracBrowser for help on using the repository browser.