s3:dbwrap: move all .c and .h files of dbwrap to lib/dbwrap/
[amitay/samba.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 "dbwrap/dbwrap.h"
25 #include "dbwrap/dbwrap_open.h"
26 #include "messages.h"
27
28 typedef enum { OP_FETCH, OP_STORE, OP_DELETE, OP_ERASE, OP_LISTKEYS } dbwrap_op;
29
30 typedef enum { TYPE_INT32, TYPE_UINT32 } dbwrap_type;
31
32 static int dbwrap_tool_fetch_int32(struct db_context *db,
33                                    const char *keyname,
34                                    void *data)
35 {
36         int32_t value;
37
38         value = dbwrap_fetch_int32(db, keyname);
39         d_printf("%d\n", value);
40
41         return 0;
42 }
43
44 static int dbwrap_tool_fetch_uint32(struct db_context *db,
45                                     const char *keyname,
46                                     void *data)
47 {
48         uint32_t value;
49         bool ret;
50
51         ret = dbwrap_fetch_uint32(db, keyname, &value);
52         if (ret) {
53                 d_printf("%u\n", value);
54                 return 0;
55         } else {
56                 d_fprintf(stderr, "ERROR: could not fetch uint32 key '%s'\n",
57                           keyname);
58                 return -1;
59         }
60 }
61
62 static int dbwrap_tool_store_int32(struct db_context *db,
63                                    const char *keyname,
64                                    void *data)
65 {
66         NTSTATUS status;
67         int32_t value = *((int32_t *)data);
68
69         status = dbwrap_trans_store_int32(db, keyname, value);
70
71         if (!NT_STATUS_IS_OK(status)) {
72                 d_fprintf(stderr, "ERROR: could not store int32 key '%s': %s\n",
73                           keyname, nt_errstr(status));
74                 return -1;
75         }
76
77         return 0;
78 }
79
80 static int dbwrap_tool_store_uint32(struct db_context *db,
81                                     const char *keyname,
82                                     void *data)
83 {
84         NTSTATUS status;
85         uint32_t value = *((uint32_t *)data);
86
87         status = dbwrap_trans_store_uint32(db, keyname, value);
88
89         if (!NT_STATUS_IS_OK(status)) {
90                 d_fprintf(stderr,
91                           "ERROR: could not store uint32 key '%s': %s\n",
92                           keyname, nt_errstr(status));
93                 return -1;
94         }
95
96         return 0;
97 }
98
99 static int dbwrap_tool_delete(struct db_context *db,
100                               const char *keyname,
101                               void *data)
102 {
103         NTSTATUS status;
104
105         status = dbwrap_trans_delete_bystring(db, keyname);
106
107         if (!NT_STATUS_IS_OK(status)) {
108                 d_fprintf(stderr, "ERROR deleting record %s : %s\n",
109                           keyname, nt_errstr(status));
110                 return -1;
111         }
112
113         return 0;
114 }
115
116 static int delete_fn(struct db_record *rec, void *priv)
117 {
118         rec->delete_rec(rec);
119         return 0;
120 }
121
122 /**
123  * dbwrap_tool_erase: erase the whole data base
124  * the keyname argument is not used.
125  */
126 static int dbwrap_tool_erase(struct db_context *db,
127                              const char *keyname,
128                              void *data)
129 {
130         int ret;
131
132         ret = db->traverse(db, delete_fn, NULL);
133
134         if (ret < 0) {
135                 d_fprintf(stderr, "ERROR erasing the database\n");
136                 return -1;
137         }
138
139         return 0;
140 }
141
142 static int listkey_fn(struct db_record *rec, void *private_data)
143 {
144         int length = rec->key.dsize;
145         unsigned char *p = (unsigned char *)rec->key.dptr;
146
147         while (length--) {
148                 if (isprint(*p) && !strchr("\"\\", *p)) {
149                         d_printf("%c", *p);
150                 } else {
151                         d_printf("\\%02X", *p);
152                 }
153                 p++;
154         }
155
156         d_printf("\n");
157
158         return 0;
159 }
160
161 static int dbwrap_tool_listkeys(struct db_context *db,
162                                 const char *keyname,
163                                 void *data)
164 {
165         int ret;
166
167         ret = db->traverse_read(db, listkey_fn, NULL);
168
169         if (ret < 0) {
170                 d_fprintf(stderr, "ERROR listing db keys\n");
171                 return -1;
172         }
173
174         return 0;
175 }
176
177 struct dbwrap_op_dispatch_table {
178         dbwrap_op op;
179         dbwrap_type type;
180         int (*cmd)(struct db_context *db,
181                    const char *keyname,
182                    void *data);
183 };
184
185 struct dbwrap_op_dispatch_table dispatch_table[] = {
186         { OP_FETCH,  TYPE_INT32,  dbwrap_tool_fetch_int32 },
187         { OP_FETCH,  TYPE_UINT32, dbwrap_tool_fetch_uint32 },
188         { OP_STORE,  TYPE_INT32,  dbwrap_tool_store_int32 },
189         { OP_STORE,  TYPE_UINT32, dbwrap_tool_store_uint32 },
190         { OP_DELETE, TYPE_INT32,  dbwrap_tool_delete },
191         { OP_ERASE,  TYPE_INT32,  dbwrap_tool_erase },
192         { OP_LISTKEYS, TYPE_INT32, dbwrap_tool_listkeys },
193         { 0, 0, NULL },
194 };
195
196 int main(int argc, const char **argv)
197 {
198         struct tevent_context *evt_ctx;
199         struct messaging_context *msg_ctx;
200         struct db_context *db;
201
202         uint16_t count;
203
204         const char *dbname;
205         const char *opname;
206         dbwrap_op op;
207         const char *keyname = "";
208         const char *keytype = "int32";
209         dbwrap_type type;
210         const char *valuestr = "0";
211         int32_t value = 0;
212
213         TALLOC_CTX *mem_ctx = talloc_stackframe();
214
215         int ret = 1;
216
217         load_case_tables();
218         lp_set_cmdline("log level", "0");
219         setup_logging(argv[0], DEBUG_STDERR);
220         lp_load_global(get_dyn_CONFIGFILE());
221
222         if ((argc < 3) || (argc > 6)) {
223                 d_fprintf(stderr,
224                           "USAGE: %s <database> <op> [<key> [<type> [<value>]]]\n"
225                           "       ops: fetch, store, delete, erase, listkeys\n"
226                           "       types: int32, uint32\n",
227                          argv[0]);
228                 goto done;
229         }
230
231         dbname = argv[1];
232         opname = argv[2];
233
234         if (strcmp(opname, "store") == 0) {
235                 if (argc != 6) {
236                         d_fprintf(stderr, "ERROR: operation 'store' requires "
237                                   "value argument\n");
238                         goto done;
239                 }
240                 valuestr = argv[5];
241                 keytype = argv[4];
242                 keyname = argv[3];
243                 op = OP_STORE;
244         } else if (strcmp(opname, "fetch") == 0) {
245                 if (argc != 5) {
246                         d_fprintf(stderr, "ERROR: operation 'fetch' requires "
247                                   "type but not value argument\n");
248                         goto done;
249                 }
250                 op = OP_FETCH;
251                 keytype = argv[4];
252                 keyname = argv[3];
253         } else if (strcmp(opname, "delete") == 0) {
254                 if (argc != 4) {
255                         d_fprintf(stderr, "ERROR: operation 'delete' does "
256                                   "not allow type nor value argument\n");
257                         goto done;
258                 }
259                 keyname = argv[3];
260                 op = OP_DELETE;
261         } else if (strcmp(opname, "erase") == 0) {
262                 if (argc != 3) {
263                         d_fprintf(stderr, "ERROR: operation 'erase' does "
264                                   "not take a key argument\n");
265                         goto done;
266                 }
267                 op = OP_ERASE;
268         } else if (strcmp(opname, "listkeys") == 0) {
269                 if (argc != 3) {
270                         d_fprintf(stderr, "ERROR: operation 'listkeys' does "
271                                   "not take a key argument\n");
272                         goto done;
273                 }
274                 op = OP_LISTKEYS;
275         } else {
276                 d_fprintf(stderr,
277                           "ERROR: invalid op '%s' specified\n"
278                           "       supported ops: fetch, store, delete\n",
279                           opname);
280                 goto done;
281         }
282
283         if (strcmp(keytype, "int32") == 0) {
284                 type = TYPE_INT32;
285                 value = (int32_t)strtol(valuestr, NULL, 10);
286         } else if (strcmp(keytype, "uint32") == 0) {
287                 type = TYPE_UINT32;
288                 value = (int32_t)strtoul(valuestr, NULL, 10);
289         } else {
290                 d_fprintf(stderr, "ERROR: invalid type '%s' specified.\n"
291                                   "       supported types: int32, uint32\n",
292                                   keytype);
293                 goto done;
294         }
295
296         evt_ctx = tevent_context_init(mem_ctx);
297         if (evt_ctx == NULL) {
298                 d_fprintf(stderr, "ERROR: could not init event context\n");
299                 goto done;
300         }
301
302         msg_ctx = messaging_init(mem_ctx, procid_self(), evt_ctx);
303         if (msg_ctx == NULL) {
304                 d_fprintf(stderr, "ERROR: could not init messaging context\n");
305                 goto done;
306         }
307
308         db = db_open(mem_ctx, dbname, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
309         if (db == NULL) {
310                 d_fprintf(stderr, "ERROR: could not open dbname\n");
311                 goto done;
312         }
313
314         for (count = 0; dispatch_table[count].cmd != NULL; count++) {
315                 if ((op == dispatch_table[count].op) &&
316                     (type == dispatch_table[count].type))
317                 {
318                         ret = dispatch_table[count].cmd(db, keyname, &value);
319                         break;
320                 }
321         }
322
323 done:
324         TALLOC_FREE(mem_ctx);
325         return ret;
326 }