]> jfr.im git - solanum.git/blame - src/capability.c
src/s_conf: More detailed error messages conforming to POSIX errno
[solanum.git] / src / capability.c
CommitLineData
64b56afd
AC
1/*
2 * Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org>.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice is present in all copies.
7 *
8 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
9 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
11 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
12 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
13 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
14 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
15 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
16 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
17 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
18 * POSSIBILITY OF SUCH DAMAGE.
19 */
20
21#include "stdinc.h"
22#include "capability.h"
23#include "irc_dictionary.h"
24
885cd603
AC
25static rb_dlink_list capability_indexes = { NULL, NULL, 0 };
26
64b56afd 27struct CapabilityIndex {
885cd603 28 char *name;
64b56afd
AC
29 struct Dictionary *cap_dict;
30 unsigned int highest_bit;
885cd603 31 rb_dlink_node node;
64b56afd
AC
32};
33
5058c8eb 34#define CAP_ORPHANED 0x1
f01f67f0 35#define CAP_REQUIRED 0x2
5058c8eb 36
64b56afd 37struct CapabilityEntry {
e679e389 38 char *cap;
64b56afd 39 unsigned int value;
5058c8eb 40 unsigned int flags;
64b56afd
AC
41};
42
43unsigned int
bde42c60 44capability_get(struct CapabilityIndex *idx, const char *cap)
64b56afd
AC
45{
46 struct CapabilityEntry *entry;
47
bde42c60 48 s_assert(idx != NULL);
d7e4ed77
AC
49 if (cap == NULL)
50 return 0;
64b56afd 51
bde42c60 52 entry = irc_dictionary_retrieve(idx->cap_dict, cap);
5058c8eb 53 if (entry != NULL && !(entry->flags & CAP_ORPHANED))
8bedf01d 54 return (1 << entry->value);
64b56afd 55
8d20b088 56 return 0;
64b56afd
AC
57}
58
59unsigned int
bde42c60 60capability_put(struct CapabilityIndex *idx, const char *cap)
64b56afd
AC
61{
62 struct CapabilityEntry *entry;
63
bde42c60
JT
64 s_assert(idx != NULL);
65 if (!idx->highest_bit)
8bedf01d 66 return 0xFFFFFFFF;
64b56afd 67
bde42c60 68 if ((entry = irc_dictionary_retrieve(idx->cap_dict, cap)) != NULL)
64b56afd 69 {
5058c8eb 70 entry->flags &= ~CAP_ORPHANED;
8bedf01d 71 return (1 << entry->value);
64b56afd
AC
72 }
73
74 entry = rb_malloc(sizeof(struct CapabilityEntry));
e679e389 75 entry->cap = rb_strdup(cap);
5058c8eb 76 entry->flags = 0;
bde42c60 77 entry->value = idx->highest_bit;
64b56afd 78
bde42c60 79 irc_dictionary_add(idx->cap_dict, entry->cap, entry);
64b56afd 80
bde42c60
JT
81 idx->highest_bit++;
82 if (idx->highest_bit % (sizeof(unsigned int) * 8) == 0)
83 idx->highest_bit = 0;
64b56afd 84
8bedf01d 85 return (1 << entry->value);
64b56afd
AC
86}
87
22cae20f
JT
88unsigned int
89capability_put_anonymous(struct CapabilityIndex *idx)
90{
91 unsigned int value;
92
93 s_assert(idx != NULL);
94 if (!idx->highest_bit)
95 return 0xFFFFFFFF;
96 value = 1 << idx->highest_bit;
97 idx->highest_bit++;
98 if (idx->highest_bit % (sizeof(unsigned int) * 8) == 0)
99 idx->highest_bit = 0;
100 return value;
101}
102
64b56afd 103void
bde42c60 104capability_orphan(struct CapabilityIndex *idx, const char *cap)
64b56afd
AC
105{
106 struct CapabilityEntry *entry;
107
bde42c60 108 s_assert(idx != NULL);
64b56afd 109
bde42c60 110 entry = irc_dictionary_retrieve(idx->cap_dict, cap);
64b56afd 111 if (entry != NULL)
f01f67f0
AC
112 {
113 entry->flags &= ~CAP_REQUIRED;
5058c8eb 114 entry->flags |= CAP_ORPHANED;
f01f67f0
AC
115 }
116}
117
118void
bde42c60 119capability_require(struct CapabilityIndex *idx, const char *cap)
f01f67f0
AC
120{
121 struct CapabilityEntry *entry;
122
bde42c60 123 s_assert(idx != NULL);
f01f67f0 124
bde42c60 125 entry = irc_dictionary_retrieve(idx->cap_dict, cap);
f01f67f0
AC
126 if (entry != NULL)
127 entry->flags |= CAP_REQUIRED;
64b56afd
AC
128}
129
130static void
131capability_destroy(struct DictionaryElement *delem, void *privdata)
132{
133 s_assert(delem != NULL);
134
135 rb_free(delem->data);
136}
137
138struct CapabilityIndex *
885cd603 139capability_index_create(const char *name)
64b56afd 140{
bde42c60 141 struct CapabilityIndex *idx;
64b56afd 142
bde42c60 143 idx = rb_malloc(sizeof(struct CapabilityIndex));
885cd603 144 idx->name = rb_strdup(name);
bde42c60
JT
145 idx->cap_dict = irc_dictionary_create(strcasecmp);
146 idx->highest_bit = 1;
64b56afd 147
885cd603
AC
148 rb_dlinkAdd(idx, &idx->node, &capability_indexes);
149
bde42c60 150 return idx;
64b56afd
AC
151}
152
153void
bde42c60 154capability_index_destroy(struct CapabilityIndex *idx)
64b56afd 155{
bde42c60 156 s_assert(idx != NULL);
64b56afd 157
885cd603
AC
158 rb_dlinkDelete(&idx->node, &capability_indexes);
159
bde42c60
JT
160 irc_dictionary_destroy(idx->cap_dict, capability_destroy, NULL);
161 rb_free(idx);
64b56afd 162}
5e773521
AC
163
164const char *
bde42c60 165capability_index_list(struct CapabilityIndex *idx, unsigned int cap_mask)
5e773521
AC
166{
167 struct DictionaryIter iter;
168 struct CapabilityEntry *entry;
169 static char buf[BUFSIZE];
170 char *t = buf;
171 int tl;
172
bde42c60 173 s_assert(idx != NULL);
5e773521
AC
174
175 *t = '\0';
176
bde42c60 177 DICTIONARY_FOREACH(entry, &iter, idx->cap_dict)
5e773521 178 {
33b214fa 179 if ((1 << entry->value) & cap_mask)
5e773521 180 {
e915e51f 181 tl = rb_sprintf(t, "%s ", entry->cap);
5e773521
AC
182 t += tl;
183 }
184 }
185
186 t--;
187 *t = '\0';
188
189 return buf;
190}
ec3a9055
AC
191
192unsigned int
bde42c60 193capability_index_mask(struct CapabilityIndex *idx)
ec3a9055
AC
194{
195 struct DictionaryIter iter;
196 struct CapabilityEntry *entry;
197 unsigned int mask = 0;
198
bde42c60 199 s_assert(idx != NULL);
ec3a9055 200
bde42c60 201 DICTIONARY_FOREACH(entry, &iter, idx->cap_dict)
ec3a9055 202 {
0582290f 203 if (!(entry->flags & CAP_ORPHANED))
8bedf01d 204 mask |= (1 << entry->value);
ec3a9055
AC
205 }
206
207 return mask;
208}
f01f67f0
AC
209
210unsigned int
bde42c60 211capability_index_get_required(struct CapabilityIndex *idx)
f01f67f0
AC
212{
213 struct DictionaryIter iter;
214 struct CapabilityEntry *entry;
215 unsigned int mask = 0;
216
bde42c60 217 s_assert(idx != NULL);
f01f67f0 218
bde42c60 219 DICTIONARY_FOREACH(entry, &iter, idx->cap_dict)
f01f67f0
AC
220 {
221 if (!(entry->flags & CAP_ORPHANED) && (entry->flags & CAP_REQUIRED))
8bedf01d 222 mask |= (1 << entry->value);
f01f67f0
AC
223 }
224
225 return mask;
226}
a16910aa
AC
227
228void
229capability_index_stats(void (*cb)(const char *line, void *privdata), void *privdata)
230{
231 rb_dlink_node *node;
232 char buf[BUFSIZE];
233
234 RB_DLINK_FOREACH(node, capability_indexes.head)
235 {
236 struct CapabilityIndex *idx = node->data;
237 struct DictionaryIter iter;
238 struct CapabilityEntry *entry;
239
240 rb_snprintf(buf, sizeof buf, "'%s': allocated bits - %d", idx->name, (idx->highest_bit - 1));
241 cb(buf, privdata);
242
243 DICTIONARY_FOREACH(entry, &iter, idx->cap_dict)
244 {
245 rb_snprintf(buf, sizeof buf, "bit %d: '%s'", entry->value, entry->cap);
246 cb(buf, privdata);
247 }
248
249 rb_snprintf(buf, sizeof buf, "'%s': remaining bits - %ld", idx->name,
250 (sizeof(unsigned int) * 8) - (idx->highest_bit - 1));
251 cb(buf, privdata);
252 }
253
254 rb_snprintf(buf, sizeof buf, "%ld capability indexes", rb_dlink_list_length(&capability_indexes));
255 cb(buf, privdata);
256}