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