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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 28a5ebd 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
RevLine 
[22fb7ab]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
[ff381a7]35#include <abi/ipc/interfaces.h>
[22fb7ab]36#include <errno.h>
37#include <ipc/services.h>
38#include <ipc/vol.h>
39#include <loc.h>
40#include <stdlib.h>
[9c2c7d2]41#include <str.h>
[64ffd83]42#include <vfs/vfs.h>
[22fb7ab]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 */
[b7fd2a0]51errno_t vol_create(vol_t **rvol)
[22fb7ab]52{
53 vol_t *vol;
54 service_id_t vol_svcid;
[b7fd2a0]55 errno_t rc;
[22fb7ab]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) {
[ff381a7]65 rc = ENOENT;
[22fb7ab]66 goto error;
67 }
68
[ff381a7]69 vol->sess = loc_service_connect(vol_svcid, INTERFACE_VOL, 0);
[22fb7ab]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 *
[cde999a]104 * @return EOK on success or an error code.
[22fb7ab]105 */
[b7fd2a0]106static errno_t vol_get_ids_once(vol_t *vol, sysarg_t method, sysarg_t arg1,
[22fb7ab]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);
[b7fd2a0]113 errno_t rc = async_data_read_start(exch, id_buf, buf_size);
[22fb7ab]114
115 async_exchange_end(exch);
116
117 if (rc != EOK) {
118 async_forget(req);
119 return rc;
120 }
121
[b7fd2a0]122 errno_t retval;
[22fb7ab]123 async_wait_for(req, &retval);
124
125 if (retval != EOK) {
126 return retval;
127 }
128
[fafb8e5]129 *act_size = ipc_get_arg1(&answer);
[22fb7ab]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
[cde999a]142 * @return EOK on success or an error code
[22fb7ab]143 */
[b7fd2a0]144static errno_t vol_get_ids_internal(vol_t *vol, sysarg_t method, sysarg_t arg1,
[22fb7ab]145 sysarg_t **data, size_t *count)
146{
147 *data = NULL;
148 *count = 0;
149
150 size_t act_size = 0;
[b7fd2a0]151 errno_t rc = vol_get_ids_once(vol, method, arg1, NULL, 0, &act_size);
[22fb7ab]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;
[265be8a]170 service_id_t *temp = realloc(ids, alloc_size);
171 if (temp == NULL) {
172 free(ids);
[22fb7ab]173 return ENOMEM;
[265be8a]174 }
175 ids = temp;
[22fb7ab]176 }
177
178 *count = act_size / sizeof(service_id_t);
179 *data = ids;
180 return EOK;
181}
182
[372df8f]183/** Get list of partitions as array of service IDs.
[22fb7ab]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 *
[cde999a]189 * @return EOK on success or an error code
[22fb7ab]190 */
[b7fd2a0]191errno_t vol_get_parts(vol_t *vol, service_id_t **data, size_t *count)
[22fb7ab]192{
[372df8f]193 return vol_get_ids_internal(vol, VOL_GET_PARTS, 0, data, count);
[22fb7ab]194}
195
[edebb4a1]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.
[f0f8787]201 *
202 * @param vol Volume service
203 * @param sid Service ID of the partition
204 * @return EOK on success or an error code
[edebb4a1]205 */
[b7fd2a0]206errno_t vol_part_add(vol_t *vol, service_id_t sid)
[edebb4a1]207{
208 async_exch_t *exch;
[b7fd2a0]209 errno_t retval;
[edebb4a1]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
[f0f8787]221/** Get partition information.
222 *
223 * @param vol Volume service
224 * @param sid Service ID of the partition
[c477c80]225 * @param vinfo Place to store partition information
[f0f8787]226 * @return EOK on success or an error code
227 */
[b7fd2a0]228errno_t vol_part_info(vol_t *vol, service_id_t sid, vol_part_info_t *vinfo)
[22fb7ab]229{
230 async_exch_t *exch;
[b7fd2a0]231 errno_t retval;
[0ecfc62]232 ipc_call_t answer;
[22fb7ab]233
234 exch = async_exchange_begin(vol->sess);
[0ecfc62]235 aid_t req = async_send_1(exch, VOL_PART_INFO, sid, &answer);
[64ffd83]236
[b7fd2a0]237 errno_t rc = async_data_read_start(exch, vinfo, sizeof(vol_part_info_t));
[22fb7ab]238 async_exchange_end(exch);
[0ecfc62]239 if (rc != EOK) {
240 async_forget(req);
241 return EIO;
242 }
243
244 async_wait_for(req, &retval);
[22fb7ab]245 if (retval != EOK)
246 return EIO;
247
248 return EOK;
249}
250
[f0f8787]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 */
[72c72d4]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
[372df8f]272/** Erase partition (to the extent where we will consider it not containing
[7c3fb9b]273 * a file system.
[f0f8787]274 *
275 * @param vol Volume service
276 * @param sid Service ID of the partition
277 * @return EOK on success or an error code
[7c3fb9b]278 */
[b7fd2a0]279errno_t vol_part_empty(vol_t *vol, service_id_t sid)
[22fb7ab]280{
281 async_exch_t *exch;
[b7fd2a0]282 errno_t retval;
[22fb7ab]283
284 exch = async_exchange_begin(vol->sess);
[372df8f]285 retval = async_req_1_0(exch, VOL_PART_EMPTY, sid);
[22fb7ab]286 async_exchange_end(exch);
287
288 if (retval != EOK)
[ea0ff6b]289 return retval;
[22fb7ab]290
291 return EOK;
292}
293
[f0f8787]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
[b82985e]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
[f0f8787]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 */
[b7fd2a0]356errno_t vol_part_get_lsupp(vol_t *vol, vol_fstype_t fstype,
[9c2c7d2]357 vol_label_supp_t *vlsupp)
358{
359 async_exch_t *exch;
[b7fd2a0]360 errno_t retval;
[9c2c7d2]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);
[b7fd2a0]365 errno_t rc = async_data_read_start(exch, vlsupp, sizeof(vol_label_supp_t));
[9c2c7d2]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
[64ffd83]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 */
[b7fd2a0]390errno_t vol_part_mkfs(vol_t *vol, service_id_t sid, vol_fstype_t fstype,
[64ffd83]391 const char *label, const char *mountp)
[44fe800]392{
393 async_exch_t *exch;
[9c2c7d2]394 ipc_call_t answer;
[b7fd2a0]395 errno_t retval;
[44fe800]396
397 exch = async_exchange_begin(vol->sess);
[9c2c7d2]398 aid_t req = async_send_2(exch, VOL_PART_MKFS, sid, fstype, &answer);
[64ffd83]399
[9c2c7d2]400 retval = async_data_write_start(exch, label, str_size(label));
[64ffd83]401 if (retval != EOK) {
402 async_exchange_end(exch);
403 async_forget(req);
404 return retval;
405 }
[44fe800]406
[64ffd83]407 retval = async_data_write_start(exch, mountp, str_size(mountp));
[9c2c7d2]408 if (retval != EOK) {
[64ffd83]409 async_exchange_end(exch);
[9c2c7d2]410 async_forget(req);
411 return retval;
412 }
413
[64ffd83]414 async_exchange_end(exch);
[9c2c7d2]415 async_wait_for(req, &retval);
416
[44fe800]417 if (retval != EOK)
418 return retval;
419
420 return EOK;
421}
422
[2d78d88]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
[db9c889]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
[64ffd83]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
[63c1dd5]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
[c477c80]583 * @param vinfo Place to store volume configuration information
[63c1dd5]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
[22fb7ab]609/** @}
610 */
Note: See TracBrowser for help on using the repository browser.