replace: Add check for variable program_invocation_short_name
[bbaumbach/samba-autobuild/.git] / lib / util / server_id_db.c
1 /*
2  * Map names to server_ids
3  *
4  * Copyright Volker Lendecke <vl@samba.org> 2014
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "replace.h"
21 #include "system/filesys.h"
22 #include "lib/util/server_id.h"
23 #include "lib/util/server_id_db.h"
24 #include "lib/tdb_wrap/tdb_wrap.h"
25 #include "lib/util/strv.h"
26 #include "lib/util/util_tdb.h"
27 #include "lib/util/samba_util.h"
28
29 static TDB_DATA talloc_tdb_data(void *ptr)
30 {
31         return (TDB_DATA) { .dptr = ptr, .dsize = talloc_get_size(ptr) };
32 }
33
34 struct server_id_db {
35         struct server_id pid;
36         struct tdb_wrap *tdb;
37         char *names;
38 };
39
40 static int server_id_db_destructor(struct server_id_db *db);
41
42 struct server_id_db *server_id_db_init(TALLOC_CTX *mem_ctx,
43                                        struct server_id pid,
44                                        const char *base_path,
45                                        int hash_size, int tdb_flags)
46 {
47         struct server_id_db *db;
48         size_t pathlen = strlen(base_path) + 11;
49         char path[pathlen];
50
51         db = talloc(mem_ctx, struct server_id_db);
52         if (db == NULL) {
53                 return NULL;
54         }
55         db->pid = pid;
56         db->names = NULL;
57
58         snprintf(path, pathlen, "%s/names.tdb", base_path);
59
60         db->tdb = tdb_wrap_open(db, path, hash_size, tdb_flags,
61                                 O_RDWR|O_CREAT, 0660);
62         if (db->tdb == NULL) {
63                 TALLOC_FREE(db);
64                 return NULL;
65         }
66
67         talloc_set_destructor(db, server_id_db_destructor);
68
69         return db;
70 }
71
72 void server_id_db_reinit(struct server_id_db *db, struct server_id pid)
73 {
74         db->pid = pid;
75         TALLOC_FREE(db->names);
76 }
77
78 struct server_id server_id_db_pid(struct server_id_db *db)
79 {
80         return db->pid;
81 }
82
83 static int server_id_db_destructor(struct server_id_db *db)
84 {
85         char *name = NULL;
86
87         while ((name = strv_next(db->names, name)) != NULL) {
88                 server_id_db_remove(db, name);
89         }
90
91         return 0;
92 }
93
94 int server_id_db_add(struct server_id_db *db, const char *name)
95 {
96         struct tdb_context *tdb = db->tdb->tdb;
97         TDB_DATA key;
98         char *n;
99         int ret;
100
101         n = strv_find(db->names, name);
102         if (n != NULL) {
103                 return EEXIST;
104         }
105
106         ret = strv_add(db, &db->names, name);
107         if (ret != 0) {
108                 return ret;
109         }
110
111         key = string_term_tdb_data(name);
112
113         {
114                 size_t idlen = server_id_str_buf_unique(db->pid, NULL, 0);
115                 char idbuf[idlen];
116
117                 server_id_str_buf_unique(db->pid, idbuf, idlen);
118
119                 ret = tdb_append(
120                         tdb, key,
121                         (TDB_DATA) { .dptr = (uint8_t *)idbuf, .dsize = idlen });
122         }
123
124         if (ret != 0) {
125                 enum TDB_ERROR err = tdb_error(tdb);
126                 strv_delete(&db->names, strv_find(db->names, name));
127                 return map_unix_error_from_tdb(err);
128         }
129
130         return 0;
131 }
132
133 int server_id_db_prune_name(struct server_id_db *db, const char *name,
134                             struct server_id server)
135 {
136         struct tdb_context *tdb = db->tdb->tdb;
137         size_t idbuf_len = server_id_str_buf_unique(server, NULL, 0);
138         char idbuf[idbuf_len];
139         TDB_DATA key;
140         uint8_t *data;
141         size_t datalen;
142         char *ids, *id;
143         int ret;
144
145         key = string_term_tdb_data(name);
146         server_id_str_buf_unique(server, idbuf, idbuf_len);
147
148         ret = tdb_chainlock(tdb, key);
149         if (ret == -1) {
150                 enum TDB_ERROR err = tdb_error(tdb);
151                 return map_unix_error_from_tdb(err);
152         }
153
154         ret = tdb_fetch_talloc(tdb, key, db, &data);
155         if (ret != 0) {
156                 tdb_chainunlock(tdb, key);
157                 return ret;
158         }
159
160         datalen = talloc_get_size(data);
161         if ((datalen == 0) || (data[datalen-1] != '\0')) {
162                 tdb_chainunlock(tdb, key);
163                 TALLOC_FREE(data);
164                 return EINVAL;
165         }
166
167         ids = (char *)data;
168
169         id = strv_find(ids, idbuf);
170         if (id == NULL) {
171                 tdb_chainunlock(tdb, key);
172                 TALLOC_FREE(data);
173                 return ENOENT;
174         }
175
176         strv_delete(&ids, id);
177
178         if (talloc_get_size(ids) == 0) {
179                 ret = tdb_delete(tdb, key);
180         } else {
181                 ret = tdb_store(tdb, key, talloc_tdb_data(ids), TDB_MODIFY);
182         }
183         TALLOC_FREE(data);
184
185         tdb_chainunlock(tdb, key);
186
187         return 0;
188 }
189
190 int server_id_db_remove(struct server_id_db *db, const char *name)
191 {
192         char *n;
193         int ret;
194
195         n = strv_find(db->names, name);
196         if (n == NULL) {
197                 return ENOENT;
198         }
199
200         ret = server_id_db_prune_name(db, name, db->pid);
201         if (ret != 0) {
202                 return ret;
203         }
204
205         strv_delete(&db->names, n);
206         return 0;
207 }
208
209 int server_id_db_lookup(struct server_id_db *db, const char *name,
210                         TALLOC_CTX *mem_ctx, unsigned *pnum_servers,
211                         struct server_id **pservers)
212 {
213         struct tdb_context *tdb = db->tdb->tdb;
214         TDB_DATA key;
215         uint8_t *data;
216         size_t datalen;
217         char *ids, *id;
218         unsigned num_servers;
219         struct server_id *servers;
220         int i, ret;
221
222         key = string_term_tdb_data(name);
223
224         ret = tdb_fetch_talloc(tdb, key, mem_ctx, &data);
225         if (ret != 0) {
226                 return ret;
227         }
228
229         datalen = talloc_get_size(data);
230         if ((datalen == 0) || (data[datalen-1] != '\0')) {
231                 TALLOC_FREE(data);
232                 return EINVAL;
233         }
234
235         ids = (char *)data;
236         num_servers = strv_count(ids);
237
238         servers = talloc_array(mem_ctx, struct server_id, num_servers);
239         if (servers == NULL) {
240                 TALLOC_FREE(data);
241                 return ENOMEM;
242         }
243
244         i = 0;
245
246         for (id = ids; id != NULL; id = strv_next(ids, id)) {
247                 servers[i++] = server_id_from_string(NONCLUSTER_VNN, id);
248         }
249
250         TALLOC_FREE(data);
251
252         *pnum_servers = num_servers;
253         *pservers = servers;
254
255         return 0;
256 }
257
258 bool server_id_db_lookup_one(struct server_id_db *db, const char *name,
259                              struct server_id *server)
260 {
261         int ret;
262         unsigned num_servers;
263         struct server_id *servers;
264
265         ret = server_id_db_lookup(db, name, db, &num_servers, &servers);
266         if (ret != 0) {
267                 return false;
268         }
269         if (num_servers == 0) {
270                 TALLOC_FREE(servers);
271                 return false;
272         }
273         *server = servers[0];
274         TALLOC_FREE(servers);
275         return true;
276 }
277
278 struct server_id_db_traverse_state {
279         TALLOC_CTX *mem_ctx;
280         int (*fn)(const char *name,
281                   unsigned num_servers,
282                   const struct server_id *servers,
283                   void *private_data);
284         void *private_data;
285 };
286
287 static int server_id_db_traverse_fn(struct tdb_context *tdb,
288                                     TDB_DATA key, TDB_DATA data,
289                                     void *private_data)
290 {
291         struct server_id_db_traverse_state *state = private_data;
292         const char *name;
293         char *ids, *id;
294         unsigned num_servers;
295         struct server_id *servers;
296         int i, ret;
297
298         if (key.dsize == 0) {
299                 return 0;
300         }
301         if (key.dptr[key.dsize-1] != '\0') {
302                 return 0;
303         }
304         name = (const char *)key.dptr;
305
306         ids = (char *)talloc_memdup(state->mem_ctx, data.dptr, data.dsize);
307         if (ids == NULL) {
308                 return 0;
309         }
310
311         num_servers = strv_count(ids);
312         servers = talloc_array(ids, struct server_id, num_servers);
313
314         i = 0;
315
316         for (id = ids; id != NULL; id = strv_next(ids, id)) {
317                 servers[i++] = server_id_from_string(NONCLUSTER_VNN, id);
318         }
319
320         ret = state->fn(name, num_servers, servers, state->private_data);
321
322         TALLOC_FREE(ids);
323
324         return ret;
325 }
326
327 int server_id_db_traverse_read(struct server_id_db *db,
328                                int (*fn)(const char *name,
329                                          unsigned num_servers,
330                                          const struct server_id *servers,
331                                          void *private_data),
332                                void *private_data)
333 {
334         struct server_id_db_traverse_state state;
335         int ret;
336
337         state = (struct server_id_db_traverse_state) {
338                 .fn = fn, .private_data = private_data,
339                 .mem_ctx = talloc_new(db)
340         };
341
342         if (state.mem_ctx == NULL) {
343                 return ENOMEM;
344         }
345
346         ret = tdb_traverse_read(db->tdb->tdb, server_id_db_traverse_fn,
347                                 &state);
348         TALLOC_FREE(state.mem_ctx);
349         return ret;
350 }