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