ef61ea9dbbf0e6f8210a67afc2d0cb5d01fe29d4
[sfrench/samba-autobuild/.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 "dbwrap.h"
24
25 extern bool AllowDebugChange;
26
27 typedef enum { OP_FETCH, OP_STORE, OP_DELETE, OP_ERASE, OP_LISTKEYS } dbwrap_op;
28
29 typedef enum { TYPE_INT32, TYPE_UINT32 } dbwrap_type;
30
31 static int dbwrap_tool_fetch_int32(struct db_context *db,
32                                    const char *keyname,
33                                    void *data)
34 {
35         int32_t value;
36
37         value = dbwrap_fetch_int32(db, keyname);
38         d_printf("%d\n", value);
39
40         return 0;
41 }
42
43 static int dbwrap_tool_fetch_uint32(struct db_context *db,
44                                     const char *keyname,
45                                     void *data)
46 {
47         uint32_t value;
48         bool ret;
49
50         ret = dbwrap_fetch_uint32(db, keyname, &value);
51         if (ret) {
52                 d_printf("%u\n", value);
53                 return 0;
54         } else {
55                 d_fprintf(stderr, "ERROR: could not fetch uint32 key '%s'\n",
56                           keyname);
57                 return -1;
58         }
59 }
60
61 static int dbwrap_tool_store_int32(struct db_context *db,
62                                    const char *keyname,
63                                    void *data)
64 {
65         NTSTATUS status;
66         int32_t value = *((int32_t *)data);
67
68         status = dbwrap_trans_store_int32(db, keyname, value);
69
70         if (!NT_STATUS_IS_OK(status)) {
71                 d_fprintf(stderr, "ERROR: could not store int32 key '%s': %s\n",
72                           keyname, nt_errstr(status));
73                 return -1;
74         }
75
76         return 0;
77 }
78
79 static int dbwrap_tool_store_uint32(struct db_context *db,
80                                     const char *keyname,
81                                     void *data)
82 {
83         NTSTATUS status;
84         uint32_t value = *((uint32_t *)data);
85
86         status = dbwrap_trans_store_uint32(db, keyname, value);
87
88         if (!NT_STATUS_IS_OK(status)) {
89                 d_fprintf(stderr,
90                           "ERROR: could not store uint32 key '%s': %s\n",
91                           keyname, nt_errstr(status));
92                 return -1;
93         }
94
95         return 0;
96 }
97
98 static int dbwrap_tool_delete(struct db_context *db,
99                               const char *keyname,
100                               void *data)
101 {
102         NTSTATUS status;
103
104         status = dbwrap_trans_delete_bystring(db, keyname);
105
106         if (!NT_STATUS_IS_OK(status)) {
107                 d_fprintf(stderr, "ERROR deleting record %s : %s\n",
108                           keyname, nt_errstr(status));
109                 return -1;
110         }
111
112         return 0;
113 }
114
115 static int delete_fn(struct db_record *rec, void *priv)
116 {
117         rec->delete_rec(rec);
118         return 0;
119 }
120
121 /**
122  * dbwrap_tool_erase: erase the whole data base
123  * the keyname argument is not used.
124  */
125 static int dbwrap_tool_erase(struct db_context *db,
126                              const char *keyname,
127                              void *data)
128 {
129         int ret;
130
131         ret = db->traverse(db, delete_fn, NULL);
132
133         if (ret < 0) {
134                 d_fprintf(stderr, "ERROR erasing the database\n");
135                 return -1;
136         }
137
138         return 0;
139 }
140
141 static int listkey_fn(struct db_record *rec, void *private_data)
142 {
143         int length = rec->key.dsize;
144         unsigned char *p = (unsigned char *)rec->key.dptr;
145
146         while (length--) {
147                 if (isprint(*p) && !strchr("\"\\", *p)) {
148                         d_printf("%c", *p);
149                 } else {
150                         d_printf("\\%02X", *p);
151                 }
152                 p++;
153         }
154
155         d_printf("\n");
156
157         return 0;
158 }
159
160 static int dbwrap_tool_listkeys(struct db_context *db,
161                                 const char *keyname,
162                                 void *data)
163 {
164         int ret;
165
166         ret = db->traverse_read(db, listkey_fn, NULL);
167
168         if (ret < 0) {
169                 d_fprintf(stderr, "ERROR listing db keys\n");
170                 return -1;
171         }
172
173         return 0;
174 }
175
176 struct dbwrap_op_dispatch_table {
177         dbwrap_op op;
178         dbwrap_type type;
179         int (*cmd)(struct db_context *db,
180                    const char *keyname,
181                    void *data);
182 };
183
184 struct dbwrap_op_dispatch_table dispatch_table[] = {
185         { OP_FETCH,  TYPE_INT32,  dbwrap_tool_fetch_int32 },
186         { OP_FETCH,  TYPE_UINT32, dbwrap_tool_fetch_uint32 },
187         { OP_STORE,  TYPE_INT32,  dbwrap_tool_store_int32 },
188         { OP_STORE,  TYPE_UINT32, dbwrap_tool_store_uint32 },
189         { OP_DELETE, TYPE_INT32,  dbwrap_tool_delete },
190         { OP_ERASE,  TYPE_INT32,  dbwrap_tool_erase },
191         { OP_LISTKEYS, TYPE_INT32, dbwrap_tool_listkeys },
192         { 0, 0, NULL },
193 };
194
195 int main(int argc, const char **argv)
196 {
197         struct tevent_context *evt_ctx;
198         struct messaging_context *msg_ctx;
199         struct db_context *db;
200
201         uint16_t count;
202
203         const char *dbname;
204         const char *opname;
205         dbwrap_op op;
206         const char *keyname = "";
207         const char *keytype = "int32";
208         dbwrap_type type;
209         const char *valuestr = "0";
210         int32_t value = 0;
211
212         TALLOC_CTX *mem_ctx = talloc_stackframe();
213
214         int ret = 1;
215
216         load_case_tables();
217         DEBUGLEVEL_CLASS[DBGC_ALL] = 0;
218         setup_logging(argv[0], DEBUG_STDERR);
219         AllowDebugChange = false;
220         lp_load(get_dyn_CONFIGFILE(), true, false, false, true);
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 }