27aabf3ea724ea7bee684da641dfa576bce9a3f1
[rxpd] / src / main.c
1 /*
2     main.c - regex policy daemon
3
4   Copyright (C)
5     2007,               Christian Thaeter <ct@pipapo.org>
6
7   This program is free software; you can redistribute it and/or
8   modify it under the terms of the GNU General Public License as
9   published by the Free Software Foundation; either version 2 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 General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "rxpd.h"
23
24 #include <string.h>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <locale.h>
30 #include <langinfo.h>
31
32 void
33 version (void)
34 {
35   printf (
36           "  Regex Policy Daemon ("PACKAGE_STRING")\n\n"
37           "  Copyright (C)\n"
38           "    2007,               Christian Thaeter <ct@pipapo.org>\n\n"
39           "  This is free software.  You may redistribute copies of it under the terms of\n"
40           "  the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.\n"
41           "  There is NO WARRANTY, to the extent permitted by law.\n\n"
42           "  http://www.pipapo.org/pipawiki/RegexPolicyDaemon\n"
43           );
44 }
45
46 void
47 usage (void)
48 {
49   printf (
50     "rxpd [OPTIONS] RULES..\n"
51     " -v          increase verbosity level\n"
52     " -V          show version\n"
53     " -d          daemonize into background\n"
54     " -D          debug mode\n"
55     " -b dir      basedir for rules\n"
56     " -q          be quiet\n"
57     " -t port     listen on tcp port\n"
58     //" -u name     unix\n"
59     " -p policy   define a list for access policies\n"
60     //" -i          case insensitive\n"
61     //" -4          ipv4\n"
62     //" -6          ipv6\n"
63     //" -r          resolve names\n"
64     //" -l log      log hits to logfile\n"
65     " -L locale   set locale, must be a utf-8 locale, only LC_CTYPE is used\n"
66     " -h          this usage information\n"
67     //" -U user     switch to user\n"
68     );
69 }
70
71
72 int
73 main (int argc, char** argv)
74 {
75   if (pth_init() == FALSE)
76     rxpd_fail (NULL, "pth initialization failed\n");
77
78   struct rxpd_base* rxpd;
79
80   openlog (PACKAGE_NAME, LOG_PID, LOG_DAEMON);
81
82   rxpd = rxpd_init ();
83
84   opterr = 0;
85   int opt;
86
87   while ((opt = getopt (argc, argv, "vVdDb:qt:u:p:i46rl:L:h")) != -1)
88     switch (opt)
89       {
90       case 'v':
91         if (rxpd->verbosity < LOG_DEBUG)
92           ++rxpd->verbosity;
93         break;
94       case 'V':
95         version ();
96         exit (EXIT_SUCCESS);
97       case 'd':
98         rxpd->daemonize = 1;
99         break;
100       case 'D':
101         if (rxpd->verbosity < LOG_INFO)
102           rxpd->verbosity = LOG_INFO;
103         rxpd->daemonize = 0;
104         break;
105       case 'b':
106         if (!rxpd->basedir)
107           rxpd_set_basedir (rxpd, optarg);
108         else
109           rxpd_fail (rxpd, "basedir already set\n");
110         break;
111       case 'q':
112         rxpd->verbosity = LOG_ALERT;
113         break;
114       case 't':
115         {
116           int port = atoi (optarg);
117           if (port > 0 && port < 65536)
118             {
119               if (!rxpd_socket_new_tcp4 (rxpd, NULL, port))
120                 rxpd_fail (rxpd, "Could not open listening socket on port %d\n", port);
121             }
122           else
123             rxpd_fail (rxpd, "Illegal port number\n");
124         }
125         // TODO rxpd_socket_new_tcp6 (rxpd, NULL, 2374)
126         break;
127 #if 0 /*not yet implemented*/
128       case 'u':
129         //rxpd_socket_new_unix (rxpd, NULL, 2374);
130         break;
131 #endif
132       case 'p':
133         if (!rxpd->policy)
134           rxpd->policy = rxpd_file_new (rxpd, optarg);
135         else
136           rxpd_fail (rxpd, "policy already set\n");
137         break;
138       case 'i':
139         rxpd->regflags |= REG_ICASE; 
140         break;
141       case 'L':
142         if (!rxpd->locale)
143           rxpd->locale = optarg;
144         else
145           rxpd_fail (rxpd, "locale already set\n");
146         break;
147 #if 0 /*not yet implemented*/
148       case '4':
149         break;
150       case '6':
151         break;
152       case 'r':
153         break;
154       case 'l:':
155         break;
156 #endif
157       case 'h':
158         usage ();
159         exit (0);
160         break;
161       default:
162         rxpd_fail (rxpd, "Unknown option '-%c'\n", opt);
163       }
164
165   if (!rxpd->basedir)
166     rxpd_fail (rxpd, "Basedir not set (use -b BASEDIR)\n");
167
168   if (llist_is_empty (&rxpd->sockets))
169     rxpd_fail (rxpd, "No listening sockets given (use -t TCP or -u UNIX)\n");
170
171   rxpd->locale = setlocale(LC_CTYPE, rxpd->locale ? rxpd->locale : "");
172   if (!rxpd->locale)
173     rxpd_fail (rxpd, "Failed setting locale\n");
174
175   rxpd_log (rxpd, LOG_INFO, "Using locale '%s'\n", rxpd->locale);
176   if (strcmp(nl_langinfo(CODESET), "UTF-8") != 0)
177     rxpd_fail (rxpd, "Not a utf-8 locale '%s'\n", rxpd->locale);
178
179   if (rxpd->policy)
180     {
181       if (rxpd_file_load (rxpd->policy))
182         rxpd_log (rxpd, LOG_INFO, "Loaded policy '%s'\n", rxpd->policy->filename);
183       else
184         rxpd_fail (rxpd, "Failed loading policy '%s'\n", rxpd->policy->filename);
185     }
186
187   for (int i = optind; i < argc; ++i)
188     {
189       if (!rxpd_file_load (rxpd_file_new (rxpd, argv[i])))
190         rxpd_fail (rxpd, "Failed loading file '%s'\n", argv[i]);
191     }
192
193   if (rxpd->daemonize)
194     {
195       rxpd_log (rxpd, LOG_NOTICE, "Daemonizing ...\n");
196       if (daemon(1, 0))
197         rxpd_fail (rxpd, "Couldn't daemonize\n");
198     }
199
200   rxpd_log (rxpd, LOG_NOTICE, PACKAGE_STRING" starting up\n");
201
202   LLIST_FOREACH (&rxpd->sockets, n)
203     {
204       struct rxpd_socket* socket = (struct rxpd_socket*)n;
205       rxpd_socket_spawn (socket);
206     }
207
208   rxpd_log (rxpd, LOG_NOTICE, PACKAGE_STRING" running\n");
209
210   LLIST_WHILE_HEAD (&rxpd->sockets, n)
211     {
212       struct rxpd_socket* socket = (struct rxpd_socket*)n;
213       rxpd_socket_delete (rxpd_socket_join (socket));
214     }
215
216   rxpd_log (rxpd, LOG_NOTICE, PACKAGE_STRING" exited\n");
217   rxpd_destroy ();
218
219   return EXIT_SUCCESS;
220 }