smbd: Simplify cleanupdb a bit
[amitay/samba.git] / source3 / lib / cleanupdb.c
1 /*
2    Unix SMB/CIFS implementation.
3    Implementation of reliable cleanup events
4    Copyright (C) Ralph Boehme 2016
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "cleanupdb.h"
21
22 struct cleanup_key {
23         pid_t pid;
24 };
25
26 struct cleanup_rec {
27         bool unclean;
28 };
29
30 static struct tdb_wrap *cleanup_db(void)
31 {
32         static struct tdb_wrap *db;
33         char *db_path = NULL;
34         int tdbflags = TDB_INCOMPATIBLE_HASH | TDB_CLEAR_IF_FIRST |
35                 TDB_MUTEX_LOCKING;
36
37         if (db != NULL) {
38                 return db;
39         }
40
41         db_path = lock_path("smbd_cleanupd.tdb");
42         if (db_path == NULL) {
43                 return NULL;
44         }
45
46         db = tdb_wrap_open(NULL, db_path, 0, tdbflags,
47                            O_CREAT | O_RDWR, 0644);
48         if (db == NULL) {
49                 DBG_ERR("Failed to open smbd_cleanupd.tdb\n");
50         }
51
52         TALLOC_FREE(db_path);
53         return db;
54 }
55
56 bool cleanupdb_store_child(const pid_t pid, const bool unclean)
57 {
58         struct tdb_wrap *db;
59         struct cleanup_key key = { .pid = pid };
60         struct cleanup_rec rec = { .unclean = unclean };
61         TDB_DATA tdbkey = { .dptr = (uint8_t *)&key, .dsize = sizeof(key) };
62         TDB_DATA tdbdata = { .dptr = (uint8_t *)&rec, .dsize = sizeof(rec) };
63         int result;
64
65         db = cleanup_db();
66         if (db == NULL) {
67                 return false;
68         }
69
70         result = tdb_store(db->tdb, tdbkey, tdbdata, TDB_REPLACE);
71         if (result != 0) {
72                 DBG_ERR("tdb_store failed for pid %d\n", (int)pid);
73                 return false;
74         }
75
76         return true;
77 }
78
79 bool cleanupdb_delete_child(const pid_t pid)
80 {
81         struct tdb_wrap *db;
82         struct cleanup_key key = { .pid = pid };
83         TDB_DATA tdbkey = { .dptr = (uint8_t *)&key, .dsize = sizeof(key) };
84         int result;
85
86         db = cleanup_db();
87         if (db == NULL) {
88                 return false;
89         }
90
91         result = tdb_delete(db->tdb, tdbkey);
92         if (result != 0) {
93                 DBG_ERR("tdb_delete failed for pid %d\n", (int)pid);
94                 return false;
95         }
96
97         return true;
98 }
99
100 struct cleanup_read_state {
101         int (*fn)(const pid_t pid, const bool cleanup, void *private_data);
102         void *private_data;
103 };
104
105 static int cleanup_traverse_fn(struct tdb_context *tdb,
106                                TDB_DATA key, TDB_DATA value,
107                                void *private_data)
108 {
109         struct cleanup_read_state *state =
110                 (struct cleanup_read_state *)private_data;
111         struct cleanup_key ckey;
112         struct cleanup_rec rec;
113         int result;
114
115         if (key.dsize != sizeof(struct cleanup_key)) {
116                 DBG_ERR("Found invalid key length %zu in cleanup.tdb\n",
117                         key.dsize);
118                 return -1;
119         }
120         memcpy(&ckey, key.dptr, sizeof(struct cleanup_key));
121
122         if (value.dsize != sizeof(struct cleanup_rec)) {
123                 DBG_ERR("Found invalid value length %zu in cleanup.tdb\n",
124                         value.dsize);
125                 return -1;
126         }
127         memcpy(&rec, value.dptr, sizeof(struct cleanup_rec));
128
129         result = state->fn(ckey.pid, rec.unclean, state->private_data);
130         if (result != 0) {
131                 return -1;
132         }
133
134         return 0;
135 }
136
137 int cleanupdb_traverse_read(int (*fn)(const pid_t pid,
138                                       const bool cleanup,
139                                       void *private_data),
140                             void *private_data)
141 {
142         struct tdb_wrap *db;
143         struct cleanup_read_state state;
144         int result;
145
146         db = cleanup_db();
147         if (db == NULL) {
148                 return -1;
149         }
150
151         state = (struct cleanup_read_state) {
152                 .fn = fn,
153                 .private_data = private_data
154         };
155
156         result = tdb_traverse_read(db->tdb, cleanup_traverse_fn, &state);
157         if (result < 0) {
158                 DBG_ERR("tdb_traverse_read failed\n");
159                 return -1;
160         }
161
162         return result;
163 }