static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) { if (level <= TDB_DEBUG_ERROR) { va_list ap; this_log_level = level; char newfmt[strlen(tdb_name(tdb)) + 1 + strlen(fmt) + 1]; sprintf(newfmt, "%s:%s", tdb_name(tdb), fmt); va_start(ap, fmt); do_debug_v(newfmt, ap); va_end(ap); } }
/* * internal validation function, executed by the child. */ static int tdb_validate_child(struct tdb_context *tdb, tdb_validate_data_func validate_fn) { int ret = 1; int num_entries = 0; struct tdb_validation_status v_status; v_status.tdb_error = False; v_status.bad_freelist = False; v_status.bad_entry = False; v_status.unknown_key = False; v_status.success = True; if (!tdb) { v_status.tdb_error = True; v_status.success = False; goto out; } /* Check if the tdb's freelist is good. */ if (tdb_validate_freelist(tdb, &num_entries) == -1) { v_status.bad_freelist = True; v_status.success = False; goto out; } DEBUG(10,("tdb_validate_child: tdb %s freelist has %d entries\n", tdb_name(tdb), num_entries)); /* Now traverse the tdb to validate it. */ num_entries = tdb_traverse(tdb, validate_fn, (void *)&v_status); if (!v_status.success) { goto out; } else if (num_entries == -1) { v_status.tdb_error = True; v_status.success = False; goto out; } DEBUG(10,("tdb_validate_child: tdb %s is good with %d entries\n", tdb_name(tdb), num_entries)); ret = 0; /* Cache is good. */ out: DEBUG(10, ("tdb_validate_child: summary of validation status:\n")); DEBUGADD(10,(" * tdb error: %s\n", v_status.tdb_error ? "yes" : "no")); DEBUGADD(10,(" * bad freelist: %s\n",v_status.bad_freelist?"yes":"no")); DEBUGADD(10,(" * bad entry: %s\n", v_status.bad_entry ? "yes" : "no")); DEBUGADD(10,(" * unknown key: %s\n", v_status.unknown_key?"yes":"no")); DEBUGADD(10,(" => overall success: %s\n", v_status.success?"yes":"no")); return ret; }
static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) { va_list ap; const char *name = tdb_name(tdb); const char *prefix = ""; if (!name) name = "unnamed"; switch (level) { case TDB_DEBUG_ERROR: prefix = "ERROR: "; break; case TDB_DEBUG_WARNING: prefix = "WARNING: "; break; case TDB_DEBUG_TRACE: return; default: case TDB_DEBUG_FATAL: prefix = "FATAL: "; break; } va_start(ap, fmt); fprintf(stderr, "tdb(%s): %s", name, prefix); vfprintf(stderr, fmt, ap); va_end(ap); }
static void ltdb_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) { va_list ap; const char *name = tdb_name(tdb); struct ldb_context *ldb = talloc_get_type(tdb_get_logging_private(tdb), struct ldb_context); enum ldb_debug_level ldb_level; char *message; if (ldb == NULL) return; va_start(ap, fmt); message = talloc_vasprintf(ldb, fmt, ap); va_end(ap); switch (level) { case TDB_DEBUG_FATAL: ldb_level = LDB_DEBUG_FATAL; break; case TDB_DEBUG_ERROR: ldb_level = LDB_DEBUG_ERROR; break; case TDB_DEBUG_WARNING: ldb_level = LDB_DEBUG_WARNING; break; case TDB_DEBUG_TRACE: ldb_level = LDB_DEBUG_TRACE; break; default: ldb_level = LDB_DEBUG_FATAL; } ldb_debug(ldb, ldb_level, "ltdb: tdb(%s): %s", name, message); talloc_free(message); }
static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, const char *format, ...) { va_list ap; char *ptr = NULL; int debuglevel = 0; int ret; switch (level) { case TDB_DEBUG_FATAL: debuglevel = 0; break; case TDB_DEBUG_ERROR: debuglevel = 1; break; case TDB_DEBUG_WARNING: debuglevel = 2; break; case TDB_DEBUG_TRACE: debuglevel = 5; break; default: debuglevel = 0; } va_start(ap, format); ret = vasprintf(&ptr, format, ap); va_end(ap); if (ret != -1) { const char *name = tdb_name(tdb); DEBUG(debuglevel, ("tdb(%s): %s", name ? name : "unnamed", ptr)); free(ptr); } }
static int tdb_chainlock_with_timeout_internal( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout, int rw_type) { /* Allow tdb_chainlock to be interrupted by an alarm. */ int ret; gotalarm = 0; if (timeout) { CatchSignal(SIGALRM, gotalarm_sig); tdb_setalarm_sigptr(tdb, &gotalarm); alarm(timeout); } if (rw_type == F_RDLCK) ret = tdb_chainlock_read(tdb, key); else ret = tdb_chainlock(tdb, key); if (timeout) { alarm(0); tdb_setalarm_sigptr(tdb, NULL); CatchSignal(SIGALRM, SIG_IGN); if (gotalarm && (ret != 0)) { DEBUG(0,("tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n", timeout, key.dptr, tdb_name(tdb))); /* TODO: If we time out waiting for a lock, it might * be nice to use F_GETLK to get the pid of the * process currently holding the lock and print that * as part of the debugging message. -- mbp */ return -1; } } return ret == 0 ? 0 : -1; }
static uint32_t _reg_perfcount_multi_sz_from_tdb(TDB_CONTEXT *tdb, int keyval, char **retbuf, uint32_t buffer_size) { TDB_DATA kbuf, dbuf; char temp[PERFCOUNT_MAX_LEN] = {0}; char *buf1 = *retbuf; uint32_t working_size = 0; DATA_BLOB name_index, name; bool ok; snprintf(temp, sizeof(temp), "%d", keyval); kbuf = string_tdb_data(temp); dbuf = tdb_fetch(tdb, kbuf); if(dbuf.dptr == NULL) { /* If a key isn't there, just bypass it -- this really shouldn't happen unless someone's mucking around with the tdb */ DEBUG(3, ("_reg_perfcount_multi_sz_from_tdb: failed to find key [%s] in [%s].\n", temp, tdb_name(tdb))); return buffer_size; } /* First encode the name_index */ working_size = (kbuf.dsize + 1)*sizeof(uint16_t); buf1 = (char *)SMB_REALLOC(buf1, buffer_size + working_size); if(!buf1) { buffer_size = 0; return buffer_size; } ok = push_reg_sz(talloc_tos(), &name_index, (const char *)kbuf.dptr); if (!ok) { buffer_size = 0; return buffer_size; } memcpy(buf1+buffer_size, (char *)name_index.data, working_size); buffer_size += working_size; /* Now encode the actual name */ working_size = (dbuf.dsize + 1)*sizeof(uint16_t); buf1 = (char *)SMB_REALLOC(buf1, buffer_size + working_size); if(!buf1) { buffer_size = 0; return buffer_size; } memset(temp, 0, sizeof(temp)); memcpy(temp, dbuf.dptr, dbuf.dsize); SAFE_FREE(dbuf.dptr); ok = push_reg_sz(talloc_tos(), &name, temp); if (!ok) { buffer_size = 0; return buffer_size; } memcpy(buf1+buffer_size, (char *)name.data, working_size); buffer_size += working_size; *retbuf = buf1; return buffer_size; }
int main(int argc, char *argv[]) { struct tdb_context *tdb; TDB_DATA key, data; plan_tests(13); agent = prepare_external_agent(); if (!agent) err(1, "preparing agent"); tdb = tdb_open_ex("run-traverse-in-transaction.tdb", 1024, TDB_CLEAR_IF_FIRST, O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL); ok1(tdb); key.dsize = strlen("hi"); key.dptr = (void *)"hi"; data.dptr = (void *)"world"; data.dsize = strlen("world"); ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0); ok1(external_agent_operation(agent, OPEN, tdb_name(tdb)) == SUCCESS); ok1(tdb_transaction_start(tdb) == 0); ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb)) == WOULD_HAVE_BLOCKED); tdb_traverse(tdb, traverse, NULL); /* That should *not* release the transaction lock! */ ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb)) == WOULD_HAVE_BLOCKED); tdb_traverse_read(tdb, traverse, NULL); /* That should *not* release the transaction lock! */ ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb)) == WOULD_HAVE_BLOCKED); ok1(tdb_transaction_commit(tdb) == 0); /* Now we should be fine. */ ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb)) == SUCCESS); tdb_close(tdb); return exit_status(); }
/* * Write a key with uin64 value */ static int partition_metadata_set_uint64(struct ldb_module *module, const char *key, uint64_t value, bool insert) { struct partition_private_data *data; struct tdb_context *tdb; TDB_DATA tdb_key, tdb_data; int tdb_flag; char *value_str; TALLOC_CTX *tmp_ctx; data = talloc_get_type_abort(ldb_module_get_private(module), struct partition_private_data); if (!data || !data->metadata || !data->metadata->db) { return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR, "partition_metadata: metadata tdb not initialized"); } tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { return ldb_module_oom(module); } tdb = data->metadata->db->tdb; value_str = talloc_asprintf(tmp_ctx, "%llu", (unsigned long long)value); if (value_str == NULL) { talloc_free(tmp_ctx); return ldb_module_oom(module); } tdb_key.dptr = (uint8_t *)discard_const_p(char, key); tdb_key.dsize = strlen(key); tdb_data.dptr = (uint8_t *)value_str; tdb_data.dsize = strlen(value_str); if (insert) { tdb_flag = TDB_INSERT; } else { tdb_flag = TDB_MODIFY; } if (tdb_store(tdb, tdb_key, tdb_data, tdb_flag) != 0) { int ret; char *error_string = talloc_asprintf(tmp_ctx, "%s: tdb_store of key %s failed: %s", tdb_name(tdb), key, tdb_errorstr(tdb)); ret = ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR, error_string); talloc_free(tmp_ctx); return ret; } talloc_free(tmp_ctx); return LDB_SUCCESS; }
static PyObject *tdb_object_repr(PyTdbObject *self) { PyErr_TDB_RAISE_IF_CLOSED(self); if (tdb_get_flags(self->ctx) & TDB_INTERNAL) { return PyString_FromString("Tdb(<internal>)"); } else { return PyString_FromFormat("Tdb('%s')", tdb_name(self->ctx)); } }
static void tdb_log(struct tdb_context *tdb, enum tdb_log_level level, enum TDB_ERROR ecode, const char *message, void *data) { fprintf(stderr, "tdb:%s:%s:%s\n", tdb_name(tdb), tdb_errorstr(ecode), message); }
static int copy_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state) { TDB_CONTEXT *tdb_new = (TDB_CONTEXT *)state; if (tdb_store(tdb_new, key, dbuf, TDB_INSERT) != 0) { fprintf(stderr,"Failed to insert into %s\n", tdb_name(tdb_new)); failed = 1; return 1; } return 0; }
static int traverse_copy_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, void *private_data) { struct tdb_copy_data *data = (struct tdb_copy_data *)private_data; if (tdb_store(data->dst, key, dbuf, TDB_INSERT) != 0) { DEBUG(4, ("Failed to insert into %s: %s\n", tdb_name(data->dst), strerror(errno))); data->success = False; return 1; } return 0; }
static void tdb_log(struct tdb_context *tdb, enum tdb_log_level level, enum TDB_ERROR ecode, const char *message, void *data) { printf("tdb:%s:%s:%s\n", tdb_name(tdb), tdb_errorstr(ecode), message); fflush(stdout); #if 0 { char str[200]; signal(SIGUSR1, SIG_IGN); sprintf(str,"xterm -e gdb /proc/%d/exe %d", getpid(), getpid()); system(str); } #endif }
static void ltdb_log_fn(struct tdb_context *tdb, enum tdb_log_level level, const char *message, struct ldb_context *ldb) { enum ldb_debug_level ldb_level; const char *name = tdb_name(tdb); switch (level) { case TDB_LOG_WARNING: ldb_level = LDB_DEBUG_WARNING; case TDB_LOG_USE_ERROR: case TDB_LOG_ERROR: ldb_level = LDB_DEBUG_FATAL; break; default: ldb_level = LDB_DEBUG_FATAL; } ldb_debug(ldb, ldb_level, "ltdb: tdb(%s): %s", name, message); }
/* we've made a modification to a dn - possibly reindex and update sequence number */ static int ltdb_modified(struct ldb_module *module, struct ldb_dn *dn) { int ret = LDB_SUCCESS; struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module), struct ltdb_private); /* only allow modifies inside a transaction, otherwise the * ldb is unsafe */ if (ltdb->in_transaction == 0) { ldb_set_errstring(ldb_module_get_ctx(module), "ltdb modify without transaction"); return LDB_ERR_OPERATIONS_ERROR; } if (ldb_dn_is_special(dn) && (ldb_dn_check_special(dn, LTDB_INDEXLIST) || ldb_dn_check_special(dn, LTDB_ATTRIBUTES)) ) { if (ltdb->warn_reindex) { ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR, "Reindexing %s due to modification on %s", tdb_name(ltdb->tdb), ldb_dn_get_linearized(dn)); } ret = ltdb_reindex(module); } /* If the modify was to a normal record, or any special except @BASEINFO, update the seq number */ if (ret == LDB_SUCCESS && !(ldb_dn_is_special(dn) && ldb_dn_check_special(dn, LTDB_BASEINFO)) ) { ret = ltdb_increase_sequence_number(module); } /* If the modify was to @OPTIONS, reload the cache */ if (ret == LDB_SUCCESS && ldb_dn_is_special(dn) && (ldb_dn_check_special(dn, LTDB_OPTIONS)) ) { ret = ltdb_cache_reload(module); } return ret; }
static void tdb_wrap_log(struct tdb_context *tdb, enum tdb_log_level level, const char *message, void *unused) { int dl; const char *name = tdb_name(tdb); switch (level) { case TDB_LOG_USE_ERROR: case TDB_LOG_ERROR: dl = 0; break; case TDB_LOG_WARNING: dl = 2; break; default: dl = 0; } DEBUG(dl, ("tdb(%s): %s", name ? name : "unnamed", message)); }
static enum agent_return do_operation(enum operation op, const char *name) { TDB_DATA k; enum agent_return ret; TDB_DATA data; enum TDB_ERROR ecode; union tdb_attribute cif; if (op != OPEN && op != OPEN_WITH_HOOK && !tdb) { diag("external: No tdb open!"); return OTHER_FAILURE; } diag("external: %s", operation_name(op)); k = tdb_mkdata(name, strlen(name)); locking_would_block = 0; switch (op) { case OPEN: if (tdb) { diag("Already have tdb %s open", tdb_name(tdb)); return OTHER_FAILURE; } tdb = tdb_open(name, TDB_DEFAULT, O_RDWR, 0, &tap_log_attr); if (!tdb) { if (!locking_would_block) diag("Opening tdb gave %s", strerror(errno)); forget_locking(); ret = OTHER_FAILURE; } else ret = SUCCESS; break; case OPEN_WITH_HOOK: if (tdb) { diag("Already have tdb %s open", tdb_name(tdb)); return OTHER_FAILURE; } cif.openhook.base.attr = TDB_ATTRIBUTE_OPENHOOK; cif.openhook.base.next = &tap_log_attr; cif.openhook.fn = clear_if_first; tdb = tdb_open(name, TDB_DEFAULT, O_RDWR, 0, &cif); if (!tdb) { if (!locking_would_block) diag("Opening tdb gave %s", strerror(errno)); forget_locking(); ret = OTHER_FAILURE; } else ret = SUCCESS; break; case FETCH: ecode = tdb_fetch(tdb, k, &data); if (ecode == TDB_ERR_NOEXIST) { ret = FAILED; } else if (ecode < 0) { ret = OTHER_FAILURE; } else if (!tdb_deq(data, k)) { ret = OTHER_FAILURE; external_agent_free(data.dptr); } else { ret = SUCCESS; external_agent_free(data.dptr); } break; case STORE: ret = tdb_store(tdb, k, k, 0) == 0 ? SUCCESS : OTHER_FAILURE; break; case TRANSACTION_START: ret = tdb_transaction_start(tdb) == 0 ? SUCCESS : OTHER_FAILURE; break; case TRANSACTION_COMMIT: ret = tdb_transaction_commit(tdb)==0 ? SUCCESS : OTHER_FAILURE; break; case NEEDS_RECOVERY: ret = external_agent_needs_rec(tdb); break; case CHECK: ret = tdb_check(tdb, NULL, NULL) == 0 ? SUCCESS : OTHER_FAILURE; break; case CLOSE: ret = tdb_close(tdb) == 0 ? SUCCESS : OTHER_FAILURE; tdb = NULL; break; case SEND_SIGNAL: /* We do this async */ ret = SUCCESS; break; default: ret = OTHER_FAILURE; } if (locking_would_block) ret = WOULD_HAVE_BLOCKED; return ret; }
struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, const char *name, int hash_size, int tdb_flags, int open_flags, mode_t mode, enum dbwrap_lock_order lock_order, uint64_t dbrwap_flags) { struct db_context *result = NULL; struct db_tdb_ctx *db_tdb; struct stat st; result = talloc_zero(mem_ctx, struct db_context); if (result == NULL) { DEBUG(0, ("talloc failed\n")); goto fail; } result->private_data = db_tdb = talloc(result, struct db_tdb_ctx); if (db_tdb == NULL) { DEBUG(0, ("talloc failed\n")); goto fail; } result->lock_order = lock_order; if (hash_size == 0) { hash_size = lpcfg_tdb_hash_size(lp_ctx, name); } db_tdb->wtdb = tdb_wrap_open(db_tdb, name, hash_size, lpcfg_tdb_flags(lp_ctx, tdb_flags), open_flags, mode); if (db_tdb->wtdb == NULL) { DEBUG(3, ("Could not open tdb: %s\n", strerror(errno))); goto fail; } ZERO_STRUCT(db_tdb->id); if (fstat(tdb_fd(db_tdb->wtdb->tdb), &st) == -1) { DEBUG(3, ("fstat failed: %s\n", strerror(errno))); goto fail; } db_tdb->id.dev = st.st_dev; db_tdb->id.ino = st.st_ino; result->fetch_locked = db_tdb_fetch_locked; result->try_fetch_locked = db_tdb_try_fetch_locked; result->traverse = db_tdb_traverse; result->traverse_read = db_tdb_traverse_read; result->parse_record = db_tdb_parse; result->get_seqnum = db_tdb_get_seqnum; result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0); result->transaction_start = db_tdb_transaction_start; result->transaction_start_nonblock = db_tdb_transaction_start_nonblock; result->transaction_commit = db_tdb_transaction_commit; result->transaction_cancel = db_tdb_transaction_cancel; result->exists = db_tdb_exists; result->wipe = db_tdb_wipe; result->id = db_tdb_id; result->check = db_tdb_check; result->name = tdb_name(db_tdb->wtdb->tdb); result->hash_size = hash_size; return result; fail: TALLOC_FREE(result); return NULL; }
static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA _dbuf, void *state) { int ret, i, j; struct ldb_dn *dn = state; struct ldb_message *msg = talloc_zero(NULL, struct ldb_message); struct ldb_val dbuf = { .data = _dbuf.dptr, .length = _dbuf.dsize, }; struct ldb_ldif ldif = { .msg = msg, .changetype = LDB_CHANGETYPE_NONE }; if (!msg) { return -1; } ret = ldb_unpack_data(ldb, &dbuf, msg); if (ret != 0) { fprintf(stderr, "Failed to parse record %*.*s as an LDB record\n", (int)key.dsize, (int)key.dsize, (char *)key.dptr); TALLOC_FREE(msg); return 0; } if (dn && ldb_dn_compare(msg->dn, dn) != 0) { TALLOC_FREE(msg); return 0; } if (!show_index && ldb_dn_is_special(msg->dn)) { const char *dn_lin = ldb_dn_get_linearized(msg->dn); if ((strcmp(dn_lin, "@BASEINFO") == 0) || (strncmp(dn_lin, "@INDEX:", strlen("@INDEX:")) == 0)) { /* the user has asked not to show index records. Also exclude BASEINFO as it contains meta-data which will be re-created if this database is restored */ TALLOC_FREE(msg); return 0; } } if (!validate_contents || ldb_dn_is_special(msg->dn)) { ldb_ldif_write_file(ldb, stdout, &ldif); TALLOC_FREE(msg); return 0; } for (i=0;i<msg->num_elements;i++) { const struct ldb_schema_attribute *a; a = ldb_schema_attribute_by_name(ldb, msg->elements[i].name); for (j=0;j<msg->elements[i].num_values;j++) { struct ldb_val v; ret = a->syntax->ldif_write_fn(ldb, msg, &msg->elements[i].values[j], &v); if (ret != 0) { v = msg->elements[i].values[j]; if (ldb_should_b64_encode(ldb, &v)) { v.data = (uint8_t *)ldb_base64_encode(ldb, (char *)v.data, v.length); v.length = strlen((char *)v.data); } fprintf(stderr, "On %s element %s value %d (%*.*s) failed to convert to LDIF correctly, skipping possibly corrupt record\n", ldb_dn_get_linearized(msg->dn), msg->elements[i].name, j, (int)v.length, (int)v.length, v.data); TALLOC_FREE(msg); return 0; } } } ldb_ldif_write_file(ldb, stdout, &ldif); TALLOC_FREE(msg); return 0; } static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3,4); static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) { va_list ap; const char *name = tdb_name(tdb); const char *prefix = ""; if (!name) name = "unnamed"; switch (level) { case TDB_DEBUG_ERROR: prefix = "ERROR: "; break; case TDB_DEBUG_WARNING: prefix = "WARNING: "; break; case TDB_DEBUG_TRACE: return; default: case TDB_DEBUG_FATAL: prefix = "FATAL: "; break; } va_start(ap, fmt); fprintf(stderr, "tdb(%s): %s", name, prefix); vfprintf(stderr, fmt, ap); va_end(ap); }
static PyObject *obj_get_filename(PyTdbObject *self, void *closure) { PyErr_TDB_RAISE_IF_CLOSED(self); return PyString_FromString(tdb_name(self->ctx)); }
/* * tdb validation function. * returns 0 if tdb is ok, != 0 if it isn't. * this function expects an opened tdb. */ int tdb_validate(struct tdb_context *tdb, tdb_validate_data_func validate_fn) { pid_t child_pid = -1; int child_status = 0; int wait_pid = 0; int ret = 1; if (tdb == NULL) { DEBUG(1, ("Error: tdb_validate called with tdb == NULL\n")); return ret; } DEBUG(5, ("tdb_validate called for tdb '%s'\n", tdb_name(tdb))); /* fork and let the child do the validation. * benefit: no need to twist signal handlers and panic functions. * just let the child panic. we catch the signal. */ DEBUG(10, ("tdb_validate: forking to let child do validation.\n")); child_pid = sys_fork(); if (child_pid == 0) { /* child code */ DEBUG(10, ("tdb_validate (validation child): created\n")); DEBUG(10, ("tdb_validate (validation child): " "calling tdb_validate_child\n")); exit(tdb_validate_child(tdb, validate_fn)); } else if (child_pid < 0) { DEBUG(1, ("tdb_validate: fork for validation failed.\n")); goto done; } /* parent */ DEBUG(10, ("tdb_validate: fork succeeded, child PID = %u\n", (unsigned int)child_pid)); DEBUG(10, ("tdb_validate: waiting for child to finish...\n")); while ((wait_pid = sys_waitpid(child_pid, &child_status, 0)) < 0) { if (errno == EINTR) { DEBUG(10, ("tdb_validate: got signal during waitpid, " "retrying\n")); errno = 0; continue; } DEBUG(1, ("tdb_validate: waitpid failed with error '%s'.\n", strerror(errno))); goto done; } if (wait_pid != child_pid) { DEBUG(1, ("tdb_validate: waitpid returned pid %d, " "but %u was expected\n", wait_pid, (unsigned int)child_pid)); goto done; } DEBUG(10, ("tdb_validate: validating child returned.\n")); if (WIFEXITED(child_status)) { DEBUG(10, ("tdb_validate: child exited, code %d.\n", WEXITSTATUS(child_status))); ret = WEXITSTATUS(child_status); } if (WIFSIGNALED(child_status)) { DEBUG(10, ("tdb_validate: child terminated by signal %d\n", WTERMSIG(child_status))); #ifdef WCOREDUMP if (WCOREDUMP(child_status)) { DEBUGADD(10, ("core dumped\n")); } #endif ret = WTERMSIG(child_status); } if (WIFSTOPPED(child_status)) { DEBUG(10, ("tdb_validate: child was stopped by signal %d\n", WSTOPSIG(child_status))); ret = WSTOPSIG(child_status); } done: DEBUG(5, ("tdb_validate returning code '%d' for tdb '%s'\n", ret, tdb_name(tdb))); return ret; }
static enum agent_return do_operation(enum operation op, const char *name) { TDB_DATA k; enum agent_return ret; TDB_DATA data; if (op != OPEN && op != OPEN_WITH_CLEAR_IF_FIRST && !tdb) { diag("external: No tdb open!"); return OTHER_FAILURE; } k.dptr = (void *)name; k.dsize = strlen(name); locking_would_block = 0; switch (op) { case OPEN: if (tdb) { diag("Already have tdb %s open", tdb_name(tdb)); return OTHER_FAILURE; } tdb = tdb_open_ex(name, 0, TDB_DEFAULT, O_RDWR, 0, &taplogctx, NULL); if (!tdb) { if (!locking_would_block) diag("Opening tdb gave %s", strerror(errno)); ret = OTHER_FAILURE; } else ret = SUCCESS; break; case OPEN_WITH_CLEAR_IF_FIRST: if (tdb) return OTHER_FAILURE; tdb = tdb_open_ex(name, 0, TDB_CLEAR_IF_FIRST, O_RDWR, 0, &taplogctx, NULL); ret = tdb ? SUCCESS : OTHER_FAILURE; break; case TRANSACTION_START: ret = tdb_transaction_start(tdb) == 0 ? SUCCESS : OTHER_FAILURE; break; case FETCH: data = tdb_fetch(tdb, k); if (data.dptr == NULL) { if (tdb_error(tdb) == TDB_ERR_NOEXIST) ret = FAILED; else ret = OTHER_FAILURE; } else if (data.dsize != k.dsize || memcmp(data.dptr, k.dptr, k.dsize) != 0) { ret = OTHER_FAILURE; } else { ret = SUCCESS; } free(data.dptr); break; case STORE: ret = tdb_store(tdb, k, k, 0) == 0 ? SUCCESS : OTHER_FAILURE; break; case TRANSACTION_COMMIT: ret = tdb_transaction_commit(tdb)==0 ? SUCCESS : OTHER_FAILURE; break; case CHECK: ret = tdb_check(tdb, NULL, NULL) == 0 ? SUCCESS : OTHER_FAILURE; break; case NEEDS_RECOVERY: ret = tdb_needs_recovery(tdb) ? SUCCESS : FAILED; break; case CLOSE: ret = tdb_close(tdb) == 0 ? SUCCESS : OTHER_FAILURE; tdb = NULL; break; default: ret = OTHER_FAILURE; } if (locking_would_block) ret = WOULD_HAVE_BLOCKED; return ret; }