New CLEAR command, removes all rules from a list
[rxpd] / src / rxpd_file.c
1 /*
2     rxpd_file.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 struct rxpd_file*
25 rxpd_file_new (struct rxpd_base* base, const char* filename)
26 {
27   struct rxpd_file* self = NULL;
28
29   while (*filename == '/')
30     ++filename;
31
32   if (!filename ||
33       strcspn (filename, RXPD_FILE_ILG_CHARS) != strlen (filename) ||
34       strstr (filename, "../") ||
35       strstr (filename, "/./") ||
36       filename[strlen (filename) - 1] == '/' ||
37       strlen (filename) + strlen (base->basedir) > 4095)
38     {
39       rxpd_log (base, LOG_ERR, "illegal filename: '%s'\n", filename?filename:"");
40       return NULL;
41     }
42
43   self = rxpd_malloc (sizeof (struct rxpd_file));
44   self->base = base;
45   pth_rwlock_init (&self->lock);
46
47   psplay_init (&self->node, rxpd_strdup (filename));
48   llist_init (&self->rules);
49
50   psplay_insert (&base->files, &self->node);
51
52   rxpd_log (base, LOG_INFO, "new file: '%s'\n", filename);
53   return self;
54 }
55
56 void
57 rxpd_file_delete (struct rxpd_file* self)
58 {
59   if (self)
60     {
61       rxpd_file_rules_delete (self);
62       psplay_remove (&self->base->files, &self->node);
63
64       while (1) 
65         {
66           remove ((char*)self->node.key);
67           char* slash = strrchr ((char*)self->node.key, '/');
68           if (slash)
69             *slash = '\0';
70           else
71             break;
72         }
73
74       free ((void*)self->node.key);
75       free (self);
76     }
77 }
78
79 struct rxpd_file*
80 rxpd_file_rules_delete (struct rxpd_file* self)
81 {
82   if (self)
83     {
84       pth_rwlock_acquire (&self->lock, PTH_RWLOCK_RW, FALSE, NULL);
85       LLIST_WHILE_HEAD (&self->rules, n)
86         {
87           struct rxpd_rule* node = (struct rxpd_rule*)n;
88           rxpd_rule_delete (node);
89         }
90       pth_rwlock_release (&self->lock);
91     }
92   return self;
93 }
94
95 int
96 rxpd_file_load (struct rxpd_file* self)
97 {
98   FILE* f = fopen (self->node.key, "r");
99   if (f)
100     {
101       pth_rwlock_acquire (&self->lock, PTH_RWLOCK_RW, FALSE, NULL);
102
103       /* First purge old rules */
104       LLIST_WHILE_HEAD (&self->rules, n)
105         {
106           struct rxpd_rule* node = (struct rxpd_rule*)n;
107           rxpd_rule_delete (node);
108         }
109
110       // TODO test excess line length = error
111       char buf[4096];
112
113       rxpd_log (self->base, LOG_NOTICE, "loading '%s'\n", self->node.key);
114
115       while (fgets (buf, 4096, f))
116         {
117           size_t last = strlen(buf);
118           if (buf[last-1] == '\n')
119             buf[last-1] = '\0';
120
121           struct rxpd_rule* rule;
122           rule = rxpd_rule_new (buf, self->base);
123           rxpd_log (self->base, LOG_DEBUG, "new rule '%s'\n", rule->string);
124
125           llist_insert_tail (&self->rules, &rule->node);
126         }
127
128       pth_rwlock_release (&self->lock);
129       fclose (f);
130       return 1;
131     }
132   else
133     {
134       rxpd_log (self->base, LOG_ERR, "failed loading '%s'\n", self->node.key);
135       return 0;
136     }
137 }
138
139
140 int
141 rxpd_file_save (struct rxpd_file* self)
142 {
143   char* filename = strdupa (self->node.key);
144
145   char* slash = filename;
146
147   while ((slash = strchr (slash+1, '/')))
148     {
149       *slash = '\0';
150       mkdir (filename, 0777);
151       *slash = '/';
152     }
153
154   FILE* f = fopen (filename, "w");
155   if (f)
156     {
157       pth_rwlock_acquire (&self->lock, PTH_RWLOCK_RD, FALSE, NULL);
158
159       LLIST_FOREACH (&self->rules, n)
160         {
161           struct rxpd_rule* node = (struct rxpd_rule*)n;
162           if (node->atime != (time_t)-1)
163             fprintf (f, "%ld:%s\n", node->atime, node->string);
164           else if (*node->string != '#')
165             fprintf (f, ":%s\n", node->string);
166           else
167             fprintf (f, "%s\n", node->string);
168         }
169
170       pth_rwlock_release (&self->lock);
171       fclose (f);
172       rxpd_log (self->base, LOG_NOTICE, "saved '%s'\n", filename);
173       return 1;
174     }
175   else
176     {
177       rxpd_log (self->base, LOG_ERR, "failed saving '%s'\n", filename);
178       return 0;
179     }
180 }
181
182 struct rxpd_file*
183 rxpd_file_dump (struct rxpd_file* self, struct rxpd_buffer* out)
184 {
185   if (self)
186     {
187       if (llist_is_empty (&self->rules))
188         rxpd_buffer_printf (out, "#OK:\n");
189       else
190         {
191           pth_rwlock_acquire (&self->lock, PTH_RWLOCK_RD, FALSE, NULL);
192
193           LLIST_FOREACH (&self->rules, n)
194             {
195               struct rxpd_rule* rule = (struct rxpd_rule*)n;
196               if (rule->atime != (time_t)-1)
197                 rxpd_buffer_printf (out, "%ld:%s\n", rule->atime, rule->string);
198               else if (*rule->string != '#')
199                 rxpd_buffer_printf (out, ":%s\n", rule->string);
200               else
201                 rxpd_buffer_printf (out, "%s\n", rule->string);
202             }
203           pth_rwlock_release (&self->lock);
204         }
205     }
206
207   return self;
208 }
209
210 int
211 rxpd_file_cmp (const void* A, const void* B)
212 {
213   return strcmp (A, B);
214 }
215
216