source: mainline/uspace/lib/c/generic/vbd.c@ 28a5ebd

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 28a5ebd was 27c0e5b, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 5 years ago

Avoid memory leak in vdb_get_ids_internal on realloc fails

  • Property mode set to 100644
File size: 8.4 KB
Line 
1/*
2 * Copyright (c) 2015 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * 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 the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libc
30 * @{
31 */
32/** @file Virtual Block Device client API
33 */
34
35#include <abi/ipc/interfaces.h>
36#include <errno.h>
37#include <ipc/services.h>
38#include <ipc/vbd.h>
39#include <loc.h>
40#include <macros.h>
41#include <mem.h>
42#include <stdlib.h>
43#include <types/label.h>
44#include <vbd.h>
45
46static errno_t vbd_get_ids_internal(vbd_t *, sysarg_t, sysarg_t, sysarg_t **,
47 size_t *);
48
49errno_t vbd_create(vbd_t **rvbd)
50{
51 vbd_t *vbd;
52 service_id_t vbd_svcid;
53 errno_t rc;
54
55 vbd = calloc(1, sizeof(vbd_t));
56 if (vbd == NULL) {
57 rc = ENOMEM;
58 goto error;
59 }
60
61 rc = loc_service_get_id(SERVICE_NAME_VBD, &vbd_svcid,
62 IPC_FLAG_BLOCKING);
63 if (rc != EOK) {
64 rc = EIO;
65 goto error;
66 }
67
68 vbd->sess = loc_service_connect(vbd_svcid, INTERFACE_VBD,
69 IPC_FLAG_BLOCKING);
70 if (vbd->sess == NULL) {
71 rc = EIO;
72 goto error;
73 }
74
75 *rvbd = vbd;
76 return EOK;
77error:
78 free(vbd);
79 return rc;
80}
81
82void vbd_destroy(vbd_t *vbd)
83{
84 if (vbd == NULL)
85 return;
86
87 async_hangup(vbd->sess);
88 free(vbd);
89}
90
91/** Get list of partitions as array of service IDs.
92 *
93 * @param vbd Virtual block device service
94 * @param data Place to store pointer to array
95 * @param count Place to store length of array (number of entries)
96 *
97 * @return EOK on success or an error code
98 */
99errno_t vbd_get_disks(vbd_t *vbd, service_id_t **data, size_t *count)
100{
101 return vbd_get_ids_internal(vbd, VBD_GET_DISKS, 0, data, count);
102}
103
104/** Get disk information. */
105errno_t vbd_disk_info(vbd_t *vbd, service_id_t sid, vbd_disk_info_t *vinfo)
106{
107 async_exch_t *exch;
108 errno_t retval;
109 ipc_call_t answer;
110
111 exch = async_exchange_begin(vbd->sess);
112 aid_t req = async_send_1(exch, VBD_DISK_INFO, sid, &answer);
113 errno_t rc = async_data_read_start(exch, vinfo, sizeof(vbd_disk_info_t));
114 async_exchange_end(exch);
115
116 if (rc != EOK) {
117 async_forget(req);
118 return EIO;
119 }
120
121 async_wait_for(req, &retval);
122 if (retval != EOK)
123 return EIO;
124
125 return EOK;
126}
127
128errno_t vbd_label_create(vbd_t *vbd, service_id_t sid, label_type_t ltype)
129{
130 async_exch_t *exch;
131 errno_t retval;
132
133 exch = async_exchange_begin(vbd->sess);
134 retval = async_req_2_0(exch, VBD_LABEL_CREATE, sid, ltype);
135 async_exchange_end(exch);
136
137 if (retval != EOK)
138 return EIO;
139
140 return EOK;
141}
142
143errno_t vbd_label_delete(vbd_t *vbd, service_id_t sid)
144{
145 async_exch_t *exch;
146 errno_t retval;
147
148 exch = async_exchange_begin(vbd->sess);
149 retval = async_req_1_0(exch, VBD_LABEL_DELETE, sid);
150 async_exchange_end(exch);
151
152 if (retval != EOK)
153 return EIO;
154
155 return EOK;
156}
157
158/** Get list of IDs into a buffer of fixed size.
159 *
160 * @param vbd Virtual Block Device
161 * @param method IPC method
162 * @param arg1 First argument
163 * @param id_buf Buffer to store IDs
164 * @param buf_size Buffer size
165 * @param act_size Place to store actual size of complete data.
166 *
167 * @return EOK on success or an error code.
168 */
169static errno_t vbd_get_ids_once(vbd_t *vbd, sysarg_t method, sysarg_t arg1,
170 sysarg_t *id_buf, size_t buf_size, size_t *act_size)
171{
172 async_exch_t *exch = async_exchange_begin(vbd->sess);
173
174 ipc_call_t answer;
175 aid_t req = async_send_1(exch, method, arg1, &answer);
176 errno_t rc = async_data_read_start(exch, id_buf, buf_size);
177
178 async_exchange_end(exch);
179
180 if (rc != EOK) {
181 async_forget(req);
182 return rc;
183 }
184
185 errno_t retval;
186 async_wait_for(req, &retval);
187
188 if (retval != EOK) {
189 return retval;
190 }
191
192 *act_size = ipc_get_arg1(&answer);
193 return EOK;
194}
195
196/** Get list of IDs.
197 *
198 * Returns an allocated array of service IDs.
199 *
200 * @param vbd Virtual Block Device
201 * @param method IPC method
202 * @param arg1 IPC argument 1
203 * @param data Place to store pointer to array of IDs
204 * @param count Place to store number of IDs
205 * @return EOK on success or an error code
206 */
207static errno_t vbd_get_ids_internal(vbd_t *vbd, sysarg_t method, sysarg_t arg1,
208 sysarg_t **data, size_t *count)
209{
210 *data = NULL;
211 *count = 0;
212
213 size_t act_size = 0;
214 errno_t rc = vbd_get_ids_once(vbd, method, arg1, NULL, 0, &act_size);
215 if (rc != EOK)
216 return rc;
217
218 size_t alloc_size = act_size;
219 service_id_t *ids = malloc(alloc_size);
220 if (ids == NULL)
221 return ENOMEM;
222
223 while (true) {
224 rc = vbd_get_ids_once(vbd, method, arg1, ids, alloc_size,
225 &act_size);
226 if (rc != EOK)
227 return rc;
228
229 if (act_size <= alloc_size)
230 break;
231
232 alloc_size = act_size;
233 service_id_t *tmp = realloc(ids, alloc_size);
234 if (tmp == NULL) {
235 free(ids);
236 return ENOMEM;
237 }
238 ids = tmp;
239 }
240
241 *count = act_size / sizeof(service_id_t);
242 *data = ids;
243 return EOK;
244}
245
246/** Get list of disks as array of service IDs.
247 *
248 * @param vbd Virtual Block Device
249 * @param data Place to store pointer to array
250 * @param count Place to store length of array (number of entries)
251 *
252 * @return EOK on success or an error code
253 */
254errno_t vbd_label_get_parts(vbd_t *vbd, service_id_t disk,
255 service_id_t **data, size_t *count)
256{
257 return vbd_get_ids_internal(vbd, VBD_LABEL_GET_PARTS, disk,
258 data, count);
259}
260
261errno_t vbd_part_get_info(vbd_t *vbd, vbd_part_id_t part, vbd_part_info_t *pinfo)
262{
263 async_exch_t *exch;
264 errno_t retval;
265 ipc_call_t answer;
266
267 exch = async_exchange_begin(vbd->sess);
268 aid_t req = async_send_1(exch, VBD_PART_GET_INFO, part, &answer);
269 errno_t rc = async_data_read_start(exch, pinfo, sizeof(vbd_part_info_t));
270 async_exchange_end(exch);
271
272 if (rc != EOK) {
273 async_forget(req);
274 return EIO;
275 }
276
277 async_wait_for(req, &retval);
278 if (retval != EOK)
279 return EIO;
280
281 return EOK;
282}
283
284errno_t vbd_part_create(vbd_t *vbd, service_id_t disk, vbd_part_spec_t *pspec,
285 vbd_part_id_t *rpart)
286{
287 async_exch_t *exch;
288 errno_t retval;
289 ipc_call_t answer;
290
291 exch = async_exchange_begin(vbd->sess);
292 aid_t req = async_send_1(exch, VBD_PART_CREATE, disk, &answer);
293 errno_t rc = async_data_write_start(exch, pspec, sizeof(vbd_part_spec_t));
294 async_exchange_end(exch);
295
296 if (rc != EOK) {
297 async_forget(req);
298 return EIO;
299 }
300
301 async_wait_for(req, &retval);
302 if (retval != EOK)
303 return EIO;
304
305 *rpart = (vbd_part_id_t)ipc_get_arg1(&answer);
306 return EOK;
307
308}
309
310errno_t vbd_part_delete(vbd_t *vbd, vbd_part_id_t part)
311{
312 async_exch_t *exch;
313 errno_t retval;
314
315 exch = async_exchange_begin(vbd->sess);
316 retval = async_req_1_0(exch, VBD_PART_DELETE, part);
317 async_exchange_end(exch);
318
319 if (retval != EOK)
320 return EIO;
321
322 return EOK;
323}
324
325void vbd_pspec_init(vbd_part_spec_t *pspec)
326{
327 memset(pspec, 0, sizeof(vbd_part_spec_t));
328}
329
330/** Suggest partition type based on partition content.
331 *
332 * @param vbd Virtual Block Device
333 * @param disk Disk on which the partition will be created
334 * @param pcnt Partition content
335 * @param ptype Place to store suggested partition type
336 *
337 * @return EOK on success or an error code
338 */
339errno_t vbd_suggest_ptype(vbd_t *vbd, service_id_t disk, label_pcnt_t pcnt,
340 label_ptype_t *ptype)
341{
342 async_exch_t *exch;
343 errno_t retval;
344 ipc_call_t answer;
345
346 exch = async_exchange_begin(vbd->sess);
347 aid_t req = async_send_2(exch, VBD_SUGGEST_PTYPE, disk, pcnt, &answer);
348 errno_t rc = async_data_read_start(exch, ptype, sizeof(label_ptype_t));
349 async_exchange_end(exch);
350
351 if (rc != EOK) {
352 async_forget(req);
353 return EIO;
354 }
355
356 async_wait_for(req, &retval);
357 if (retval != EOK)
358 return EIO;
359
360 return EOK;
361}
362
363/** @}
364 */
Note: See TracBrowser for help on using the repository browser.