33ef94f6b95e7edefc3b208304645060dbdfa6dd
[obnox/samba/samba-obnox.git] / source3 / utils / dbwrap_tool.c
1 /*
2    Samba Unix/Linux CIFS implementation
3
4    low level TDB/CTDB tool using the dbwrap interface
5
6    Copyright (C) 2009 Michael Adam <obnox@samba.org>
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "system/filesys.h"
24 #include "popt_common.h"
25 #include "dbwrap/dbwrap.h"
26 #include "dbwrap/dbwrap_open.h"
27 #include "messages.h"
28
29 typedef enum { OP_FETCH, OP_STORE, OP_DELETE, OP_ERASE, OP_LISTKEYS } dbwrap_op;
30
31 typedef enum { TYPE_INT32, TYPE_UINT32 } dbwrap_type;
32
33 static int dbwrap_tool_fetch_int32(struct db_context *db,
34                                    const char *keyname,
35                                    void *data)
36 {
37         int32_t value;
38         NTSTATUS status;
39
40         status = dbwrap_fetch_int32(db, keyname, &value);
41         if (!NT_STATUS_IS_OK(status)) {
42                 d_printf("Error fetching int32 from key '%s': %s\n",
43                          keyname, nt_errstr(status));
44                 return -1;
45         }
46         d_printf("%d\n", value);
47
48         return 0;
49 }
50
51 static int dbwrap_tool_fetch_uint32(struct db_context *db,
52                                     const char *keyname,
53                                     void *data)
54 {
55         uint32_t value;
56         bool ret;
57
58         ret = dbwrap_fetch_uint32(db, keyname, &value);
59         if (ret) {
60                 d_printf("%u\n", value);
61                 return 0;
62         } else {
63                 d_fprintf(stderr, "ERROR: could not fetch uint32 key '%s'\n",
64                           keyname);
65                 return -1;
66         }
67 }
68
69 static int dbwrap_tool_store_int32(struct db_context *db,
70                                    const char *keyname,
71                                    void *data)
72 {
73         NTSTATUS status;
74         int32_t value = *((int32_t *)data);
75
76         status = dbwrap_trans_store_int32(db, keyname, value);
77
78         if (!NT_STATUS_IS_OK(status)) {
79                 d_fprintf(stderr, "ERROR: could not store int32 key '%s': %s\n",
80                           keyname, nt_errstr(status));
81                 return -1;
82         }
83
84         return 0;
85 }
86
87 static int dbwrap_tool_store_uint32(struct db_context *db,
88                                     const char *keyname,
89                                     void *data)
90 {
91         NTSTATUS status;
92         uint32_t value = *((uint32_t *)data);
93
94         status = dbwrap_trans_store_uint32(db, keyname, value);
95
96         if (!NT_STATUS_IS_OK(status)) {
97                 d_fprintf(stderr,
98                           "ERROR: could not store uint32 key '%s': %s\n",
99                           keyname, nt_errstr(status));
100                 return -1;
101         }
102
103         return 0;
104 }
105
106 static int dbwrap_tool_delete(struct db_context *db,
107                               const char *keyname,
108                               void *data)
109 {
110         NTSTATUS status;
111
112         status = dbwrap_trans_delete_bystring(db, keyname);
113
114         if (!NT_STATUS_IS_OK(status)) {
115                 d_fprintf(stderr, "ERROR deleting record %s : %s\n",
116                           keyname, nt_errstr(status));
117                 return -1;
118         }
119
120         return 0;
121 }
122
123 static int delete_fn(struct db_record *rec, void *priv)
124 {
125         dbwrap_record_delete(rec);
126         return 0;
127 }
128
129 /**
130  * dbwrap_tool_erase: erase the whole data base
131  * the keyname argument is not used.
132  */
133 static int dbwrap_tool_erase(struct db_context *db,
134                              const char *keyname,
135                              void *data)
136 {
137         NTSTATUS status;
138
139         status = dbwrap_traverse(db, delete_fn, NULL, NULL);
140
141         if (!NT_STATUS_IS_OK(status)) {
142                 d_fprintf(stderr, "ERROR erasing the database\n");
143                 return -1;
144         }
145
146         return 0;
147 }
148
149 static int listkey_fn(struct db_record *rec, void *private_data)
150 {
151         int length = dbwrap_record_get_key(rec).dsize;
152         unsigned char *p = (unsigned char *)dbwrap_record_get_key(rec).dptr;
153
154         while (length--) {
155                 if (isprint(*p) && !strchr("\"\\", *p)) {
156                         d_printf("%c", *p);
157                 } else {
158                         d_printf("\\%02X", *p);
159                 }
160                 p++;
161         }
162
163         d_printf("\n");
164
165         return 0;
166 }
167
168 static int dbwrap_tool_listkeys(struct db_context *db,
169                                 const char *keyname,
170                                 void *data)
171 {
172         NTSTATUS status;
173
174         status = dbwrap_traverse_read(db, listkey_fn, NULL, NULL);
175
176         if (!NT_STATUS_IS_OK(status)) {
177                 d_fprintf(stderr, "ERROR listing db keys\n");
178                 return -1;
179         }
180
181         return 0;
182 }
183
184 struct dbwrap_op_dispatch_table {
185         dbwrap_op op;
186         dbwrap_type type;
187         int (*cmd)(struct db_context *db,
188                    const char *keyname,
189                    void *data);
190 };
191
192 struct dbwrap_op_dispatch_table dispatch_table[] = {
193         { OP_FETCH,  TYPE_INT32,  dbwrap_tool_fetch_int32 },
194         { OP_FETCH,  TYPE_UINT32, dbwrap_tool_fetch_uint32 },
195         { OP_STORE,  TYPE_INT32,  dbwrap_tool_store_int32 },
196         { OP_STORE,  TYPE_UINT32, dbwrap_tool_store_uint32 },
197         { OP_DELETE, TYPE_INT32,  dbwrap_tool_delete },
198         { OP_ERASE,  TYPE_INT32,  dbwrap_tool_erase },
199         { OP_LISTKEYS, TYPE_INT32, dbwrap_tool_listkeys },
200         { 0, 0, NULL },
201 };
202
203 int main(int argc, const char **argv)
204 {
205         struct tevent_context *evt_ctx;
206         struct messaging_context *msg_ctx;
207         struct db_context *db;
208
209         uint16_t count;
210
211         const char *dbname;
212         const char *opname;
213         dbwrap_op op;
214         const char *keyname = "";
215         const char *keytype = "int32";
216         dbwrap_type type;
217         const char *valuestr = "0";
218         int32_t value = 0;
219
220         TALLOC_CTX *mem_ctx = talloc_stackframe();
221
222         int ret = 1;
223
224         struct poptOption popt_options[] = {
225                 POPT_AUTOHELP
226                 POPT_COMMON_SAMBA
227                 POPT_TABLEEND
228         };
229         int opt;
230         const char **extra_argv;
231         int extra_argc = 0;
232         poptContext pc;
233
234         load_case_tables();
235         lp_set_cmdline("log level", "0");
236         setup_logging(argv[0], DEBUG_STDERR);
237
238         pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
239
240         while ((opt = poptGetNextOpt(pc)) != -1) {
241                 switch (opt) {
242                 default:
243                         fprintf(stderr, "Invalid option %s: %s\n",
244                                 poptBadOption(pc, 0), poptStrerror(opt));
245                         goto done;
246                 }
247         }
248
249         /* setup the remaining options for the main program to use */
250         extra_argv = poptGetArgs(pc);
251         if (extra_argv) {
252                 extra_argv++;
253                 while (extra_argv[extra_argc]) extra_argc++;
254         }
255
256         lp_load_global(get_dyn_CONFIGFILE());
257
258         if ((extra_argc < 2) || (extra_argc > 5)) {
259                 d_fprintf(stderr,
260                           "USAGE: %s <database> <op> [<key> [<type> [<value>]]]\n"
261                           "       ops: fetch, store, delete, erase, listkeys\n"
262                           "       types: int32, uint32\n",
263                          argv[0]);
264                 goto done;
265         }
266
267         dbname = extra_argv[0];
268         opname = extra_argv[1];
269
270         if (strcmp(opname, "store") == 0) {
271                 if (extra_argc != 5) {
272                         d_fprintf(stderr, "ERROR: operation 'store' requires "
273                                   "value argument\n");
274                         goto done;
275                 }
276                 valuestr = extra_argv[4];
277                 keytype = extra_argv[3];
278                 keyname = extra_argv[2];
279                 op = OP_STORE;
280         } else if (strcmp(opname, "fetch") == 0) {
281                 if (extra_argc != 4) {
282                         d_fprintf(stderr, "ERROR: operation 'fetch' requires "
283                                   "type but not value argument\n");
284                         goto done;
285                 }
286                 op = OP_FETCH;
287                 keytype = extra_argv[3];
288                 keyname = extra_argv[2];
289         } else if (strcmp(opname, "delete") == 0) {
290                 if (extra_argc != 3) {
291                         d_fprintf(stderr, "ERROR: operation 'delete' does "
292                                   "not allow type nor value argument\n");
293                         goto done;
294                 }
295                 keyname = extra_argv[2];
296                 op = OP_DELETE;
297         } else if (strcmp(opname, "erase") == 0) {
298                 if (extra_argc != 2) {
299                         d_fprintf(stderr, "ERROR: operation 'erase' does "
300                                   "not take a key argument\n");
301                         goto done;
302                 }
303                 op = OP_ERASE;
304         } else if (strcmp(opname, "listkeys") == 0) {
305                 if (extra_argc != 2) {
306                         d_fprintf(stderr, "ERROR: operation 'listkeys' does "
307                                   "not take a key argument\n");
308                         goto done;
309                 }
310                 op = OP_LISTKEYS;
311         } else {
312                 d_fprintf(stderr,
313                           "ERROR: invalid op '%s' specified\n"
314                           "       supported ops: fetch, store, delete\n",
315                           opname);
316                 goto done;
317         }
318
319         if (strcmp(keytype, "int32") == 0) {
320                 type = TYPE_INT32;
321                 value = (int32_t)strtol(valuestr, NULL, 10);
322         } else if (strcmp(keytype, "uint32") == 0) {
323                 type = TYPE_UINT32;
324                 value = (int32_t)strtoul(valuestr, NULL, 10);
325         } else {
326                 d_fprintf(stderr, "ERROR: invalid type '%s' specified.\n"
327                                   "       supported types: int32, uint32\n",
328                                   keytype);
329                 goto done;
330         }
331
332         evt_ctx = tevent_context_init(mem_ctx);
333         if (evt_ctx == NULL) {
334                 d_fprintf(stderr, "ERROR: could not init event context\n");
335                 goto done;
336         }
337
338         msg_ctx = messaging_init(mem_ctx, procid_self(), evt_ctx);
339         if (msg_ctx == NULL) {
340                 d_fprintf(stderr, "ERROR: could not init messaging context\n");
341                 goto done;
342         }
343
344         db = db_open(mem_ctx, dbname, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
345         if (db == NULL) {
346                 d_fprintf(stderr, "ERROR: could not open dbname\n");
347                 goto done;
348         }
349
350         for (count = 0; dispatch_table[count].cmd != NULL; count++) {
351                 if ((op == dispatch_table[count].op) &&
352                     (type == dispatch_table[count].type))
353                 {
354                         ret = dispatch_table[count].cmd(db, keyname, &value);
355                         break;
356                 }
357         }
358
359 done:
360         TALLOC_FREE(mem_ctx);
361         return ret;
362 }