source: mainline/uspace/lib/c/generic/vol.c@ 94e75cf

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

Avoid memory leak when realloc fails in vol_get_ids_internal function

  • Property mode set to 100644
File size: 13.5 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 Volume service API
33 */
34
35#include <abi/ipc/interfaces.h>
36#include <errno.h>
37#include <ipc/services.h>
38#include <ipc/vol.h>
39#include <loc.h>
40#include <stdlib.h>
41#include <str.h>
42#include <vfs/vfs.h>
43#include <vol.h>
44
45/** Create Volume service session.
46 *
47 * @param rvol Place to store pointer to volume service session.
48 * @return EOK on success, ENOMEM if out of memory, EIO if service
49 * cannot be contacted.
50 */
51errno_t vol_create(vol_t **rvol)
52{
53 vol_t *vol;
54 service_id_t vol_svcid;
55 errno_t rc;
56
57 vol = calloc(1, sizeof(vol_t));
58 if (vol == NULL) {
59 rc = ENOMEM;
60 goto error;
61 }
62
63 rc = loc_service_get_id(SERVICE_NAME_VOLSRV, &vol_svcid, 0);
64 if (rc != EOK) {
65 rc = ENOENT;
66 goto error;
67 }
68
69 vol->sess = loc_service_connect(vol_svcid, INTERFACE_VOL, 0);
70 if (vol->sess == NULL) {
71 rc = EIO;
72 goto error;
73 }
74
75 *rvol = vol;
76 return EOK;
77error:
78 free(vol);
79 return rc;
80}
81
82/** Destroy volume service session.
83 *
84 * @param vol Volume service session
85 */
86void vol_destroy(vol_t *vol)
87{
88 if (vol == NULL)
89 return;
90
91 async_hangup(vol->sess);
92 free(vol);
93}
94
95/** Get list of IDs into a buffer of fixed size.
96 *
97 * @param vol Volume service
98 * @param method IPC method
99 * @param arg1 First argument
100 * @param id_buf Buffer to store IDs
101 * @param buf_size Buffer size
102 * @param act_size Place to store actual size of complete data.
103 *
104 * @return EOK on success or an error code.
105 */
106static errno_t vol_get_ids_once(vol_t *vol, sysarg_t method, sysarg_t arg1,
107 sysarg_t *id_buf, size_t buf_size, size_t *act_size)
108{
109 async_exch_t *exch = async_exchange_begin(vol->sess);
110
111 ipc_call_t answer;
112 aid_t req = async_send_1(exch, method, arg1, &answer);
113 errno_t rc = async_data_read_start(exch, id_buf, buf_size);
114
115 async_exchange_end(exch);
116
117 if (rc != EOK) {
118 async_forget(req);
119 return rc;
120 }
121
122 errno_t retval;
123 async_wait_for(req, &retval);
124
125 if (retval != EOK) {
126 return retval;
127 }
128
129 *act_size = ipc_get_arg1(&answer);
130 return EOK;
131}
132
133/** Get list of IDs.
134 *
135 * Returns an allocated array of service IDs.
136 *
137 * @param vol Volume service
138 * @param method IPC method
139 * @param arg1 IPC argument 1
140 * @param data Place to store pointer to array of IDs
141 * @param count Place to store number of IDs
142 * @return EOK on success or an error code
143 */
144static errno_t vol_get_ids_internal(vol_t *vol, sysarg_t method, sysarg_t arg1,
145 sysarg_t **data, size_t *count)
146{
147 *data = NULL;
148 *count = 0;
149
150 size_t act_size = 0;
151 errno_t rc = vol_get_ids_once(vol, method, arg1, NULL, 0, &act_size);
152 if (rc != EOK)
153 return rc;
154
155 size_t alloc_size = act_size;
156 service_id_t *ids = malloc(alloc_size);
157 if (ids == NULL)
158 return ENOMEM;
159
160 while (true) {
161 rc = vol_get_ids_once(vol, method, arg1, ids, alloc_size,
162 &act_size);
163 if (rc != EOK)
164 return rc;
165
166 if (act_size <= alloc_size)
167 break;
168
169 alloc_size = act_size;
170 service_id_t *temp = realloc(ids, alloc_size);
171 if (temp == NULL) {
172 free(ids);
173 return ENOMEM;
174 }
175 ids = temp;
176 }
177
178 *count = act_size / sizeof(service_id_t);
179 *data = ids;
180 return EOK;
181}
182
183/** Get list of partitions as array of service IDs.
184 *
185 * @param vol Volume service
186 * @param data Place to store pointer to array
187 * @param count Place to store length of array (number of entries)
188 *
189 * @return EOK on success or an error code
190 */
191errno_t vol_get_parts(vol_t *vol, service_id_t **data, size_t *count)
192{
193 return vol_get_ids_internal(vol, VOL_GET_PARTS, 0, data, count);
194}
195
196/** Add partition.
197 *
198 * After a partition is created (e.g. as a result of deleting a label
199 * the dummy partition is created), it can take some (unknown) time
200 * until it is discovered.
201 *
202 * @param vol Volume service
203 * @param sid Service ID of the partition
204 * @return EOK on success or an error code
205 */
206errno_t vol_part_add(vol_t *vol, service_id_t sid)
207{
208 async_exch_t *exch;
209 errno_t retval;
210
211 exch = async_exchange_begin(vol->sess);
212 retval = async_req_1_0(exch, VOL_PART_ADD, sid);
213 async_exchange_end(exch);
214
215 if (retval != EOK)
216 return retval;
217
218 return EOK;
219}
220
221/** Get partition information.
222 *
223 * @param vol Volume service
224 * @param sid Service ID of the partition
225 * @param vinfo Place to store partition information
226 * @return EOK on success or an error code
227 */
228errno_t vol_part_info(vol_t *vol, service_id_t sid, vol_part_info_t *vinfo)
229{
230 async_exch_t *exch;
231 errno_t retval;
232 ipc_call_t answer;
233
234 exch = async_exchange_begin(vol->sess);
235 aid_t req = async_send_1(exch, VOL_PART_INFO, sid, &answer);
236
237 errno_t rc = async_data_read_start(exch, vinfo, sizeof(vol_part_info_t));
238 async_exchange_end(exch);
239 if (rc != EOK) {
240 async_forget(req);
241 return EIO;
242 }
243
244 async_wait_for(req, &retval);
245 if (retval != EOK)
246 return EIO;
247
248 return EOK;
249}
250
251/** Unmount partition (and possibly eject the media).
252 *
253 * @param vol Volume service
254 * @param sid Service ID of the partition
255 * @return EOK on success or an error code
256 */
257errno_t vol_part_eject(vol_t *vol, service_id_t sid)
258{
259 async_exch_t *exch;
260 errno_t retval;
261
262 exch = async_exchange_begin(vol->sess);
263 retval = async_req_1_0(exch, VOL_PART_EJECT, sid);
264 async_exchange_end(exch);
265
266 if (retval != EOK)
267 return retval;
268
269 return EOK;
270}
271
272/** Erase partition (to the extent where we will consider it not containing
273 * a file system.
274 *
275 * @param vol Volume service
276 * @param sid Service ID of the partition
277 * @return EOK on success or an error code
278 */
279errno_t vol_part_empty(vol_t *vol, service_id_t sid)
280{
281 async_exch_t *exch;
282 errno_t retval;
283
284 exch = async_exchange_begin(vol->sess);
285 retval = async_req_1_0(exch, VOL_PART_EMPTY, sid);
286 async_exchange_end(exch);
287
288 if (retval != EOK)
289 return retval;
290
291 return EOK;
292}
293
294/** Insert volume.
295 *
296 * This will re-mount the volume if it has been ejected previously.
297 *
298 * @param vol Volume service
299 * @param sid Service ID of the partition
300 * @return EOK on success or an error code
301 */
302errno_t vol_part_insert(vol_t *vol, service_id_t sid)
303{
304 async_exch_t *exch;
305 errno_t retval;
306
307 exch = async_exchange_begin(vol->sess);
308 retval = async_req_1_0(exch, VOL_PART_INSERT, sid);
309 async_exchange_end(exch);
310
311 if (retval != EOK)
312 return retval;
313
314 return EOK;
315}
316
317/** Insert volume by path.
318 *
319 * @param vol Volume service
320 * @param path Filesystem path
321 *
322 * @return EOK on success or an error code
323 */
324errno_t vol_part_insert_by_path(vol_t *vol, const char *path)
325{
326 async_exch_t *exch;
327 ipc_call_t answer;
328 errno_t retval;
329
330 exch = async_exchange_begin(vol->sess);
331 aid_t req = async_send_0(exch, VOL_PART_INSERT_BY_PATH, &answer);
332
333 retval = async_data_write_start(exch, path, str_size(path));
334 if (retval != EOK) {
335 async_exchange_end(exch);
336 async_forget(req);
337 return retval;
338 }
339
340 async_exchange_end(exch);
341 async_wait_for(req, &retval);
342
343 if (retval != EOK)
344 return retval;
345
346 return EOK;
347}
348
349/** Get volume label support.
350 *
351 * @param vol Volume service
352 * @param fstype File system type
353 * @param vlsupp Place to store volume label support information
354 * @return EOK on success or an error code
355 */
356errno_t vol_part_get_lsupp(vol_t *vol, vol_fstype_t fstype,
357 vol_label_supp_t *vlsupp)
358{
359 async_exch_t *exch;
360 errno_t retval;
361 ipc_call_t answer;
362
363 exch = async_exchange_begin(vol->sess);
364 aid_t req = async_send_1(exch, VOL_PART_LSUPP, fstype, &answer);
365 errno_t rc = async_data_read_start(exch, vlsupp, sizeof(vol_label_supp_t));
366 async_exchange_end(exch);
367
368 if (rc != EOK) {
369 async_forget(req);
370 return EIO;
371 }
372
373 async_wait_for(req, &retval);
374 if (retval != EOK)
375 return EIO;
376
377 return EOK;
378}
379
380/** Create file system.
381 *
382 * @param vol Volume service
383 * @param sid Partition service ID
384 * @param fstype File system type
385 * @param label Volume label
386 * @param mountp Mount point
387 *
388 * @return EOK on success or an error code
389 */
390errno_t vol_part_mkfs(vol_t *vol, service_id_t sid, vol_fstype_t fstype,
391 const char *label, const char *mountp)
392{
393 async_exch_t *exch;
394 ipc_call_t answer;
395 errno_t retval;
396
397 exch = async_exchange_begin(vol->sess);
398 aid_t req = async_send_2(exch, VOL_PART_MKFS, sid, fstype, &answer);
399
400 retval = async_data_write_start(exch, label, str_size(label));
401 if (retval != EOK) {
402 async_exchange_end(exch);
403 async_forget(req);
404 return retval;
405 }
406
407 retval = async_data_write_start(exch, mountp, str_size(mountp));
408 if (retval != EOK) {
409 async_exchange_end(exch);
410 async_forget(req);
411 return retval;
412 }
413
414 async_exchange_end(exch);
415 async_wait_for(req, &retval);
416
417 if (retval != EOK)
418 return retval;
419
420 return EOK;
421}
422
423/** Set mount point for partition.
424 *
425 * @param vol Volume service
426 * @param sid Partition service ID
427 * @param mountp Mount point
428 *
429 * @return EOK on success or an error code
430 */
431errno_t vol_part_set_mountp(vol_t *vol, service_id_t sid,
432 const char *mountp)
433{
434 async_exch_t *exch;
435 ipc_call_t answer;
436 errno_t retval;
437
438 exch = async_exchange_begin(vol->sess);
439 aid_t req = async_send_1(exch, VOL_PART_SET_MOUNTP, sid,
440 &answer);
441
442 retval = async_data_write_start(exch, mountp, str_size(mountp));
443 if (retval != EOK) {
444 async_exchange_end(exch);
445 async_forget(req);
446 return retval;
447 }
448
449 async_exchange_end(exch);
450 async_wait_for(req, &retval);
451
452 if (retval != EOK)
453 return retval;
454
455 return EOK;
456}
457
458/** Format file system type as string.
459 *
460 * @param fstype File system type
461 * @param rstr Place to store pointer to newly allocated string
462 * @return EOK on success, ENOMEM if out of memory
463 */
464errno_t vol_fstype_format(vol_fstype_t fstype, char **rstr)
465{
466 const char *sfstype;
467 char *s;
468
469 sfstype = NULL;
470 switch (fstype) {
471 case fs_exfat:
472 sfstype = "ExFAT";
473 break;
474 case fs_fat:
475 sfstype = "FAT";
476 break;
477 case fs_minix:
478 sfstype = "MINIX";
479 break;
480 case fs_ext4:
481 sfstype = "Ext4";
482 break;
483 case fs_cdfs:
484 sfstype = "ISO 9660";
485 break;
486 }
487
488 s = str_dup(sfstype);
489 if (s == NULL)
490 return ENOMEM;
491
492 *rstr = s;
493 return EOK;
494}
495
496/** Format partition content / file system type as string.
497 *
498 * @param pcnt Partition content
499 * @param fstype File system type
500 * @param rstr Place to store pointer to newly allocated string
501 * @return EOK on success, ENOMEM if out of memory
502 */
503errno_t vol_pcnt_fs_format(vol_part_cnt_t pcnt, vol_fstype_t fstype,
504 char **rstr)
505{
506 int rc;
507 char *s = NULL;
508
509 switch (pcnt) {
510 case vpc_empty:
511 s = str_dup("Empty");
512 if (s == NULL)
513 return ENOMEM;
514 break;
515 case vpc_fs:
516 rc = vol_fstype_format(fstype, &s);
517 if (rc != EOK)
518 return ENOMEM;
519 break;
520 case vpc_unknown:
521 s = str_dup("Unknown");
522 if (s == NULL)
523 return ENOMEM;
524 break;
525 }
526
527 assert(s != NULL);
528 *rstr = s;
529 return EOK;
530}
531
532/** Validate mount point.
533 *
534 * Verify that mount point is valid. A valid mount point is
535 * one of:
536 * - 'Auto'
537 * - 'None'
538 * - /path (string beginning with '/') to an existing directory
539 *
540 * @return EOK if mount point is in valid, EINVAL if the format is invalid,
541 * ENOENT if the directory does not exist
542 */
543errno_t vol_mountp_validate(const char *mountp)
544{
545 errno_t rc;
546 vfs_stat_t stat;
547
548 if (str_cmp(mountp, "Auto") == 0 || str_cmp(mountp, "auto") == 0)
549 return EOK;
550
551 if (str_casecmp(mountp, "None") == 0 || str_cmp(mountp, "none") == 0)
552 return EOK;
553
554 if (mountp[0] == '/') {
555 rc = vfs_stat_path(mountp, &stat);
556 if (rc != EOK || !stat.is_directory)
557 return ENOENT;
558
559 return EOK;
560 }
561
562 return EINVAL;
563}
564
565/** Get list of volumes as array of volume IDs.
566 *
567 * @param vol Volume service
568 * @param data Place to store pointer to array
569 * @param count Place to store length of array (number of entries)
570 *
571 * @return EOK on success or an error code
572 */
573errno_t vol_get_volumes(vol_t *vol, volume_id_t **data, size_t *count)
574{
575 return vol_get_ids_internal(vol, VOL_GET_VOLUMES, 0,
576 (sysarg_t **) data, count);
577}
578
579/** Get volume configuration information.
580 *
581 * @param vol Volume service
582 * @param vid Volume ID
583 * @param vinfo Place to store volume configuration information
584 * @return EOK on success or an error code
585 */
586errno_t vol_info(vol_t *vol, volume_id_t vid, vol_info_t *vinfo)
587{
588 async_exch_t *exch;
589 errno_t retval;
590 ipc_call_t answer;
591
592 exch = async_exchange_begin(vol->sess);
593 aid_t req = async_send_1(exch, VOL_INFO, vid.id, &answer);
594
595 errno_t rc = async_data_read_start(exch, vinfo, sizeof(vol_info_t));
596 async_exchange_end(exch);
597 if (rc != EOK) {
598 async_forget(req);
599 return EIO;
600 }
601
602 async_wait_for(req, &retval);
603 if (retval != EOK)
604 return EIO;
605
606 return EOK;
607}
608
609/** @}
610 */
Note: See TracBrowser for help on using the repository browser.