]> jfr.im git - solanum.git/blame - bandb/bantool.c
librb: fix socklen_t check
[solanum.git] / bandb / bantool.c
CommitLineData
832ed81a
AC
1/**
2 * ircd-ratbox: A slightly useful ircd.
3 * bantool.c: The ircd-ratbox database managment tool.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2008 ircd-ratbox development team
8 * Copyright (C) 2008 Daniel J Reidy <dubkat@gmail.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 * USA
24 *
832ed81a
AC
25 * The following server admins have either contributed various configs to test against,
26 * or helped with debugging and feature requests. Many thanks to them.
27 * stevoo / efnet.port80.se
28 * AndroSyn / irc2.choopa.net, irc.igs.ca
29 * Salvation / irc.blessed.net
30 * JamesOff / efnet.demon.co.uk
31 *
32 * Thanks to AndroSyn for challenging me to learn C on the fly :)
33 * BUGS Direct Question, Bug Reports, and Feature Requests to #ratbox on EFnet.
34 * BUGS Complaints >/dev/null
35 *
36 */
37
832ed81a
AC
38#include <stdio.h>
39#include <stdlib.h>
40#include <time.h>
41
42#include "stdinc.h"
a18e9931 43#include "common.h"
832ed81a
AC
44#include "rsdb.h"
45
46#define EmptyString(x) ((x == NULL) || (*(x) == '\0'))
47#define CheckEmpty(x) EmptyString(x) ? "" : x
48
49#define BT_VERSION "0.4.1"
50
51typedef enum
52{
53 BANDB_KLINE,
54 BANDB_KLINE_PERM,
55 BANDB_DLINE,
56 BANDB_DLINE_PERM,
57 BANDB_XLINE,
58 BANDB_XLINE_PERM,
59 BANDB_RESV,
60 BANDB_RESV_PERM,
61 LAST_BANDB_TYPE
62} bandb_type;
63
64
65static char bandb_letter[LAST_BANDB_TYPE] = {
66 'K', 'K', 'D', 'D', 'X', 'X', 'R', 'R'
67};
68
69static const char *bandb_table[LAST_BANDB_TYPE] = {
70 "kline", "kline", "dline", "dline", "xline", "xline", "resv", "resv"
71};
72
73static const char *bandb_suffix[LAST_BANDB_TYPE] = {
74 "", ".perm",
75 "", ".perm",
76 "", ".perm",
77 "", ".perm"
78};
79
80static char me[PATH_MAX];
81
82/* *INDENT-OFF* */
83/* report counters */
84struct counter
85{
86 unsigned int klines;
87 unsigned int dlines;
88 unsigned int xlines;
89 unsigned int resvs;
90 unsigned int error;
91} count = {0, 0, 0, 0, 0};
92
93/* flags set by command line options */
94struct flags
95{
96 int none;
97 int export;
98 int import;
99 int verify;
100 int vacuum;
101 int pretend;
102 int verbose;
103 int wipe;
104 int dupes_ok;
105} flag = {YES, NO, NO, NO, NO, NO, NO, NO, NO};
106/* *INDENT-ON* */
107
108static int table_has_rows(const char *table);
109static int table_exists(const char *table);
110
111static const char *clean_gecos_field(const char *gecos);
112static char *bt_smalldate(const char *string);
113static char *getfield(char *newline);
114static char *strip_quotes(const char *string);
115static char *mangle_reason(const char *string);
116static char *escape_quotes(const char *string);
117
118static void db_error_cb(const char *errstr);
119static void db_reclaim_slack(void);
120static void export_config(const char *conf, int id);
121static void import_config(const char *conf, int id);
122static void check_schema(void);
123static void print_help(int i_exit);
124static void wipe_schema(void);
125static void drop_dupes(const char *user, const char *host, const char *t);
126
127/**
55abcbb2 128 * swing your pants
832ed81a
AC
129 */
130int
131main(int argc, char *argv[])
132{
133 char etc[PATH_MAX];
134 char conf[PATH_MAX];
135 int opt;
136 int i;
137
138 rb_strlcpy(me, argv[0], sizeof(me));
139
140 while((opt = getopt(argc, argv, "hieuspvwd")) != -1)
141 {
142 switch (opt)
143 {
144 case 'h':
145 print_help(EXIT_SUCCESS);
146 break;
147 case 'i':
148 flag.none = NO;
149 flag.import = YES;
150 break;
151 case 'e':
152 flag.none = NO;
153 flag.export = YES;
154 break;
155 case 'u':
156 flag.none = NO;
157 flag.verify = YES;
158 break;
159 case 's':
160 flag.none = NO;
161 flag.vacuum = YES;
162 break;
163 case 'p':
164 flag.pretend = YES;
165 break;
166 case 'v':
167 flag.verbose = YES;
168 break;
169 case 'w':
170 flag.wipe = YES;
171 break;
172 case 'd':
173 flag.dupes_ok = YES;
174 break;
175 default: /* '?' */
176 print_help(EXIT_FAILURE);
177 }
178 }
179
180 /* they should really read the help. */
181 if(flag.none)
182 print_help(EXIT_FAILURE);
183
184 if((flag.import && flag.export) || (flag.export && flag.wipe)
185 || (flag.verify && flag.pretend) || (flag.export && flag.pretend))
186 {
187 fprintf(stderr, "* Error: Conflicting flags.\n");
188 if(flag.export && flag.pretend)
189 fprintf(stderr, "* There is nothing to 'pretend' when exporting.\n");
190
191 fprintf(stderr, "* For an explination of commands, run: %s -h\n", me);
192 exit(EXIT_FAILURE);
193 }
194
195 if(argv[optind] != NULL)
196 rb_strlcpy(etc, argv[optind], sizeof(etc));
197 else
198 rb_strlcpy(etc, ETCPATH, sizeof(ETCPATH));
199
200 fprintf(stdout,
5c5d0fb7 201 "* charybdis bantool v.%s\n", BT_VERSION);
832ed81a
AC
202
203 if(flag.pretend == NO)
204 {
205 if(rsdb_init(db_error_cb) == -1)
206 {
207 fprintf(stderr, "* Error: Unable to open database\n");
208 exit(EXIT_FAILURE);
209 }
210 check_schema();
211
212 if(flag.vacuum)
213 db_reclaim_slack();
214
215 if(flag.import && flag.wipe)
216 {
217 flag.dupes_ok = YES; /* dont check for dupes if we are wiping the db clean */
218 for(i = 0; i < 3; i++)
219 fprintf(stdout,
220 "* WARNING: YOU ARE ABOUT TO WIPE YOUR DATABASE!\n");
221
222 fprintf(stdout, "* Press ^C to abort! ");
223 fflush(stdout);
224 rb_sleep(10, 0);
225 fprintf(stdout, "Carrying on...\n");
226 wipe_schema();
227 }
228 }
229 if(flag.verbose && flag.dupes_ok == YES)
230 fprintf(stdout, "* Allowing duplicate bans...\n");
231
232 /* checking for our files to import or export */
233 for(i = 0; i < LAST_BANDB_TYPE; i++)
234 {
5203cba5 235 snprintf(conf, sizeof(conf), "%s/%s.conf%s",
832ed81a
AC
236 etc, bandb_table[i], bandb_suffix[i]);
237
238 if(flag.import && flag.pretend == NO)
239 rsdb_transaction(RSDB_TRANS_START);
240
241 if(flag.import)
242 import_config(conf, i);
243
244 if(flag.export)
245 export_config(conf, i);
246
247 if(flag.import && flag.pretend == NO)
248 rsdb_transaction(RSDB_TRANS_END);
249 }
250
251 if(flag.import)
252 {
253 if(count.error && flag.verbose)
29c92cf9 254 fprintf(stderr, "* I was unable to locate %u config files to import.\n",
832ed81a
AC
255 count.error);
256
29c92cf9 257 fprintf(stdout, "* Import Stats: Klines: %u, Dlines: %u, Xlines: %u, Resvs: %u \n",
832ed81a
AC
258 count.klines, count.dlines, count.xlines, count.resvs);
259
260 fprintf(stdout,
261 "*\n* If your IRC server is currently running, newly imported bans \n* will not take effect until you issue the command: /quote rehash bans\n");
262
263 if(flag.pretend)
264 fprintf(stdout,
265 "* Pretend mode engaged. Nothing was actually entered into the database.\n");
266 }
267
268 return 0;
269}
270
271
272/**
273 * export the database to old-style flat files
274 */
275static void
276export_config(const char *conf, int id)
277{
278 struct rsdb_table table;
279 static char sql[BUFSIZE * 2];
280 static char buf[512];
281 FILE *fd = NULL;
282 int j;
283
284 /* for sanity sake */
285 const int mask1 = 0;
286 const int mask2 = 1;
287 const int reason = 2;
288 const int oper = 3;
289 const int ts = 4;
290 /* const int perm = 5; */
291
292 if(!table_has_rows(bandb_table[id]))
293 return;
294
295 if(strstr(conf, ".perm") != 0)
5203cba5 296 snprintf(sql, sizeof(sql),
832ed81a
AC
297 "SELECT DISTINCT mask1,mask2,reason,oper,time FROM %s WHERE perm = 1 ORDER BY time",
298 bandb_table[id]);
299 else
5203cba5 300 snprintf(sql, sizeof(sql),
832ed81a
AC
301 "SELECT DISTINCT mask1,mask2,reason,oper,time FROM %s WHERE perm = 0 ORDER BY time",
302 bandb_table[id]);
303
304 rsdb_exec_fetch(&table, sql);
305 if(table.row_count <= 0)
306 {
307 rsdb_exec_fetch_end(&table);
308 return;
309 }
310
311 if(flag.verbose)
312 fprintf(stdout, "* checking for %s: ", conf); /* debug */
313
314 /* open config for reading, or skip to the next */
315 if(!(fd = fopen(conf, "w")))
316 {
317 if(flag.verbose)
318 fprintf(stdout, "\tmissing.\n");
319 count.error++;
320 return;
321 }
322
323 for(j = 0; j < table.row_count; j++)
324 {
325 switch (id)
326 {
327 case BANDB_DLINE:
328 case BANDB_DLINE_PERM:
5203cba5 329 snprintf(buf, sizeof(buf),
832ed81a
AC
330 "\"%s\",\"%s\",\"\",\"%s\",\"%s\",%s\n",
331 table.row[j][mask1],
332 mangle_reason(table.row[j][reason]),
333 bt_smalldate(table.row[j][ts]),
334 table.row[j][oper], table.row[j][ts]);
335 break;
336
337 case BANDB_XLINE:
338 case BANDB_XLINE_PERM:
5203cba5 339 snprintf(buf, sizeof(buf),
832ed81a
AC
340 "\"%s\",\"0\",\"%s\",\"%s\",%s\n",
341 escape_quotes(table.row[j][mask1]),
342 mangle_reason(table.row[j][reason]),
343 table.row[j][oper], table.row[j][ts]);
344 break;
345
346 case BANDB_RESV:
347 case BANDB_RESV_PERM:
5203cba5 348 snprintf(buf, sizeof(buf),
832ed81a
AC
349 "\"%s\",\"%s\",\"%s\",%s\n",
350 table.row[j][mask1],
351 mangle_reason(table.row[j][reason]),
352 table.row[j][oper], table.row[j][ts]);
353 break;
354
355
356 default: /* Klines */
5203cba5 357 snprintf(buf, sizeof(buf),
832ed81a
AC
358 "\"%s\",\"%s\",\"%s\",\"\",\"%s\",\"%s\",%s\n",
359 table.row[j][mask1], table.row[j][mask2],
360 mangle_reason(table.row[j][reason]),
361 bt_smalldate(table.row[j][ts]), table.row[j][oper],
362 table.row[j][ts]);
363 break;
364 }
365
366 fprintf(fd, "%s", buf);
367 }
368
369 rsdb_exec_fetch_end(&table);
370 if(flag.verbose)
371 fprintf(stdout, "\twritten.\n");
372 fclose(fd);
373}
374
375/**
376 * attempt to condense the individual conf functions into one
377 */
378static void
379import_config(const char *conf, int id)
380{
381 FILE *fd;
382
383 char line[BUFSIZE];
384 char *p;
385 int i = 0;
386
387 char f_perm = 0;
f67e7283
JT
388 const char *f_mask1 = NULL;
389 const char *f_mask2 = NULL;
390 const char *f_oper = NULL;
391 const char *f_time = NULL;
392 const char *f_reason = NULL;
393 const char *f_oreason = NULL;
832ed81a
AC
394 char newreason[REASONLEN];
395
396 if(flag.verbose)
397 fprintf(stdout, "* checking for %s: ", conf); /* debug */
398
399 /* open config for reading, or skip to the next */
400 if(!(fd = fopen(conf, "r")))
401 {
402 if(flag.verbose)
403 fprintf(stdout, "%*s", strlen(bandb_suffix[id]) > 0 ? 10 : 15,
404 "missing.\n");
405 count.error++;
406 return;
407 }
408
409 if(strstr(conf, ".perm") != 0)
410 f_perm = 1;
411
412
413 /* xline
414 * "SYSTEM","0","banned","stevoo!stevoo@efnet.port80.se{stevoo}",1111080437
415 * resv
416 * "OseK","banned nickname","stevoo!stevoo@efnet.port80.se{stevoo}",1111031619
417 * dline
418 * "194.158.192.0/19","laptop scammers","","2005/3/17 05.33","stevoo!stevoo@efnet.port80.se{stevoo}",1111033988
419 */
420 while(fgets(line, sizeof(line), fd))
421 {
422 if((p = strpbrk(line, "\r\n")) != NULL)
423 *p = '\0';
424
425 if((*line == '\0') || (*line == '#'))
426 continue;
427
428 /* mask1 */
429 f_mask1 = getfield(line);
430
431 if(EmptyString(f_mask1))
432 continue;
433
434 /* mask2 */
435 switch (id)
436 {
437 case BANDB_XLINE:
438 case BANDB_XLINE_PERM:
439 f_mask1 = escape_quotes(clean_gecos_field(f_mask1));
440 getfield(NULL); /* empty field */
441 break;
442
443 case BANDB_RESV:
444 case BANDB_RESV_PERM:
445 case BANDB_DLINE:
446 case BANDB_DLINE_PERM:
447 break;
448
449 default:
450 f_mask2 = getfield(NULL);
451 if(EmptyString(f_mask2))
452 continue;
453 break;
454 }
455
456 /* reason */
457 f_reason = getfield(NULL);
458 if(EmptyString(f_reason))
459 continue;
460
461 /* oper comment */
462 switch (id)
463 {
464 case BANDB_KLINE:
465 case BANDB_KLINE_PERM:
466 case BANDB_DLINE:
467 case BANDB_DLINE_PERM:
468 f_oreason = getfield(NULL);
469 getfield(NULL);
470 break;
471
472 default:
473 break;
474 }
475
476 f_oper = getfield(NULL);
477 f_time = strip_quotes(f_oper + strlen(f_oper) + 2);
f67e7283
JT
478 if(EmptyString(f_oper))
479 f_oper = "unknown";
832ed81a
AC
480
481 /* meh */
482 if(id == BANDB_KLINE || id == BANDB_KLINE_PERM)
483 {
484 if(strstr(f_mask1, "!") != NULL)
485 {
486 fprintf(stderr,
487 "* SKIPPING INVALID KLINE %s@%s set by %s\n",
488 f_mask1, f_mask2, f_oper);
489 fprintf(stderr, " You may wish to re-apply it correctly.\n");
490 continue;
491 }
492 }
493
494 /* append operreason_field to reason_field */
495 if(!EmptyString(f_oreason))
5203cba5 496 snprintf(newreason, sizeof(newreason), "%s | %s", f_reason, f_oreason);
832ed81a 497 else
5203cba5 498 snprintf(newreason, sizeof(newreason), "%s", f_reason);
832ed81a
AC
499
500 if(flag.pretend == NO)
501 {
502 if(flag.dupes_ok == NO)
503 drop_dupes(f_mask1, f_mask2, bandb_table[id]);
504
505 rsdb_exec(NULL,
506 "INSERT INTO %s (mask1, mask2, oper, time, perm, reason) VALUES('%Q','%Q','%Q','%Q','%d','%Q')",
507 bandb_table[id], f_mask1, f_mask2, f_oper, f_time, f_perm,
508 newreason);
509 }
510
511 if(flag.pretend && flag.verbose)
512 fprintf(stdout,
513 "%s: perm(%d) mask1(%s) mask2(%s) oper(%s) reason(%s) time(%s)\n",
514 bandb_table[id], f_perm, f_mask1, f_mask2, f_oper, newreason,
515 f_time);
516
517 i++;
518 }
519
520 switch (bandb_letter[id])
521 {
522 case 'K':
523 count.klines += i;
524 break;
525 case 'D':
526 count.dlines += i;
527 break;
528 case 'X':
529 count.xlines += i;
530 break;
531 case 'R':
532 count.resvs += i;
533 break;
534 default:
535 break;
536 }
537
538 if(flag.verbose)
539 fprintf(stdout, "%*s\n", strlen(bandb_suffix[id]) > 0 ? 10 : 15, "imported.");
540
e3a3eb92
JT
541 fclose(fd);
542
832ed81a
AC
543 return;
544}
545
546/**
547 * getfield
548 *
549 * inputs - input buffer
550 * output - next field
551 * side effects - field breakup for ircd.conf file.
552 */
553char *
554getfield(char *newline)
555{
556 static char *line = NULL;
557 char *end, *field;
558
559 if(newline != NULL)
560 line = newline;
561
562 if(line == NULL)
563 return (NULL);
564
565 field = line;
566
567 /* XXX make this skip to first " if present */
568 if(*field == '"')
569 field++;
570 else
571 return (NULL); /* mal-formed field */
572
573 end = strchr(line, ',');
574
575 while(1)
576 {
577 /* no trailing , - last field */
578 if(end == NULL)
579 {
580 end = line + strlen(line);
581 line = NULL;
582
583 if(*end == '"')
584 {
585 *end = '\0';
586 return field;
587 }
588 else
589 return NULL;
590 }
591 else
592 {
593 /* look for a ", to mark the end of a field.. */
594 if(*(end - 1) == '"')
595 {
596 line = end + 1;
597 end--;
598 *end = '\0';
599 return field;
600 }
601
602 /* search for the next ',' */
603 end++;
604 end = strchr(end, ',');
605 }
606 }
607
608 return NULL;
609}
610
611/**
612 * strip away "quotes" from around strings
613 */
614static char *
615strip_quotes(const char *string)
616{
617 static char buf[14]; /* int(11) + 2 + \0 */
618 char *str = buf;
619
620 if(string == NULL)
621 return NULL;
622
623 while(*string)
624 {
625 if(*string != '"')
626 {
627 *str++ = *string;
628 }
629 string++;
630 }
631 *str = '\0';
632 return buf;
633}
634
635/**
636 * escape quotes in a string
637 */
638static char *
639escape_quotes(const char *string)
640{
641 static char buf[BUFSIZE * 2];
642 char *str = buf;
643
644 if(string == NULL)
645 return NULL;
646
647 while(*string)
648 {
649 if(*string == '"')
650 {
651 *str++ = '\\';
652 *str++ = '"';
653 }
654 else
655 {
656 *str++ = *string;
657 }
658 string++;
659 }
660 *str = '\0';
661 return buf;
662}
663
664
665static char *
666mangle_reason(const char *string)
667{
668 static char buf[BUFSIZE * 2];
669 char *str = buf;
670
671 if(string == NULL)
672 return NULL;
673
674 while(*string)
675 {
676 switch (*string)
677 {
678 case '"':
679 *str = '\'';
680 break;
681 case ':':
682 *str = ' ';
683 break;
684 default:
685 *str = *string;
686 }
687 string++;
688 str++;
689
690 }
691 *str = '\0';
692 return buf;
693}
694
695
696/**
697 * change spaces to \s in gecos field
698 */
699static const char *
700clean_gecos_field(const char *gecos)
701{
702 static char buf[BUFSIZE * 2];
703 char *str = buf;
704
705 if(gecos == NULL)
706 return NULL;
707
708 while(*gecos)
709 {
710 if(*gecos == ' ')
711 {
712 *str++ = '\\';
713 *str++ = 's';
714 }
715 else
716 *str++ = *gecos;
717 gecos++;
718 }
719 *str = '\0';
720 return buf;
721}
722
723/**
724 * verify the database integrity, and if necessary create apropriate tables
725 */
726static void
727check_schema(void)
728{
729 int i, j;
730 char type[8]; /* longest string is 'INTEGER\0' */
731
732 if(flag.verify || flag.verbose)
733 fprintf(stdout, "* Verifying database.\n");
734
735 const char *columns[] = {
736 "perm",
737 "mask1",
738 "mask2",
739 "oper",
740 "time",
741 "reason",
742 NULL
743 };
744
745 for(i = 0; i < LAST_BANDB_TYPE; i++)
746 {
747 if(!table_exists(bandb_table[i]))
748 {
749 rsdb_exec(NULL,
750 "CREATE TABLE %s (mask1 TEXT, mask2 TEXT, oper TEXT, time INTEGER, perm INTEGER, reason TEXT)",
751 bandb_table[i]);
752 }
753
754 /*
755 * i can't think of any better way to do this, other then attempt to
756 * force the creation of column that may, or may not already exist. --dubkat
757 */
758 else
759 {
760 for(j = 0; columns[j] != NULL; j++)
761 {
762 if(!strcmp(columns[j], "time") && !strcmp(columns[j], "perm"))
763 rb_strlcpy(type, "INTEGER", sizeof(type));
764 else
765 rb_strlcpy(type, "TEXT", sizeof(type));
766
767 /* attempt to add a column with extreme prejudice, errors are ignored */
768 rsdb_exec(NULL, "ALTER TABLE %s ADD COLUMN %s %s", bandb_table[i],
769 columns[j], type);
770 }
771 }
772
773 i++; /* skip over .perm */
774 }
775}
776
777static void
778db_reclaim_slack(void)
779{
780 fprintf(stdout, "* Reclaiming free space.\n");
781 rsdb_exec(NULL, "VACUUM");
782}
783
784
785/**
786 * check that appropriate tables exist.
787 */
788static int
789table_exists(const char *dbtab)
790{
791 struct rsdb_table table;
792 rsdb_exec_fetch(&table, "SELECT name FROM sqlite_master WHERE type='table' AND name='%s'",
793 dbtab);
794 rsdb_exec_fetch_end(&table);
795 return table.row_count;
796}
797
798/**
799 * check that there are actual entries in a table
800 */
801static int
802table_has_rows(const char *dbtab)
803{
804 struct rsdb_table table;
805 rsdb_exec_fetch(&table, "SELECT * FROM %s", dbtab);
806 rsdb_exec_fetch_end(&table);
807 return table.row_count;
808}
809
810/**
811 * completly wipes out an existing ban.db of all entries.
812 */
813static void
814wipe_schema(void)
815{
816 int i;
817 rsdb_transaction(RSDB_TRANS_START);
818 for(i = 0; i < LAST_BANDB_TYPE; i++)
819 {
820 rsdb_exec(NULL, "DROP TABLE %s", bandb_table[i]);
821 i++; /* double increment to skip over .perm */
822 }
823 rsdb_transaction(RSDB_TRANS_END);
824
825 check_schema();
826}
827
828/**
829 * remove pre-existing duplicate bans from the database.
830 * we favor the new, imported ban over the one in the database
831 */
832void
833drop_dupes(const char *user, const char *host, const char *t)
834{
835 rsdb_exec(NULL, "DELETE FROM %s WHERE mask1='%Q' AND mask2='%Q'", t, user, host);
836}
837
838static void
839db_error_cb(const char *errstr)
840{
841 return;
842}
843
844
845/**
846 * convert unix timestamp to human readable (small) date
847 */
848static char *
849bt_smalldate(const char *string)
850{
851 static char buf[MAX_DATE_STRING];
852 struct tm *lt;
853 time_t t;
854 t = strtol(string, NULL, 10);
855 lt = gmtime(&t);
856 if(lt == NULL)
857 return NULL;
5203cba5 858 snprintf(buf, sizeof(buf), "%d/%d/%d %02d.%02d",
832ed81a
AC
859 lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min);
860 return buf;
861}
862
863/**
864 * you are here ->.
865 */
866void
867print_help(int i_exit)
868{
5c5d0fb7 869 fprintf(stderr, "bantool v.%s - the charybdis database tool.\n", BT_VERSION);
832ed81a 870 fprintf(stderr, "Copyright (C) 2008 Daniel J Reidy <dubkat@gmail.com>\n");
832ed81a
AC
871 fprintf(stderr, "This program is distributed in the hope that it will be useful,\n"
872 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
873 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
874 "GNU General Public License for more details.\n\n");
875
876 fprintf(stderr, "Usage: %s <-i|-e> [-p] [-v] [-h] [-d] [-w] [path]\n", me);
877 fprintf(stderr, " -h : Display some slightly useful help.\n");
878 fprintf(stderr, " -i : Actually import configs into your database.\n");
879 fprintf(stderr, " -e : Export your database to old-style flat files.\n");
880 fprintf(stderr,
881 " This is suitable for redistrubuting your banlists, or creating backups.\n");
882 fprintf(stderr, " -s : Reclaim empty slack space the database may be taking up.\n");
883 fprintf(stderr, " -u : Update the database tables to support any new features.\n");
884 fprintf(stderr,
885 " This is automaticlly done if you are importing or exporting\n");
886 fprintf(stderr, " but should be run whenever you upgrade the ircd.\n");
887 fprintf(stderr,
888 " -p : pretend, checks for the configs, and parses them, then tells you some data...\n");
889 fprintf(stderr, " but does not touch your database.\n");
890 fprintf(stderr,
891 " -v : Be verbose... and it *is* very verbose! (intended for debugging)\n");
892 fprintf(stderr, " -d : Enable checking for redunant entries.\n");
893 fprintf(stderr, " -w : Completly wipe your database clean. May be used with -i \n");
894 fprintf(stderr,
895 " path : An optional directory containing old ratbox configs for import, or export.\n");
896 fprintf(stderr, " If not specified, it looks in PREFIX/etc.\n");
897 exit(i_exit);
898}