/* Unix SMB/CIFS implementation. Implementation of reliable cleanup events Copyright (C) Ralph Boehme 2016 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "cleanupdb.h" struct cleanup_key { pid_t pid; }; struct cleanup_rec { /* Storing the pid here as well saves a few lines of code */ pid_t pid; bool unclean; }; static struct tdb_wrap *cleanup_db(void) { static struct tdb_wrap *db; char *db_path = NULL; int tdbflags = TDB_INCOMPATIBLE_HASH | TDB_CLEAR_IF_FIRST | TDB_MUTEX_LOCKING; if (db != NULL) { return db; } db_path = lock_path("smbd_cleanupd.tdb"); if (db_path == NULL) { return NULL; } db = tdb_wrap_open(NULL, db_path, 0, tdbflags, O_CREAT | O_RDWR, 0644); if (db == NULL) { DBG_ERR("Failed to open smbd_cleanupd.tdb\n"); } TALLOC_FREE(db_path); return db; } bool cleanupdb_store_child(const pid_t pid, const bool unclean) { struct tdb_wrap *db; struct cleanup_key key = { .pid = pid }; struct cleanup_rec rec = { .pid = pid, .unclean = unclean }; TDB_DATA tdbkey = { .dptr = (uint8_t *)&key, .dsize = sizeof(key) }; TDB_DATA tdbdata = { .dptr = (uint8_t *)&rec, .dsize = sizeof(rec) }; int result; db = cleanup_db(); if (db == NULL) { return false; } result = tdb_store(db->tdb, tdbkey, tdbdata, TDB_REPLACE); if (result != 0) { DBG_ERR("tdb_store failed for pid %d\n", (int)pid); return false; } return true; } bool cleanupdb_delete_child(const pid_t pid) { struct tdb_wrap *db; struct cleanup_key key = { .pid = pid }; TDB_DATA tdbkey = { .dptr = (uint8_t *)&key, .dsize = sizeof(key) }; int result; db = cleanup_db(); if (db == NULL) { return false; } result = tdb_delete(db->tdb, tdbkey); if (result != 0) { DBG_ERR("tdb_delete failed for pid %d\n", (int)pid); return false; } return true; } static bool cleanup_rec_parse(TDB_DATA tdbdata, struct cleanup_rec *cleanup_rec) { if (tdbdata.dsize != sizeof(struct cleanup_rec)) { DBG_ERR("Found invalid value length %d in cleanup.tdb\n", (int)tdbdata.dsize); return false; } memcpy(cleanup_rec, tdbdata.dptr, sizeof(struct cleanup_rec)); return true; } struct cleanup_read_state { int (*fn)(const pid_t pid, const bool cleanup, void *private_data); void *private_data; }; static int cleanup_traverse_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA value, void *private_data) { struct cleanup_read_state *state = (struct cleanup_read_state *)private_data; struct cleanup_rec rec; bool ok; int result; ok = cleanup_rec_parse(value, &rec); if (!ok) { return -1; } result = state->fn(rec.pid, rec.unclean, state->private_data); if (result != 0) { return -1; } return 0; } int cleanupdb_traverse_read(int (*fn)(const pid_t pid, const bool cleanup, void *private_data), void *private_data) { struct tdb_wrap *db; struct cleanup_read_state state; int result; db = cleanup_db(); if (db == NULL) { return -1; } state = (struct cleanup_read_state) { .fn = fn, .private_data = private_data }; result = tdb_traverse_read(db->tdb, cleanup_traverse_fn, &state); if (result < 0) { DBG_ERR("tdb_traverse_read failed\n"); return -1; } return result; }