source: mainline/uspace/lib/device/src/vol.c@ 4285f384

Last change on this file since 4285f384 was 4285f384, checked in by Jiri Svoboda <jiri@…>, 4 months ago

Allow physically ejecting CD-ROM using vol eject -s

  • Property mode set to 100644
File size: 13.5 KB
RevLine 
[22fb7ab]1/*
[4285f384]2 * Copyright (c) 2025 Jiri Svoboda
[22fb7ab]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
[edeee9f]29/** @addtogroup libdevice
[22fb7ab]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
[4285f384]255 * @param flags Ejection flags
[f0f8787]256 * @return EOK on success or an error code
257 */
[4285f384]258errno_t vol_part_eject(vol_t *vol, service_id_t sid, vol_eject_flags_t flags)
[72c72d4]259{
260 async_exch_t *exch;
261 errno_t retval;
262
263 exch = async_exchange_begin(vol->sess);
[4285f384]264 retval = async_req_2_0(exch, VOL_PART_EJECT, sid, flags);
[72c72d4]265 async_exchange_end(exch);
266
267 if (retval != EOK)
268 return retval;
269
270 return EOK;
271}
272
[372df8f]273/** Erase partition (to the extent where we will consider it not containing
[7c3fb9b]274 * a file system.
[f0f8787]275 *
276 * @param vol Volume service
277 * @param sid Service ID of the partition
278 * @return EOK on success or an error code
[7c3fb9b]279 */
[b7fd2a0]280errno_t vol_part_empty(vol_t *vol, service_id_t sid)
[22fb7ab]281{
282 async_exch_t *exch;
[b7fd2a0]283 errno_t retval;
[22fb7ab]284
285 exch = async_exchange_begin(vol->sess);
[372df8f]286 retval = async_req_1_0(exch, VOL_PART_EMPTY, sid);
[22fb7ab]287 async_exchange_end(exch);
288
289 if (retval != EOK)
[ea0ff6b]290 return retval;
[22fb7ab]291
292 return EOK;
293}
294
[f0f8787]295/** Insert volume.
296 *
297 * This will re-mount the volume if it has been ejected previously.
298 *
299 * @param vol Volume service
300 * @param sid Service ID of the partition
301 * @return EOK on success or an error code
302 */
303errno_t vol_part_insert(vol_t *vol, service_id_t sid)
304{
305 async_exch_t *exch;
306 errno_t retval;
307
308 exch = async_exchange_begin(vol->sess);
309 retval = async_req_1_0(exch, VOL_PART_INSERT, sid);
310 async_exchange_end(exch);
311
312 if (retval != EOK)
313 return retval;
314
315 return EOK;
316}
317
[b82985e]318/** Insert volume by path.
319 *
320 * @param vol Volume service
321 * @param path Filesystem path
322 *
323 * @return EOK on success or an error code
324 */
325errno_t vol_part_insert_by_path(vol_t *vol, const char *path)
326{
327 async_exch_t *exch;
328 ipc_call_t answer;
329 errno_t retval;
330
331 exch = async_exchange_begin(vol->sess);
332 aid_t req = async_send_0(exch, VOL_PART_INSERT_BY_PATH, &answer);
333
334 retval = async_data_write_start(exch, path, str_size(path));
335 if (retval != EOK) {
336 async_exchange_end(exch);
337 async_forget(req);
338 return retval;
339 }
340
341 async_exchange_end(exch);
342 async_wait_for(req, &retval);
343
344 if (retval != EOK)
345 return retval;
346
347 return EOK;
348}
349
[f0f8787]350/** Get volume label support.
351 *
352 * @param vol Volume service
353 * @param fstype File system type
354 * @param vlsupp Place to store volume label support information
355 * @return EOK on success or an error code
356 */
[b7fd2a0]357errno_t vol_part_get_lsupp(vol_t *vol, vol_fstype_t fstype,
[9c2c7d2]358 vol_label_supp_t *vlsupp)
359{
360 async_exch_t *exch;
[b7fd2a0]361 errno_t retval;
[9c2c7d2]362 ipc_call_t answer;
363
364 exch = async_exchange_begin(vol->sess);
365 aid_t req = async_send_1(exch, VOL_PART_LSUPP, fstype, &answer);
[b7fd2a0]366 errno_t rc = async_data_read_start(exch, vlsupp, sizeof(vol_label_supp_t));
[9c2c7d2]367 async_exchange_end(exch);
368
369 if (rc != EOK) {
370 async_forget(req);
371 return EIO;
372 }
373
374 async_wait_for(req, &retval);
375 if (retval != EOK)
376 return EIO;
377
378 return EOK;
379}
380
[64ffd83]381/** Create file system.
382 *
383 * @param vol Volume service
384 * @param sid Partition service ID
385 * @param fstype File system type
386 * @param label Volume label
387 * @param mountp Mount point
388 *
389 * @return EOK on success or an error code
390 */
[b7fd2a0]391errno_t vol_part_mkfs(vol_t *vol, service_id_t sid, vol_fstype_t fstype,
[64ffd83]392 const char *label, const char *mountp)
[44fe800]393{
394 async_exch_t *exch;
[9c2c7d2]395 ipc_call_t answer;
[b7fd2a0]396 errno_t retval;
[44fe800]397
398 exch = async_exchange_begin(vol->sess);
[9c2c7d2]399 aid_t req = async_send_2(exch, VOL_PART_MKFS, sid, fstype, &answer);
[64ffd83]400
[9c2c7d2]401 retval = async_data_write_start(exch, label, str_size(label));
[64ffd83]402 if (retval != EOK) {
403 async_exchange_end(exch);
404 async_forget(req);
405 return retval;
406 }
[44fe800]407
[64ffd83]408 retval = async_data_write_start(exch, mountp, str_size(mountp));
[9c2c7d2]409 if (retval != EOK) {
[64ffd83]410 async_exchange_end(exch);
[9c2c7d2]411 async_forget(req);
412 return retval;
413 }
414
[64ffd83]415 async_exchange_end(exch);
[9c2c7d2]416 async_wait_for(req, &retval);
417
[44fe800]418 if (retval != EOK)
419 return retval;
420
421 return EOK;
422}
423
[2d78d88]424/** Set mount point for partition.
425 *
426 * @param vol Volume service
427 * @param sid Partition service ID
428 * @param mountp Mount point
429 *
430 * @return EOK on success or an error code
431 */
432errno_t vol_part_set_mountp(vol_t *vol, service_id_t sid,
433 const char *mountp)
434{
435 async_exch_t *exch;
436 ipc_call_t answer;
437 errno_t retval;
438
439 exch = async_exchange_begin(vol->sess);
440 aid_t req = async_send_1(exch, VOL_PART_SET_MOUNTP, sid,
441 &answer);
442
443 retval = async_data_write_start(exch, mountp, str_size(mountp));
444 if (retval != EOK) {
445 async_exchange_end(exch);
446 async_forget(req);
447 return retval;
448 }
449
450 async_exchange_end(exch);
451 async_wait_for(req, &retval);
452
453 if (retval != EOK)
454 return retval;
455
456 return EOK;
457}
458
[db9c889]459/** Format file system type as string.
460 *
461 * @param fstype File system type
462 * @param rstr Place to store pointer to newly allocated string
463 * @return EOK on success, ENOMEM if out of memory
464 */
465errno_t vol_fstype_format(vol_fstype_t fstype, char **rstr)
466{
467 const char *sfstype;
468 char *s;
469
470 sfstype = NULL;
471 switch (fstype) {
472 case fs_exfat:
473 sfstype = "ExFAT";
474 break;
475 case fs_fat:
476 sfstype = "FAT";
477 break;
478 case fs_minix:
479 sfstype = "MINIX";
480 break;
481 case fs_ext4:
482 sfstype = "Ext4";
483 break;
484 case fs_cdfs:
485 sfstype = "ISO 9660";
486 break;
487 }
488
489 s = str_dup(sfstype);
490 if (s == NULL)
491 return ENOMEM;
492
493 *rstr = s;
494 return EOK;
495}
496
497/** Format partition content / file system type as string.
498 *
499 * @param pcnt Partition content
500 * @param fstype File system type
501 * @param rstr Place to store pointer to newly allocated string
502 * @return EOK on success, ENOMEM if out of memory
503 */
504errno_t vol_pcnt_fs_format(vol_part_cnt_t pcnt, vol_fstype_t fstype,
505 char **rstr)
506{
507 int rc;
508 char *s = NULL;
509
510 switch (pcnt) {
511 case vpc_empty:
512 s = str_dup("Empty");
513 if (s == NULL)
514 return ENOMEM;
515 break;
516 case vpc_fs:
517 rc = vol_fstype_format(fstype, &s);
518 if (rc != EOK)
519 return ENOMEM;
520 break;
521 case vpc_unknown:
522 s = str_dup("Unknown");
523 if (s == NULL)
524 return ENOMEM;
525 break;
526 }
527
528 assert(s != NULL);
529 *rstr = s;
530 return EOK;
531}
532
[64ffd83]533/** Validate mount point.
534 *
535 * Verify that mount point is valid. A valid mount point is
536 * one of:
537 * - 'Auto'
538 * - 'None'
539 * - /path (string beginning with '/') to an existing directory
540 *
541 * @return EOK if mount point is in valid, EINVAL if the format is invalid,
542 * ENOENT if the directory does not exist
543 */
544errno_t vol_mountp_validate(const char *mountp)
545{
546 errno_t rc;
547 vfs_stat_t stat;
548
549 if (str_cmp(mountp, "Auto") == 0 || str_cmp(mountp, "auto") == 0)
550 return EOK;
551
552 if (str_casecmp(mountp, "None") == 0 || str_cmp(mountp, "none") == 0)
553 return EOK;
554
555 if (mountp[0] == '/') {
556 rc = vfs_stat_path(mountp, &stat);
557 if (rc != EOK || !stat.is_directory)
558 return ENOENT;
559
560 return EOK;
561 }
562
563 return EINVAL;
564}
565
[63c1dd5]566/** Get list of volumes as array of volume IDs.
567 *
568 * @param vol Volume service
569 * @param data Place to store pointer to array
570 * @param count Place to store length of array (number of entries)
571 *
572 * @return EOK on success or an error code
573 */
574errno_t vol_get_volumes(vol_t *vol, volume_id_t **data, size_t *count)
575{
576 return vol_get_ids_internal(vol, VOL_GET_VOLUMES, 0,
577 (sysarg_t **) data, count);
578}
579
580/** Get volume configuration information.
581 *
582 * @param vol Volume service
583 * @param vid Volume ID
[c477c80]584 * @param vinfo Place to store volume configuration information
[63c1dd5]585 * @return EOK on success or an error code
586 */
587errno_t vol_info(vol_t *vol, volume_id_t vid, vol_info_t *vinfo)
588{
589 async_exch_t *exch;
590 errno_t retval;
591 ipc_call_t answer;
592
593 exch = async_exchange_begin(vol->sess);
594 aid_t req = async_send_1(exch, VOL_INFO, vid.id, &answer);
595
596 errno_t rc = async_data_read_start(exch, vinfo, sizeof(vol_info_t));
597 async_exchange_end(exch);
598 if (rc != EOK) {
599 async_forget(req);
600 return EIO;
601 }
602
603 async_wait_for(req, &retval);
604 if (retval != EOK)
605 return EIO;
606
607 return EOK;
608}
609
[22fb7ab]610/** @}
611 */
Note: See TracBrowser for help on using the repository browser.