source: mainline/uspace/srv/volsrv/volsrv.c@ 6f13257

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

Allow physically ejecting CD-ROM using vol eject -s

  • Property mode set to 100644
File size: 13.4 KB
Line 
1/*
2 * Copyright (c) 2025 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 volsrv
30 * @{
31 */
32/**
33 * @file Volume service
34 */
35
36#include <async.h>
37#include <errno.h>
38#include <str_error.h>
39#include <io/log.h>
40#include <ipc/services.h>
41#include <ipc/vol.h>
42#include <loc.h>
43#include <macros.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <task.h>
47#include <types/vol.h>
48
49#include "mkfs.h"
50#include "part.h"
51#include "volume.h"
52
53#define NAME "volsrv"
54
55const char *vol_icfg_file = "/cfg/initvol.sif";
56const char *vol_cfg_file = "/w/cfg/volsrv.sif";
57
58static void vol_client_conn(ipc_call_t *, void *);
59
60static errno_t vol_init(void)
61{
62 errno_t rc;
63 vol_volumes_t *volumes = NULL;
64 vol_parts_t *parts = NULL;
65 loc_srv_t *srv = NULL;
66
67 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_init()");
68
69 rc = vol_volumes_create(vol_icfg_file, &volumes);
70 if (rc != EOK)
71 goto error;
72
73 rc = vol_parts_create(volumes, &parts);
74 if (rc != EOK)
75 goto error;
76
77 rc = vol_part_discovery_start(parts);
78 if (rc != EOK)
79 goto error;
80
81 async_set_fallback_port_handler(vol_client_conn, parts);
82
83 rc = loc_server_register(NAME, &srv);
84 if (rc != EOK) {
85 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering server: %s.", str_error(rc));
86 rc = EEXIST;
87 }
88
89 service_id_t sid;
90 rc = loc_service_register(srv, SERVICE_NAME_VOLSRV, &sid);
91 if (rc != EOK) {
92 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service: %s.", str_error(rc));
93 rc = EEXIST;
94 goto error;
95 }
96
97 return EOK;
98error:
99 if (srv != NULL)
100 loc_server_unregister(srv);
101 vol_volumes_destroy(volumes);
102 vol_parts_destroy(parts);
103 return rc;
104}
105
106static void vol_get_parts_srv(vol_parts_t *parts, ipc_call_t *icall)
107{
108 ipc_call_t call;
109 size_t size;
110 size_t act_size;
111 errno_t rc;
112
113 if (!async_data_read_receive(&call, &size)) {
114 async_answer_0(&call, EREFUSED);
115 async_answer_0(icall, EREFUSED);
116 return;
117 }
118
119 service_id_t *id_buf = (service_id_t *) malloc(size);
120 if (id_buf == NULL) {
121 async_answer_0(&call, ENOMEM);
122 async_answer_0(icall, ENOMEM);
123 return;
124 }
125
126 rc = vol_part_get_ids(parts, id_buf, size, &act_size);
127 if (rc != EOK) {
128 async_answer_0(&call, rc);
129 async_answer_0(icall, rc);
130 return;
131 }
132
133 errno_t retval = async_data_read_finalize(&call, id_buf, size);
134 free(id_buf);
135
136 async_answer_1(icall, retval, act_size);
137}
138
139static void vol_part_add_srv(vol_parts_t *parts, ipc_call_t *icall)
140{
141 service_id_t sid;
142 errno_t rc;
143
144 sid = ipc_get_arg1(icall);
145
146 rc = vol_part_add_part(parts, sid);
147 if (rc != EOK) {
148 async_answer_0(icall, rc);
149 return;
150 }
151
152 async_answer_0(icall, EOK);
153}
154
155static void vol_part_info_srv(vol_parts_t *parts, ipc_call_t *icall)
156{
157 service_id_t sid;
158 vol_part_t *part;
159 vol_part_info_t pinfo;
160 errno_t rc;
161
162 sid = ipc_get_arg1(icall);
163 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_part_info_srv(%zu)",
164 sid);
165 rc = vol_part_find_by_id_ref(parts, sid, &part);
166 if (rc != EOK) {
167 async_answer_0(icall, ENOENT);
168 return;
169 }
170
171 rc = vol_part_get_info(part, &pinfo);
172 if (rc != EOK) {
173 async_answer_0(icall, EIO);
174 goto error;
175 }
176
177 ipc_call_t call;
178 size_t size;
179 if (!async_data_read_receive(&call, &size)) {
180 async_answer_0(&call, EREFUSED);
181 async_answer_0(icall, EREFUSED);
182 goto error;
183 }
184
185 if (size != sizeof(vol_part_info_t)) {
186 async_answer_0(&call, EINVAL);
187 async_answer_0(icall, EINVAL);
188 goto error;
189 }
190
191 rc = async_data_read_finalize(&call, &pinfo,
192 min(size, sizeof(pinfo)));
193 if (rc != EOK) {
194 async_answer_0(&call, rc);
195 async_answer_0(icall, rc);
196 goto error;
197 }
198
199 async_answer_0(icall, EOK);
200error:
201 vol_part_del_ref(part);
202}
203
204static void vol_part_eject_srv(vol_parts_t *parts, ipc_call_t *icall)
205{
206 service_id_t sid;
207 vol_eject_flags_t flags;
208 vol_part_t *part;
209 errno_t rc;
210
211 sid = ipc_get_arg1(icall);
212 flags = ipc_get_arg2(icall);
213
214 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_part_eject_srv(%zu, %x)",
215 sid, flags);
216
217 rc = vol_part_find_by_id_ref(parts, sid, &part);
218 if (rc != EOK) {
219 async_answer_0(icall, ENOENT);
220 return;
221 }
222
223 rc = vol_part_eject_part(part, flags);
224 if (rc != EOK) {
225 async_answer_0(icall, EIO);
226 goto error;
227 }
228
229 async_answer_0(icall, EOK);
230error:
231 vol_part_del_ref(part);
232}
233
234static void vol_part_insert_srv(vol_parts_t *parts, ipc_call_t *icall)
235{
236 service_id_t sid;
237 vol_part_t *part;
238 errno_t rc;
239
240 sid = ipc_get_arg1(icall);
241 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_part_insert_srv(%zu)", sid);
242
243 rc = vol_part_find_by_id_ref(parts, sid, &part);
244 if (rc != EOK) {
245 async_answer_0(icall, ENOENT);
246 return;
247 }
248
249 rc = vol_part_insert_part(part);
250 if (rc != EOK) {
251 async_answer_0(icall, EIO);
252 goto error;
253 }
254
255 async_answer_0(icall, EOK);
256error:
257 vol_part_del_ref(part);
258}
259
260static void vol_part_insert_by_path_srv(vol_parts_t *parts, ipc_call_t *icall)
261{
262 vol_part_t *part;
263 char *path = NULL;
264 errno_t rc;
265
266 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_part_insert_by_path_srv()");
267
268 rc = async_data_write_accept((void **)&path, true, 0, VOL_MOUNTP_MAXLEN,
269 0, NULL);
270 if (rc != EOK) {
271 async_answer_0(icall, rc);
272 goto error;
273 }
274
275 rc = vol_part_find_by_path_ref(parts, path, &part);
276 if (rc != EOK) {
277 async_answer_0(icall, ENOENT);
278 goto error;
279 }
280
281 rc = vol_part_insert_part(part);
282 if (rc != EOK) {
283 async_answer_0(icall, rc);
284 vol_part_del_ref(part);
285 goto error;
286 }
287
288 free(path);
289 vol_part_del_ref(part);
290 async_answer_0(icall, EOK);
291
292 return;
293error:
294 if (path != NULL)
295 free(path);
296}
297
298static void vol_part_empty_srv(vol_parts_t *parts, ipc_call_t *icall)
299{
300 service_id_t sid;
301 vol_part_t *part;
302 errno_t rc;
303
304 sid = ipc_get_arg1(icall);
305 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_part_empty_srv(%zu)", sid);
306
307 rc = vol_part_find_by_id_ref(parts, sid, &part);
308 if (rc != EOK) {
309 async_answer_0(icall, ENOENT);
310 return;
311 }
312
313 rc = vol_part_empty_part(part);
314 if (rc != EOK) {
315 async_answer_0(icall, EIO);
316 goto error;
317 }
318
319 async_answer_0(icall, EOK);
320error:
321 vol_part_del_ref(part);
322}
323
324static void vol_part_get_lsupp_srv(vol_parts_t *parts, ipc_call_t *icall)
325{
326 vol_fstype_t fstype;
327 vol_label_supp_t vlsupp;
328 errno_t rc;
329
330 fstype = ipc_get_arg1(icall);
331 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_part_get_lsupp_srv(%u)",
332 fstype);
333
334 volsrv_part_get_lsupp(fstype, &vlsupp);
335
336 ipc_call_t call;
337 size_t size;
338 if (!async_data_read_receive(&call, &size)) {
339 async_answer_0(&call, EREFUSED);
340 async_answer_0(icall, EREFUSED);
341 return;
342 }
343
344 if (size != sizeof(vol_label_supp_t)) {
345 async_answer_0(&call, EINVAL);
346 async_answer_0(icall, EINVAL);
347 return;
348 }
349
350 rc = async_data_read_finalize(&call, &vlsupp,
351 min(size, sizeof(vlsupp)));
352 if (rc != EOK) {
353 async_answer_0(&call, rc);
354 async_answer_0(icall, rc);
355 return;
356 }
357
358 async_answer_0(icall, EOK);
359}
360
361static void vol_part_mkfs_srv(vol_parts_t *parts, ipc_call_t *icall)
362{
363 service_id_t sid;
364 vol_part_t *part;
365 vol_fstype_t fstype;
366 char *label = NULL;
367 char *mountp = NULL;
368 errno_t rc;
369
370 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_part_mkfs_srv()");
371
372 sid = ipc_get_arg1(icall);
373 fstype = ipc_get_arg2(icall);
374
375 rc = async_data_write_accept((void **)&label, true, 0, VOL_LABEL_MAXLEN,
376 0, NULL);
377 if (rc != EOK) {
378 async_answer_0(icall, rc);
379 goto error;
380 }
381
382 if (label != NULL) {
383 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_part_mkfs_srv: label='%s'",
384 label);
385 }
386
387 rc = async_data_write_accept((void **)&mountp, true, 0, VOL_MOUNTP_MAXLEN,
388 0, NULL);
389 if (rc != EOK) {
390 async_answer_0(icall, rc);
391 goto error;
392 }
393
394 if (mountp != NULL) {
395 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_part_mkfs_srv: mountp='%s'",
396 mountp);
397 }
398
399 rc = vol_part_find_by_id_ref(parts, sid, &part);
400 if (rc != EOK) {
401 async_answer_0(icall, ENOENT);
402 goto error;
403 }
404
405 rc = vol_part_mkfs_part(part, fstype, label, mountp);
406 if (rc != EOK) {
407 async_answer_0(icall, rc);
408 vol_part_del_ref(part);
409 goto error;
410 }
411
412 free(label);
413 free(mountp);
414 async_answer_0(icall, EOK);
415
416 return;
417error:
418 if (label != NULL)
419 free(label);
420 if (mountp != NULL)
421 free(mountp);
422}
423
424static void vol_part_set_mountp_srv(vol_parts_t *parts,
425 ipc_call_t *icall)
426{
427 service_id_t sid;
428 vol_part_t *part;
429 char *mountp;
430 errno_t rc;
431
432 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_part_set_mountp_srv()");
433
434 sid = ipc_get_arg1(icall);
435
436 rc = async_data_write_accept((void **)&mountp, true, 0,
437 VOL_MOUNTP_MAXLEN, 0, NULL);
438 if (rc != EOK) {
439 async_answer_0(icall, rc);
440 return;
441 }
442
443 if (mountp != NULL) {
444 log_msg(LOG_DEFAULT, LVL_DEBUG,
445 "vol_part_set_mountp_srv: mountp='%s'", mountp);
446 }
447
448 rc = vol_part_find_by_id_ref(parts, sid, &part);
449 if (rc != EOK) {
450 free(mountp);
451 async_answer_0(icall, ENOENT);
452 return;
453 }
454
455 rc = vol_part_set_mountp_part(part, mountp);
456 if (rc != EOK) {
457 free(mountp);
458 async_answer_0(icall, rc);
459 vol_part_del_ref(part);
460 return;
461 }
462
463 free(mountp);
464 async_answer_0(icall, EOK);
465}
466
467static void vol_get_volumes_srv(vol_parts_t *parts, ipc_call_t *icall)
468{
469 ipc_call_t call;
470 size_t size;
471 size_t act_size;
472 errno_t rc;
473
474 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_get_volumes_srv()");
475
476 if (!async_data_read_receive(&call, &size)) {
477 async_answer_0(&call, EREFUSED);
478 async_answer_0(icall, EREFUSED);
479 return;
480 }
481
482 volume_id_t *id_buf = (volume_id_t *) malloc(size);
483 if (id_buf == NULL) {
484 async_answer_0(&call, ENOMEM);
485 async_answer_0(icall, ENOMEM);
486 return;
487 }
488
489 rc = vol_get_ids(parts->volumes, id_buf, size, &act_size);
490 if (rc != EOK) {
491 async_answer_0(&call, rc);
492 async_answer_0(icall, rc);
493 return;
494 }
495
496 errno_t retval = async_data_read_finalize(&call, id_buf, size);
497 free(id_buf);
498
499 async_answer_1(icall, retval, act_size);
500}
501
502static void vol_info_srv(vol_parts_t *parts, ipc_call_t *icall)
503{
504 volume_id_t vid;
505 vol_volume_t *volume;
506 vol_info_t vinfo;
507 errno_t rc;
508
509 vid.id = ipc_get_arg1(icall);
510 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_info_srv(%zu)", vid.id);
511
512 rc = vol_volume_find_by_id_ref(parts->volumes, vid, &volume);
513 if (rc != EOK) {
514 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_info_srv: volume %zu not found",
515 vid.id);
516 async_answer_0(icall, ENOENT);
517 return;
518 }
519
520 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_info_srv: vol_volume_get_info");
521 rc = vol_volume_get_info(volume, &vinfo);
522 if (rc != EOK) {
523 async_answer_0(icall, EIO);
524 goto error;
525 }
526
527 ipc_call_t call;
528 size_t size;
529 if (!async_data_read_receive(&call, &size)) {
530 async_answer_0(&call, EREFUSED);
531 async_answer_0(icall, EREFUSED);
532 goto error;
533 }
534
535 if (size != sizeof(vol_info_t)) {
536 async_answer_0(&call, EINVAL);
537 async_answer_0(icall, EINVAL);
538 goto error;
539 }
540
541 rc = async_data_read_finalize(&call, &vinfo,
542 min(size, sizeof(vinfo)));
543 if (rc != EOK) {
544 async_answer_0(&call, rc);
545 async_answer_0(icall, rc);
546 goto error;
547 }
548
549 async_answer_0(icall, EOK);
550error:
551 vol_volume_del_ref(volume);
552}
553
554static void vol_client_conn(ipc_call_t *icall, void *arg)
555{
556 vol_parts_t *parts = (vol_parts_t *) arg;
557
558 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_client_conn()");
559
560 /* Accept the connection */
561 async_accept_0(icall);
562
563 while (true) {
564 ipc_call_t call;
565 async_get_call(&call);
566 sysarg_t method = ipc_get_imethod(&call);
567
568 if (!method) {
569 /* The other side has hung up */
570 async_answer_0(&call, EOK);
571 return;
572 }
573
574 switch (method) {
575 case VOL_GET_PARTS:
576 vol_get_parts_srv(parts, &call);
577 break;
578 case VOL_PART_ADD:
579 vol_part_add_srv(parts, &call);
580 break;
581 case VOL_PART_INFO:
582 vol_part_info_srv(parts, &call);
583 break;
584 case VOL_PART_EJECT:
585 vol_part_eject_srv(parts, &call);
586 break;
587 case VOL_PART_EMPTY:
588 vol_part_empty_srv(parts, &call);
589 break;
590 case VOL_PART_INSERT:
591 vol_part_insert_srv(parts, &call);
592 break;
593 case VOL_PART_INSERT_BY_PATH:
594 vol_part_insert_by_path_srv(parts, &call);
595 break;
596 case VOL_PART_LSUPP:
597 vol_part_get_lsupp_srv(parts, &call);
598 break;
599 case VOL_PART_MKFS:
600 vol_part_mkfs_srv(parts, &call);
601 break;
602 case VOL_PART_SET_MOUNTP:
603 vol_part_set_mountp_srv(parts, &call);
604 break;
605 case VOL_GET_VOLUMES:
606 vol_get_volumes_srv(parts, &call);
607 break;
608 case VOL_INFO:
609 vol_info_srv(parts, &call);
610 break;
611 default:
612 async_answer_0(&call, EINVAL);
613 }
614 }
615}
616
617int main(int argc, char *argv[])
618{
619 errno_t rc;
620
621 printf("%s: Volume service\n", NAME);
622
623 if (log_init(NAME) != EOK) {
624 printf(NAME ": Failed to initialize logging.\n");
625 return 1;
626 }
627
628 rc = vol_init();
629 if (rc != EOK)
630 return 1;
631
632 printf(NAME ": Accepting connections.\n");
633 task_retval(0);
634 async_manager();
635
636 return 0;
637}
638
639/** @}
640 */
Note: See TracBrowser for help on using the repository browser.