s3: in sys_popen(), validate input before opening the pipe.
[kai/samba.git] / source3 / lib / tevent_barrier.c
1 /*
2    Unix SMB/CIFS implementation.
3    Implement a barrier
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 "tevent_barrier.h"
22 #include "lib/util/tevent_unix.h"
23
24 struct tevent_barrier_waiter {
25         struct tevent_immediate *im;
26         struct tevent_context *ev;
27         struct tevent_req *req;
28 };
29
30 struct tevent_barrier {
31         unsigned count;
32         struct tevent_barrier_waiter *waiters;
33         void (*trigger_cb)(void *private_data);
34         void *private_data;
35 };
36
37 static int tevent_barrier_destructor(struct tevent_barrier *b);
38 static void tevent_barrier_release(struct tevent_barrier *b);
39 static void tevent_barrier_release_one(struct tevent_context *ctx,
40                                        struct tevent_immediate *im,
41                                        void *private_data);
42 static void tevent_barrier_release_trigger(struct tevent_context *ctx,
43                                            struct tevent_immediate *im,
44                                            void *private_data);
45
46 struct tevent_barrier *tevent_barrier_init(
47         TALLOC_CTX *mem_ctx, unsigned count,
48         void (*trigger_cb)(void *private_data), void *private_data)
49 {
50         struct tevent_barrier *b;
51         unsigned i;
52
53         if (count == 0) {
54                 return NULL;
55         }
56
57         b = talloc(mem_ctx, struct tevent_barrier);
58         if (b == NULL) {
59                 return NULL;
60         }
61         b->count = 0;
62         b->trigger_cb = trigger_cb;
63         b->private_data = private_data;
64
65         b->waiters = talloc_array(b, struct tevent_barrier_waiter, count);
66         if (b->waiters == NULL) {
67                 goto fail;
68         }
69         for (i=0; i<count; i++) {
70                 struct tevent_barrier_waiter *w = &b->waiters[i];
71
72                 w->im = tevent_create_immediate(b->waiters);
73                 if (w->im == NULL) {
74                         goto fail;
75                 }
76                 w->req = NULL;
77         }
78         talloc_set_destructor(b, tevent_barrier_destructor);
79         return b;
80 fail:
81         TALLOC_FREE(b);
82         return NULL;
83 }
84
85 static int tevent_barrier_destructor(struct tevent_barrier *b)
86 {
87         tevent_barrier_release(b);
88         return 0;
89 }
90
91 struct tevent_barrier_wait_state {
92         struct tevent_barrier *b;
93         int index;
94 };
95
96 static void tevent_barrier_release(struct tevent_barrier *b)
97 {
98         unsigned i;
99
100         for (i=0; i<b->count; i++) {
101                 struct tevent_barrier_waiter *w = &b->waiters[i];
102                 struct tevent_barrier_wait_state *state;
103
104                 if (w->req == NULL) {
105                         continue;
106                 }
107                 tevent_schedule_immediate(
108                         w->im, w->ev, tevent_barrier_release_one, w->req);
109
110                 state = tevent_req_data(
111                         w->req, struct tevent_barrier_wait_state);
112                 talloc_set_destructor(state, NULL);
113
114                 w->req = NULL;
115                 w->ev = NULL;
116         }
117         b->count = 0;
118         if (b->trigger_cb != NULL) {
119                 b->trigger_cb(b->private_data);
120         }
121 }
122
123 static void tevent_barrier_release_one(struct tevent_context *ctx,
124                                        struct tevent_immediate *im,
125                                        void *private_data)
126 {
127         struct tevent_req *req = talloc_get_type_abort(
128                 private_data, struct tevent_req);
129         tevent_req_done(req);
130 }
131
132 static int tevent_barrier_wait_state_destructor(
133         struct tevent_barrier_wait_state *s);
134
135 struct tevent_req *tevent_barrier_wait_send(TALLOC_CTX *mem_ctx,
136                                             struct tevent_context *ev,
137                                             struct tevent_barrier *b)
138 {
139         struct tevent_req *req;
140         struct tevent_barrier_wait_state *state;
141         struct tevent_barrier_waiter *w;
142         struct tevent_immediate *im;
143
144         req = tevent_req_create(mem_ctx, &state,
145                                 struct tevent_barrier_wait_state);
146         if (req == NULL) {
147                 return NULL;
148         }
149         state->b = b;
150         state->index = b->count;
151
152         w = &b->waiters[b->count];
153         w->ev = ev;
154         w->req = req;
155         b->count += 1;
156
157         talloc_set_destructor(state, tevent_barrier_wait_state_destructor);
158
159         if (b->count < talloc_array_length(b->waiters)) {
160                 return req;
161         }
162
163         im = tevent_create_immediate(req);
164         if (tevent_req_nomem(im, req)) {
165                 return tevent_req_post(req, ev);
166         }
167         tevent_schedule_immediate(im, ev, tevent_barrier_release_trigger, b);
168         return req;
169 }
170
171 static int tevent_barrier_wait_state_destructor(
172         struct tevent_barrier_wait_state *s)
173 {
174         struct tevent_barrier *b = s->b;
175         b->waiters[s->index].req = b->waiters[b->count-1].req;
176         b->count -= 1;
177         return 0;
178 }
179
180 static void tevent_barrier_release_trigger(struct tevent_context *ctx,
181                                            struct tevent_immediate *im,
182                                            void *private_data)
183 {
184         struct tevent_barrier *b = talloc_get_type_abort(
185                 private_data, struct tevent_barrier);
186         tevent_barrier_release(b);
187 }
188
189 int tevent_barrier_wait_recv(struct tevent_req *req)
190 {
191         int err;
192
193         if (tevent_req_is_unix_error(req, &err)) {
194                 return err;
195         }
196         return 0;
197 }