MFC: An off-by-one malloc size was corrupting the installer's memory,
[dragonfly.git] / contrib / bsdinstaller-1.1.6 / src / lib / libdfui / conn_caps.c
blob30f6764963af9b678dc295b52f84b6732ec91638
1 /*
2 * Copyright (c)2004 Cat's Eye Technologies. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
16 * Neither the name of Cat's Eye Technologies nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31 * OF THE POSSIBILITY OF SUCH DAMAGE.
35 * conn_caps.c
36 * $Id: conn_caps.c,v 1.12 2005/02/06 19:53:19 cpressey Exp $
37 * This code was derived in part from:
38 * $_DragonFly: src/test/caps/client.c,v 1.3 2004/03/31 20:27:34 dillon Exp $
39 * $_DragonFly: src/test/caps/server.c,v 1.4 2004/03/06 22:15:00 dillon Exp $
40 * and is therefore also subject to the license conditions on those files.
43 #include "system.h"
44 #ifdef HAS_CAPS
46 #include <sys/types.h>
47 #include <sys/time.h>
48 #include <sys/caps.h>
49 #include <sys/errno.h>
51 #include <stdarg.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
57 #include <aura/mem.h>
58 #include <aura/buffer.h>
60 #define NEEDS_DFUI_STRUCTURE_DEFINITIONS
61 #include "dfui.h"
62 #undef NEEDS_DFUI_STRUCTURE_DEFINITIONS
63 #include "encoding.h"
64 #include "dump.h"
65 #include "conn_caps.h"
67 /***** BACKEND ******/
69 /** High Level **/
72 * Connect to the frontend.
74 dfui_err_t
75 dfui_caps_be_start(struct dfui_connection *c)
77 T_CAPS(c)->cid = caps_sys_service(c->rendezvous, getuid(), getgid(),
78 0, CAPF_ANYCLIENT);
79 return(T_CAPS(c)->cid < 0 ? DFUI_FAILURE : DFUI_SUCCESS);
83 * Tell the frontend that we're done and disconnect from it.
85 dfui_err_t
86 dfui_caps_be_stop(struct dfui_connection *c)
88 if (dfui_caps_be_ll_exchange(c, DFUI_BE_MSG_STOP, "")) {
89 caps_sys_close(T_CAPS(c)->cid);
90 return(DFUI_SUCCESS);
91 } else
92 return(DFUI_FAILURE);
95 /** Low Level **/
98 * Exchange a message with the frontend. This involves two receive()/reply()
99 * cycles: one to provide our message, one to get a reply from the frontend.
101 * Note that this does not immediately send the message to the frontend -
102 * it can't, because we're a service and it's a client. What it does is
103 * keep the message handy and wait for a frontend request to come in. It
104 * then replies to that request with our message.
106 * The protocol looks something like the following, using the PRESENT and
107 * SUBMIT exchange as an example:
109 * frontend (client) | backend (service)
110 * ------------------+------------------
112 * [stage 1]
113 * READY --> ll_receive()
114 * <-- PRESENT(form) ll_reply()
116 * [stage 2]
117 * SUBMIT(form) --> ll_receive()
118 * <-- READY ll_reply()
120 * Each of those exchanges is a pair of calls, on our end, to
121 * dfui_caps_be_ll_receive() and dfui_caps_be_ll_reply().
123 * The set of messages that the client can pass us is determined by
124 * the conversation state:
126 * o In stage 1, only READY and ABORT are meaningful.
127 * o After a PRESENT, the messages SUBMIT and ABORT are meaningul
128 * in stage 2.
129 * o During a PROG_*, the messages CONTINUE, CANCEL, and ABORT
130 * are meaningful in stage 2.
132 * If the frontend sends us with READY in stage 2, we assume it has
133 * fallen out of sync, so we send the same initial reply again, going
134 * back to stage 1 as it were.
136 * After this call, the message is available in c->ebuf.
138 dfui_err_t
139 dfui_caps_be_ll_exchange(struct dfui_connection *c, char msgtype, const char *msg)
141 char *fmsg;
144 * Construct our message to send.
147 fmsg = aura_malloc(strlen(msg) + 2, "exchange message");
148 fmsg[0] = msgtype;
149 strcpy(fmsg + 1, msg);
152 * Get the frontend's message.
155 dfui_caps_be_ll_receive(c);
158 * Frontend message should have been either READY or ABORT.
159 * If ABORT, we get out of here pronto.
162 if (aura_buffer_buf(c->ebuf)[0] == DFUI_FE_MSG_ABORT) {
163 aura_free(fmsg, "exchange message");
164 return(DFUI_FAILURE);
167 /* XXX if (!READY) ??? */
169 do {
170 dfui_caps_be_ll_reply(c, fmsg);
173 * Here, the frontend has picked up our request and is
174 * processing it. We have to wait for the response.
177 dfui_caps_be_ll_receive(c);
180 * Did we get READY from this?
181 * If so, loop!
184 } while (aura_buffer_buf(c->ebuf)[0] == DFUI_FE_MSG_READY);
186 fmsg[0] = DFUI_BE_MSG_READY;
187 fmsg[1] = '\0';
188 dfui_caps_be_ll_reply(c, fmsg);
190 aura_free(fmsg, "exchange message");
191 return(DFUI_SUCCESS);
195 * Receive a message from the frontend.
196 * This call is synchronous.
197 * After this call, the message is available in c->ebuf.
199 dfui_err_t
200 dfui_caps_be_ll_receive(struct dfui_connection *c)
203 * XXX Eventually, the message should be received directly
204 * into c->ebuf. For now, receive into T_CAPS(c)->buf,
205 * and copy into c->ebuf.
207 do {
208 T_CAPS(c)->wresult = caps_sys_wait(T_CAPS(c)->cid, T_CAPS(c)->buf,
209 T_CAPS(c)->size, &T_CAPS(c)->msgid, NULL);
210 if (T_CAPS(c)->wresult < 0)
211 return(DFUI_FAILURE);
213 * This might have been a CAPMS_DISPOSE message from the kernel.
214 * If so, just accept it and try, try again.
216 dfui_debug("DISPOSE?<<%s>>\n",
217 T_CAPS(c)->msgid.c_state == CAPMS_DISPOSE ? "Yes" : "No");
218 } while (T_CAPS(c)->msgid.c_state == CAPMS_DISPOSE);
220 aura_buffer_set(c->ebuf, T_CAPS(c)->buf, T_CAPS(c)->wresult);
221 dfui_debug("RECV<<%s>>\n", aura_buffer_buf(c->ebuf));
222 return(DFUI_SUCCESS);
226 * Send a NUL-terminated reply to the frontend.
228 dfui_err_t
229 dfui_caps_be_ll_reply(struct dfui_connection *c, const char *fmsg)
231 dfui_debug("SEND<<%s>>\n", fmsg);
232 T_CAPS(c)->wresult = caps_sys_reply(T_CAPS(c)->cid,
233 __DECONST(char *, fmsg), strlen(fmsg), T_CAPS(c)->msgid.c_id);
236 * We may get a CAPMS_DISPOSE message after this, if the client
237 * process is still around. If so, it'll be handled in the next
238 * call to dfui_caps_be_ll_receive().
241 return(DFUI_SUCCESS);
244 /******** FRONTEND ********/
246 /** High Level **/
248 dfui_err_t
249 dfui_caps_fe_connect(struct dfui_connection *c)
251 T_CAPS(c)->cid = caps_sys_client(c->rendezvous, getuid(), getgid(), 0,
252 CAPF_ANYCLIENT | CAPF_WAITSVC);
253 return(T_CAPS(c)->cid > 0 ? DFUI_SUCCESS : DFUI_FAILURE);
256 dfui_err_t
257 dfui_caps_fe_disconnect(struct dfui_connection *c)
259 caps_sys_close(T_CAPS(c)->cid);
260 return(DFUI_SUCCESS);
263 /** Low Level **/
266 * Ask for, and subsequently receieve, a message from the backend.
267 * msgtype should be one of the DFUI_FE_MSG_* constants.
268 * This call is synchronous.
269 * After this call, the encoded message is available in c->ebuf.
271 dfui_err_t
272 dfui_caps_fe_ll_request(struct dfui_connection *c, char msgtype, const char *msg)
274 char *fmsg;
275 off_t msgcid = 0;
278 * First, assert that the connection is open.
281 if (c == NULL || T_CAPS(c)->cid < 0)
282 return(DFUI_FAILURE);
285 * Construct a message.
288 fmsg = aura_malloc(strlen(msg) + 2, "exchange message");
289 fmsg[0] = msgtype;
290 strcpy(fmsg + 1, msg);
291 dfui_debug("SEND<<%s>>\n", fmsg);
294 * Send a NUL-terminated message to the backend.
297 errno = 0;
298 msgcid = caps_sys_put(T_CAPS(c)->cid, fmsg, strlen(fmsg));
299 if (msgcid < 0 && errno == ENOTCONN)
300 return(DFUI_FAILURE);
303 * Receive a reply from the backend.
304 * If our message was a READY, this should be a message like PRESENT.
305 * Otherwise it should simply be a READY.
308 dfui_debug("WAITING<<>>\n");
310 T_CAPS(c)->wresult = caps_sys_wait(T_CAPS(c)->cid, T_CAPS(c)->buf,
311 T_CAPS(c)->size, &T_CAPS(c)->msgid, NULL);
312 if (T_CAPS(c)->wresult < 0)
313 return(DFUI_FAILURE);
315 aura_buffer_set(c->ebuf, T_CAPS(c)->buf, T_CAPS(c)->wresult);
316 dfui_debug("RECV<<%s>>\n", aura_buffer_buf(c->ebuf));
318 aura_free(fmsg, "exchange message");
320 return(DFUI_SUCCESS);
323 #endif /* HAS_CAPS */