diff options
Diffstat (limited to 'ctdb/tools/ctdb.c')
-rw-r--r-- | ctdb/tools/ctdb.c | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/ctdb/tools/ctdb.c b/ctdb/tools/ctdb.c index e906a6939cf..b947705fb28 100644 --- a/ctdb/tools/ctdb.c +++ b/ctdb/tools/ctdb.c @@ -4254,6 +4254,155 @@ static int control_pdelete(struct ctdb_context *ctdb, int argc, const char **arg return 0; } +static const char *ptrans_parse_string(TALLOC_CTX *mem_ctx, const char *s, + TDB_DATA *data) +{ + const char *t; + size_t n; + const char *ret; /* Next byte after successfully parsed value */ + + /* Error, unless someone says otherwise */ + ret = NULL; + /* Indicates no value to parse */ + *data = tdb_null; + + /* Skip whitespace */ + n = strspn(s, " \t"); + t = s + n; + + if (t[0] == '"') { + /* Quoted ASCII string - no wide characters! */ + t++; + n = strcspn(t, "\""); + if (t[n] == '"') { + if (n > 0) { + data->dsize = n; + data->dptr = talloc_memdup(mem_ctx, t, n); + CTDB_NOMEM_ABORT(data->dptr); + } + ret = t + n + 1; + } else { + DEBUG(DEBUG_WARNING,("Unmatched \" in input %s\n", s)); + } + } else { + DEBUG(DEBUG_WARNING,("Unsupported input format in %s\n", s)); + } + + return ret; +} + +static bool ptrans_get_key_value(TALLOC_CTX *mem_ctx, FILE *file, + TDB_DATA *key, TDB_DATA *value) +{ + char line [1024]; /* FIXME: make this more flexible? */ + const char *t; + char *ptr; + + ptr = fgets(line, sizeof(line), file); + + if (ptr == NULL) { + return false; + } + + /* Get key */ + t = ptrans_parse_string(mem_ctx, line, key); + if (t == NULL || key->dptr == NULL) { + /* Line Ignored but not EOF */ + return true; + } + + /* Get value */ + t = ptrans_parse_string(mem_ctx, t, value); + if (t == NULL) { + /* Line Ignored but not EOF */ + talloc_free(key->dptr); + *key = tdb_null; + return true; + } + + return true; +} + +/* + * Update a persistent database as per file/stdin + */ +static int control_ptrans(struct ctdb_context *ctdb, + int argc, const char **argv) +{ + const char *db_name; + struct ctdb_db_context *ctdb_db; + TALLOC_CTX *tmp_ctx = talloc_new(ctdb); + struct ctdb_transaction_handle *h; + TDB_DATA key, value; + FILE *file; + int ret; + + if (argc != 2) { + talloc_free(tmp_ctx); + usage(); + } + + file = stdin; + if (strcmp(argv[1], "-") != 0) { + file = fopen(argv[1], "r"); + if (file == NULL) { + DEBUG(DEBUG_ERR,("Unable to open file for reading '%s'\n", argv[1])); + talloc_free(tmp_ctx); + return -1; + } + } + + db_name = argv[0]; + + ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, true, 0); + if (ctdb_db == NULL) { + DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name)); + goto error; + } + + h = ctdb_transaction_start(ctdb_db, tmp_ctx); + if (h == NULL) { + DEBUG(DEBUG_ERR,("Failed to start transaction on database %s\n", db_name)); + goto error; + } + + while (ptrans_get_key_value(tmp_ctx, file, &key, &value)) { + if (key.dsize != 0) { + ret = ctdb_transaction_store(h, key, value); + /* Minimise memory use */ + talloc_free(key.dptr); + if (value.dptr != NULL) { + talloc_free(value.dptr); + } + if (ret != 0) { + DEBUG(DEBUG_ERR,("Failed to store record\n")); + ctdb_transaction_cancel(h); + goto error; + } + } + } + + ret = ctdb_transaction_commit(h); + if (ret != 0) { + DEBUG(DEBUG_ERR,("Failed to commit transaction\n")); + goto error; + } + + if (file != stdin) { + fclose(file); + } + talloc_free(tmp_ctx); + return 0; + +error: + if (file != stdin) { + fclose(file); + } + + talloc_free(tmp_ctx); + return -1; +} + /* check if a service is bound to a port or not */ @@ -6115,6 +6264,7 @@ static const struct { { "pfetch", control_pfetch, false, false, "fetch a record from a persistent database", "<dbname|dbid> <key> [<file>]" }, { "pstore", control_pstore, false, false, "write a record to a persistent database", "<dbname|dbid> <key> <file containing record>" }, { "pdelete", control_pdelete, false, false, "delete a record from a persistent database", "<dbname|dbid> <key>" }, + { "ptrans", control_ptrans, false, false, "update a persistent database (from stdin)", "<dbname|dbid>" }, { "tfetch", control_tfetch, false, true, "fetch a record from a [c]tdb-file [-v]", "<tdb-file> <key> [<file>]" }, { "tstore", control_tstore, false, true, "store a record (including ltdb header)", "<tdb-file> <key> <data+header>" }, { "readkey", control_readkey, true, false, "read the content off a database key", "<tdb-file> <key>" }, |