Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Test dbwrap_watch API
4 : Copyright (C) Volker Lendecke 2012
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 "includes.h"
21 : #include "torture/proto.h"
22 : #include "system/filesys.h"
23 : #include "lib/dbwrap/dbwrap.h"
24 : #include "lib/dbwrap/dbwrap_open.h"
25 : #include "lib/dbwrap/dbwrap_watch.h"
26 : #include "lib/util/util_tdb.h"
27 :
28 5 : static bool test_dbwrap_watch_init(
29 : TALLOC_CTX *mem_ctx,
30 : const char *dbname,
31 : struct tevent_context **pev,
32 : struct messaging_context **pmsg,
33 : struct db_context **pbackend,
34 : struct db_context **pdb)
35 : {
36 5 : struct tevent_context *ev = NULL;
37 5 : struct messaging_context *msg = NULL;
38 5 : struct db_context *backend = NULL;
39 5 : struct db_context *db = NULL;
40 :
41 5 : ev = samba_tevent_context_init(mem_ctx);
42 5 : if (ev == NULL) {
43 0 : fprintf(stderr, "tevent_context_init failed\n");
44 0 : goto fail;
45 : }
46 :
47 5 : msg = messaging_init(ev, ev);
48 5 : if (msg == NULL) {
49 0 : fprintf(stderr, "messaging_init failed\n");
50 0 : goto fail;
51 : }
52 :
53 5 : backend = db_open(
54 : msg,
55 : dbname,
56 : 0,
57 : TDB_CLEAR_IF_FIRST,
58 : O_CREAT|O_RDWR,
59 : 0644,
60 : DBWRAP_LOCK_ORDER_1,
61 : DBWRAP_FLAG_NONE);
62 5 : if (backend == NULL) {
63 0 : fprintf(stderr, "db_open failed: %s\n", strerror(errno));
64 0 : goto fail;
65 : }
66 :
67 : {
68 5 : struct db_context *backend_copy = backend;
69 :
70 5 : db = db_open_watched(ev, &backend_copy, msg);
71 5 : if (db == NULL) {
72 0 : fprintf(stderr, "db_open_watched failed\n");
73 0 : goto fail;
74 : }
75 : }
76 :
77 5 : if (pev != NULL) {
78 5 : *pev = ev;
79 : }
80 5 : if (pmsg != NULL) {
81 5 : *pmsg = msg;
82 : }
83 5 : if (pbackend != NULL) {
84 5 : *pbackend = backend;
85 : }
86 5 : if (pdb != NULL) {
87 5 : *pdb = db;
88 : }
89 0 : return true;
90 :
91 0 : fail:
92 0 : TALLOC_FREE(backend);
93 0 : TALLOC_FREE(msg);
94 0 : TALLOC_FREE(ev);
95 0 : return false;
96 : }
97 :
98 1 : bool run_dbwrap_watch1(int dummy)
99 : {
100 1 : struct tevent_context *ev = NULL;
101 1 : struct messaging_context *msg = NULL;
102 1 : struct db_context *backend = NULL;
103 1 : struct db_context *db = NULL;
104 1 : const char *keystr = "key";
105 1 : TDB_DATA key = string_term_tdb_data(keystr);
106 1 : struct db_record *rec = NULL;
107 1 : struct tevent_req *req = NULL;
108 1 : NTSTATUS status;
109 1 : bool ret = false;
110 :
111 1 : ret = test_dbwrap_watch_init(
112 : talloc_tos(), "test_watch.tdb", &ev, &msg, &backend, &db);
113 1 : if (!ret) {
114 0 : goto fail;
115 : }
116 :
117 1 : rec = dbwrap_fetch_locked(db, db, key);
118 1 : if (rec == NULL) {
119 0 : fprintf(stderr, "dbwrap_fetch_locked failed\n");
120 0 : goto fail;
121 : }
122 1 : req = dbwrap_watched_watch_send(talloc_tos(), ev, rec,
123 : 0, /* resume_instance */
124 1 : (struct server_id){0});
125 1 : if (req == NULL) {
126 0 : fprintf(stderr, "dbwrap_record_watch_send failed\n");
127 0 : goto fail;
128 : }
129 1 : TALLOC_FREE(rec);
130 :
131 1 : status = dbwrap_store_int32_bystring(db, "different_key", 1);
132 1 : if (!NT_STATUS_IS_OK(status)) {
133 0 : fprintf(stderr, "dbwrap_store_int32 failed: %s\n",
134 : nt_errstr(status));
135 0 : goto fail;
136 : }
137 :
138 1 : status = dbwrap_store_int32_bystring(db, keystr, 1);
139 1 : if (!NT_STATUS_IS_OK(status)) {
140 0 : fprintf(stderr, "dbwrap_store_int32 failed: %s\n",
141 : nt_errstr(status));
142 0 : goto fail;
143 : }
144 :
145 1 : if (!tevent_req_poll(req, ev)) {
146 0 : fprintf(stderr, "tevent_req_poll failed\n");
147 0 : goto fail;
148 : }
149 :
150 1 : status = dbwrap_watched_watch_recv(req, NULL, NULL, NULL);
151 1 : if (!NT_STATUS_IS_OK(status)) {
152 0 : fprintf(stderr, "dbwrap_record_watch_recv failed: %s\n",
153 : nt_errstr(status));
154 0 : goto fail;
155 : }
156 :
157 1 : (void)unlink("test_watch.tdb");
158 1 : ret = true;
159 1 : fail:
160 1 : TALLOC_FREE(req);
161 1 : TALLOC_FREE(rec);
162 1 : TALLOC_FREE(db);
163 1 : TALLOC_FREE(msg);
164 1 : TALLOC_FREE(ev);
165 1 : return ret;
166 : }
167 :
168 : /*
169 : * Make sure dbwrap_parse_record does not return NT_STATUS_OK on
170 : * invalid data
171 : */
172 :
173 1 : bool run_dbwrap_watch2(int dummy)
174 : {
175 1 : struct tevent_context *ev = NULL;
176 1 : struct messaging_context *msg = NULL;
177 1 : struct db_context *backend = NULL;
178 1 : struct db_context *db = NULL;
179 1 : const char *keystr = "key";
180 1 : TDB_DATA key = string_term_tdb_data(keystr);
181 1 : NTSTATUS status;
182 1 : bool ret = false;
183 :
184 1 : ret = test_dbwrap_watch_init(
185 : talloc_tos(), "test_watch.tdb", &ev, &msg, &backend, &db);
186 1 : if (!ret) {
187 0 : goto fail;
188 : }
189 :
190 : /*
191 : * Store invalid data (from the dbwrap_watch point of view)
192 : * directly into the backend database
193 : */
194 1 : status = dbwrap_store_uint32_bystring(backend, keystr, UINT32_MAX);
195 1 : if (!NT_STATUS_IS_OK(status)) {
196 0 : fprintf(stderr, "dbwrap_store_uint32_bystring failed: %s\n",
197 : nt_errstr(status));
198 0 : goto fail;
199 : }
200 :
201 1 : status = dbwrap_parse_record(db, key, NULL, NULL);
202 1 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
203 0 : fprintf(stderr, "dbwrap_parse_record returned %s, expected "
204 : "NT_STATUS_NOT_FOUND\n", nt_errstr(status));
205 0 : goto fail;
206 : }
207 :
208 1 : (void)unlink("test_watch.tdb");
209 1 : ret = true;
210 1 : fail:
211 1 : TALLOC_FREE(db);
212 1 : TALLOC_FREE(msg);
213 1 : TALLOC_FREE(ev);
214 1 : return ret;
215 : }
216 :
217 : /*
218 : * Test autocleanup of dead watchers
219 : */
220 :
221 1 : bool run_dbwrap_watch3(int dummy)
222 : {
223 1 : struct tevent_context *ev = NULL;
224 1 : struct messaging_context *msg = NULL;
225 1 : struct db_context *backend = NULL;
226 1 : struct db_context *db = NULL;
227 1 : const char *keystr = "key";
228 1 : TDB_DATA key = string_term_tdb_data(keystr);
229 1 : NTSTATUS status;
230 1 : bool ret = false;
231 1 : pid_t child, waited;
232 1 : int wstatus, exit_status;
233 :
234 1 : BlockSignals(true, SIGCHLD);
235 :
236 1 : child = fork();
237 2 : if (child == -1) {
238 0 : fprintf(stderr,
239 : "fork failed: %s\n",
240 0 : strerror(errno));
241 0 : goto fail;
242 : }
243 :
244 2 : ret = test_dbwrap_watch_init(
245 : talloc_tos(), "test_watch.tdb", &ev, &msg, &backend, &db);
246 2 : if (!ret) {
247 0 : goto fail;
248 : }
249 :
250 2 : if (child == 0) {
251 1 : struct db_record *rec = dbwrap_fetch_locked(db, db, key);
252 1 : struct tevent_req *req = NULL;
253 :
254 1 : if (rec == NULL) {
255 0 : fprintf(stderr, "dbwrap_fetch_locked failed\n");
256 0 : exit(1);
257 : }
258 :
259 2 : req = dbwrap_watched_watch_send(
260 1 : db, ev, rec, 0, (struct server_id) { 0 });
261 1 : if (req == NULL) {
262 0 : fprintf(stderr, "dbwrap_watched_watch_send failed\n");
263 0 : exit(2);
264 : }
265 :
266 1 : exit(0);
267 : }
268 :
269 1 : waited = waitpid(child, &wstatus, 0);
270 1 : if (waited == -1) {
271 0 : fprintf(stderr, "waitpid failed: %s\n", strerror(errno));
272 0 : goto fail;
273 : }
274 1 : if (!WIFEXITED(wstatus)) {
275 0 : fprintf(stderr, "child did not exit normally\n");
276 0 : goto fail;
277 : }
278 :
279 1 : exit_status = WEXITSTATUS(wstatus);
280 1 : if (exit_status != 0) {
281 0 : fprintf(stderr, "exit status is %d\n", exit_status);
282 0 : goto fail;
283 : }
284 :
285 1 : status = dbwrap_store_uint32_bystring(db, keystr, 1);
286 1 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
287 0 : fprintf(stderr,
288 : "dbwrap_store_uint32 returned %s\n",
289 : nt_errstr(status));
290 0 : goto fail;
291 : }
292 :
293 1 : (void)unlink("test_watch.tdb");
294 1 : ret = true;
295 1 : fail:
296 1 : TALLOC_FREE(db);
297 1 : TALLOC_FREE(msg);
298 1 : TALLOC_FREE(ev);
299 1 : return ret;
300 : }
301 :
302 : /*
303 : * Test that we can't add two watchers in the same
304 : * fetch_lock/do_locked round
305 : */
306 :
307 : struct dbwrap_watch4_state {
308 : TALLOC_CTX *mem_ctx;
309 : struct tevent_context *ev;
310 : struct db_context *db;
311 : TDB_DATA key;
312 :
313 : NTSTATUS status;
314 :
315 : struct tevent_req *req1;
316 : NTSTATUS status1;
317 :
318 : struct tevent_req *req2;
319 : NTSTATUS status2;
320 : };
321 :
322 : static void dbwrap_watch4_done1(struct tevent_req *subreq);
323 : static void dbwrap_watch4_done2(struct tevent_req *subreq);
324 :
325 1 : static void dbwrap_watch4_fn(struct db_record *rec,
326 : TDB_DATA value,
327 : void *private_data)
328 : {
329 1 : struct dbwrap_watch4_state *state = private_data;
330 1 : bool ok;
331 :
332 2 : state->req1 = dbwrap_watched_watch_send(
333 1 : state->mem_ctx, state->ev, rec, 0, (struct server_id) { .pid=0 });
334 1 : if (state->req1 == NULL) {
335 0 : goto nomem;
336 : }
337 1 : tevent_req_set_callback(state->req1, dbwrap_watch4_done1, state);
338 1 : state->status1 = NT_STATUS_EVENT_PENDING;
339 :
340 1 : ok = tevent_req_set_endtime(
341 : state->req1, state->ev, timeval_current_ofs(1, 0));
342 1 : if (!ok) {
343 0 : goto nomem;
344 : }
345 :
346 2 : state->req2 = dbwrap_watched_watch_send(
347 1 : state->mem_ctx, state->ev, rec, 0, (struct server_id) { .pid=0 });
348 1 : if (state->req2 == NULL) {
349 0 : goto nomem;
350 : }
351 1 : tevent_req_set_callback(state->req2, dbwrap_watch4_done2, state);
352 1 : state->status2 = NT_STATUS_EVENT_PENDING;
353 :
354 1 : ok = tevent_req_set_endtime(
355 : state->req2, state->ev, timeval_current_ofs(1, 0));
356 1 : if (!ok) {
357 0 : goto nomem;
358 : }
359 :
360 1 : state->status = NT_STATUS_OK;
361 1 : return;
362 :
363 0 : nomem:
364 0 : state->status = NT_STATUS_NO_MEMORY;
365 : }
366 :
367 1 : static void dbwrap_watch4_done1(struct tevent_req *subreq)
368 : {
369 1 : struct dbwrap_watch4_state *state = tevent_req_callback_data_void(subreq);
370 1 : state->status1 = dbwrap_watched_watch_recv(subreq, NULL, NULL, NULL);
371 1 : TALLOC_FREE(subreq);
372 1 : printf("req1 finished: %s\n", nt_errstr(state->status1));
373 1 : state->req1 = NULL;
374 1 : }
375 :
376 1 : static void dbwrap_watch4_done2(struct tevent_req *subreq)
377 : {
378 1 : struct dbwrap_watch4_state *state = tevent_req_callback_data_void(subreq);
379 1 : state->status2 = dbwrap_watched_watch_recv(subreq, NULL, NULL, NULL);
380 1 : TALLOC_FREE(subreq);
381 1 : printf("req2 finished: %s\n", nt_errstr(state->status2));
382 1 : state->req2 = NULL;
383 1 : }
384 :
385 1 : bool run_dbwrap_watch4(int dummy)
386 : {
387 1 : struct tevent_context *ev = NULL;
388 1 : struct messaging_context *msg = NULL;
389 1 : struct db_context *backend = NULL;
390 1 : struct db_context *db = NULL;
391 1 : const char *keystr = "key";
392 1 : TDB_DATA key = string_term_tdb_data(keystr);
393 1 : struct dbwrap_watch4_state state = { 0 };
394 1 : NTSTATUS status;
395 1 : bool ret = false;
396 1 : bool ok;
397 :
398 1 : ok = test_dbwrap_watch_init(
399 : talloc_tos(), "test_watch.tdb", &ev, &msg, &backend, &db);
400 1 : if (!ok) {
401 0 : goto fail;
402 : }
403 :
404 2 : state = (struct dbwrap_watch4_state) {
405 1 : .mem_ctx = talloc_tos(),
406 : .ev = ev,
407 : .db = db,
408 : .key = key,
409 : };
410 :
411 1 : status = dbwrap_do_locked(db, key, dbwrap_watch4_fn, &state);
412 1 : if (!NT_STATUS_IS_OK(status)) {
413 0 : fprintf(stderr,
414 : "dbwrap_do_locked failed: %s\n",
415 : nt_errstr(status));
416 0 : goto fail;
417 : }
418 1 : if (!NT_STATUS_IS_OK(state.status)) {
419 0 : fprintf(stderr,
420 : "dbwrap_watch4_fn failed: %s\n",
421 : nt_errstr(status));
422 0 : goto fail;
423 : }
424 :
425 1 : status = dbwrap_store(db, key, key, 0);
426 1 : if (!NT_STATUS_IS_OK(status)) {
427 0 : fprintf(stderr,
428 : "dbwrap_store failed: %s\n",
429 : nt_errstr(status));
430 0 : goto fail;
431 : }
432 :
433 4 : while (NT_STATUS_EQUAL(state.status1, NT_STATUS_EVENT_PENDING) ||
434 1 : NT_STATUS_EQUAL(state.status2, NT_STATUS_EVENT_PENDING)) {
435 3 : int res = tevent_loop_once(ev);
436 3 : if (res != 0) {
437 0 : fprintf(stderr,
438 : "tevent_loop_once failed: %s\n",
439 0 : strerror(errno));
440 0 : goto fail;
441 : }
442 : }
443 :
444 1 : if (!NT_STATUS_IS_OK(state.status1)) {
445 0 : fprintf(stderr,
446 : "req1 returned %s\n",
447 : nt_errstr(state.status1));
448 0 : goto fail;
449 : }
450 :
451 1 : if (!NT_STATUS_EQUAL(state.status2, NT_STATUS_REQUEST_NOT_ACCEPTED)) {
452 0 : fprintf(stderr,
453 : "req2 returned %s\n",
454 : nt_errstr(state.status2));
455 0 : goto fail;
456 : }
457 :
458 1 : (void)unlink("test_watch.tdb");
459 1 : ret = true;
460 1 : fail:
461 1 : TALLOC_FREE(state.req2);
462 1 : TALLOC_FREE(state.req1);
463 1 : TALLOC_FREE(db);
464 1 : TALLOC_FREE(msg);
465 1 : TALLOC_FREE(ev);
466 1 : return ret;
467 : }
|