source: mainline/uspace/lib/fdisk/src/fdisk.c@ 6a0d4ce2

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6a0d4ce2 was 1626cd4, checked in by Jiri Svoboda <jiri@…>, 10 years ago

Propagate label and partition block ranges and other info up through the stack.

  • Property mode set to 100644
File size: 12.1 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 libfdisk
30 * @{
31 */
32/**
33 * @file Disk management library.
34 */
35
36#include <adt/list.h>
37#include <block.h>
38#include <errno.h>
39#include <fdisk.h>
40#include <loc.h>
41#include <mem.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <str.h>
45#include <vbd.h>
46#include <vol.h>
47
48static const char *cu_str[] = {
49 [cu_byte] = "B",
50 [cu_kbyte] = "kB",
51 [cu_mbyte] = "MB",
52 [cu_gbyte] = "GB",
53 [cu_tbyte] = "TB",
54 [cu_pbyte] = "PB",
55 [cu_ebyte] = "EB",
56 [cu_zbyte] = "ZB",
57 [cu_ybyte] = "YB"
58};
59
60static void fdisk_dev_info_delete(fdisk_dev_info_t *info)
61{
62 if (info == NULL)
63 return;
64
65 if (info->blk_inited)
66 block_fini(info->svcid);
67
68 free(info->svcname);
69 free(info);
70}
71
72int fdisk_create(fdisk_t **rfdisk)
73{
74 fdisk_t *fdisk = NULL;
75 int rc;
76
77 fdisk = calloc(1, sizeof(fdisk_t));
78 if (fdisk == NULL) {
79 rc = ENOMEM;
80 goto error;
81 }
82
83 rc = vol_create(&fdisk->vol);
84 if (rc != EOK) {
85 rc = EIO;
86 goto error;
87 }
88
89 rc = vbd_create(&fdisk->vbd);
90 if (rc != EOK) {
91 rc = EIO;
92 goto error;
93 }
94
95 *rfdisk = fdisk;
96 return EOK;
97error:
98 fdisk_destroy(fdisk);
99
100 return rc;
101}
102
103void fdisk_destroy(fdisk_t *fdisk)
104{
105 if (fdisk == NULL)
106 return;
107
108 vol_destroy(fdisk->vol);
109 vbd_destroy(fdisk->vbd);
110 free(fdisk);
111}
112
113int fdisk_dev_list_get(fdisk_t *fdisk, fdisk_dev_list_t **rdevlist)
114{
115 fdisk_dev_list_t *devlist = NULL;
116 fdisk_dev_info_t *info;
117 service_id_t *svcs = NULL;
118 size_t count, i;
119 int rc;
120
121 devlist = calloc(1, sizeof(fdisk_dev_list_t));
122 if (devlist == NULL)
123 return ENOMEM;
124
125 list_initialize(&devlist->devinfos);
126
127 rc = vol_get_disks(fdisk->vol, &svcs, &count);
128 if (rc != EOK) {
129 rc = EIO;
130 goto error;
131 }
132
133 for (i = 0; i < count; i++) {
134 info = calloc(1, sizeof(fdisk_dev_info_t));
135 if (info == NULL) {
136 rc = ENOMEM;
137 goto error;
138 }
139
140 info->svcid = svcs[i];
141 info->devlist = devlist;
142 list_append(&info->ldevlist, &devlist->devinfos);
143 }
144
145 *rdevlist = devlist;
146 free(svcs);
147 return EOK;
148error:
149 free(svcs);
150 fdisk_dev_list_free(devlist);
151 return rc;
152}
153
154void fdisk_dev_list_free(fdisk_dev_list_t *devlist)
155{
156 fdisk_dev_info_t *info;
157
158 if (devlist == NULL)
159 return;
160
161 while (!list_empty(&devlist->devinfos)) {
162 info = list_get_instance(list_first(
163 &devlist->devinfos), fdisk_dev_info_t,
164 ldevlist);
165
166 list_remove(&info->ldevlist);
167 fdisk_dev_info_delete(info);
168 }
169
170 free(devlist);
171}
172
173fdisk_dev_info_t *fdisk_dev_first(fdisk_dev_list_t *devlist)
174{
175 if (list_empty(&devlist->devinfos))
176 return NULL;
177
178 return list_get_instance(list_first(&devlist->devinfos),
179 fdisk_dev_info_t, ldevlist);
180}
181
182fdisk_dev_info_t *fdisk_dev_next(fdisk_dev_info_t *devinfo)
183{
184 link_t *lnext;
185
186 lnext = list_next(&devinfo->ldevlist,
187 &devinfo->devlist->devinfos);
188 if (lnext == NULL)
189 return NULL;
190
191 return list_get_instance(lnext, fdisk_dev_info_t,
192 ldevlist);
193}
194
195void fdisk_dev_info_get_svcid(fdisk_dev_info_t *info, service_id_t *rsid)
196{
197 *rsid = info->svcid;
198}
199
200int fdisk_dev_info_get_svcname(fdisk_dev_info_t *info, char **rname)
201{
202 char *name;
203 int rc;
204
205 if (info->svcname == NULL) {
206 rc = loc_service_get_name(info->svcid,
207 &info->svcname);
208 if (rc != EOK)
209 return rc;
210 }
211
212 name = str_dup(info->svcname);
213 if (name == NULL)
214 return ENOMEM;
215
216 *rname = name;
217 return EOK;
218}
219
220int fdisk_dev_info_capacity(fdisk_dev_info_t *info, fdisk_cap_t *cap)
221{
222 size_t bsize;
223 aoff64_t nblocks;
224 int rc;
225
226 if (!info->blk_inited) {
227 rc = block_init(EXCHANGE_SERIALIZE, info->svcid, 2048);
228 if (rc != EOK)
229 return rc;
230
231 info->blk_inited = true;
232 }
233
234 rc = block_get_bsize(info->svcid, &bsize);
235 if (rc != EOK)
236 return EIO;
237
238 rc = block_get_nblocks(info->svcid, &nblocks);
239 if (rc != EOK)
240 return EIO;
241
242 cap->value = bsize * nblocks;
243 cap->cunit = cu_byte;
244
245 return EOK;
246}
247
248static int fdisk_part_add(fdisk_dev_t *dev, vbd_part_id_t partid,
249 fdisk_part_t **rpart)
250{
251 fdisk_part_t *part, *p;
252 vbd_part_info_t pinfo;
253 link_t *link;
254 int rc;
255
256 part = calloc(1, sizeof(fdisk_part_t));
257 if (part == NULL)
258 return ENOMEM;
259
260 rc = vbd_part_get_info(dev->fdisk->vbd, partid, &pinfo);
261 if (rc != EOK) {
262 rc = EIO;
263 goto error;
264 }
265
266 part->dev = dev;
267 part->index = pinfo.index;
268 part->block0 = pinfo.block0;
269 part->nblocks = pinfo.nblocks;
270
271 /* Insert to list by block address */
272 link = list_first(&dev->parts_ba);
273 while (link != NULL) {
274 p = list_get_instance(link, fdisk_part_t, ldev_ba);
275 if (p->block0 > part->block0) {
276 list_insert_before(&part->ldev_ba, &p->ldev_ba);
277 break;
278 }
279
280 link = list_next(link, &dev->parts_ba);
281 }
282
283 if (link == NULL)
284 list_append(&part->ldev_ba, &dev->parts_ba);
285
286 /* Insert to list by index */
287 link = list_first(&dev->parts_idx);
288 while (link != NULL) {
289 p = list_get_instance(link, fdisk_part_t, ldev_idx);
290 if (p->index > part->index) {
291 list_insert_before(&part->ldev_idx, &p->ldev_idx);
292 break;
293 }
294
295 link = list_next(link, &dev->parts_idx);
296 }
297
298 if (link == NULL)
299 list_append(&part->ldev_idx, &dev->parts_idx);
300
301 part->capacity.cunit = cu_byte;
302 part->capacity.value = part->nblocks * dev->dinfo.block_size;
303 part->part_id = partid;
304
305 if (rpart != NULL)
306 *rpart = part;
307 return EOK;
308error:
309 free(part);
310 return rc;
311}
312
313
314int fdisk_dev_open(fdisk_t *fdisk, service_id_t sid, fdisk_dev_t **rdev)
315{
316 fdisk_dev_t *dev = NULL;
317 service_id_t *psids = NULL;
318 size_t nparts, i;
319 int rc;
320
321 dev = calloc(1, sizeof(fdisk_dev_t));
322 if (dev == NULL)
323 return ENOMEM;
324
325 dev->fdisk = fdisk;
326 dev->sid = sid;
327 list_initialize(&dev->parts_idx);
328 list_initialize(&dev->parts_ba);
329
330 printf("get info\n");
331 rc = vbd_disk_info(fdisk->vbd, sid, &dev->dinfo);
332 if (rc != EOK) {
333 printf("failed\n");
334 rc = EIO;
335 goto error;
336 }
337
338 printf("block size: %zu\n", dev->dinfo.block_size);
339 printf("get partitions\n");
340 rc = vbd_label_get_parts(fdisk->vbd, sid, &psids, &nparts);
341 if (rc != EOK) {
342 printf("failed\n");
343 rc = EIO;
344 goto error;
345 }
346 printf("OK\n");
347
348 printf("found %zu partitions.\n", nparts);
349 for (i = 0; i < nparts; i++) {
350 printf("add partition sid=%zu\n", psids[i]);
351 rc = fdisk_part_add(dev, psids[i], NULL);
352 if (rc != EOK) {
353 printf("failed\n");
354 goto error;
355 }
356 printf("OK\n");
357 }
358
359 free(psids);
360 *rdev = dev;
361 return EOK;
362error:
363 fdisk_dev_close(dev);
364 return rc;
365}
366
367void fdisk_dev_close(fdisk_dev_t *dev)
368{
369 if (dev == NULL)
370 return;
371
372 /* XXX Clean up partitions */
373 free(dev);
374}
375
376int fdisk_dev_get_svcname(fdisk_dev_t *dev, char **rname)
377{
378 char *name;
379 int rc;
380
381 rc = loc_service_get_name(dev->sid, &name);
382 if (rc != EOK)
383 return rc;
384
385 *rname = name;
386 return EOK;
387}
388
389int fdisk_dev_capacity(fdisk_dev_t *dev, fdisk_cap_t *cap)
390{
391 size_t bsize;
392 aoff64_t nblocks;
393 int rc;
394
395 rc = block_init(EXCHANGE_SERIALIZE, dev->sid, 2048);
396 if (rc != EOK)
397 return rc;
398
399 rc = block_get_bsize(dev->sid, &bsize);
400 if (rc != EOK)
401 return EIO;
402
403 rc = block_get_nblocks(dev->sid, &nblocks);
404 if (rc != EOK)
405 return EIO;
406
407 block_fini(dev->sid);
408
409 cap->value = bsize * nblocks;
410 cap->cunit = cu_byte;
411
412 return EOK;
413}
414
415int fdisk_label_get_info(fdisk_dev_t *dev, fdisk_label_info_t *info)
416{
417 vol_disk_info_t vinfo;
418 int rc;
419
420 rc = vol_disk_info(dev->fdisk->vol, dev->sid, &vinfo);
421 if (rc != EOK) {
422 rc = EIO;
423 goto error;
424 }
425
426 info->dcnt = vinfo.dcnt;
427 info->ltype = vinfo.ltype;
428 return EOK;
429error:
430 return rc;
431}
432
433int fdisk_label_create(fdisk_dev_t *dev, label_type_t ltype)
434{
435 return vol_label_create(dev->fdisk->vol, dev->sid, ltype);
436}
437
438int fdisk_label_destroy(fdisk_dev_t *dev)
439{
440 fdisk_part_t *part;
441 int rc;
442
443 part = fdisk_part_first(dev);
444 while (part != NULL) {
445 (void) fdisk_part_destroy(part); /* XXX */
446 part = fdisk_part_first(dev);
447 }
448
449 rc = vol_disk_empty(dev->fdisk->vol, dev->sid);
450 if (rc != EOK)
451 return EIO;
452
453 dev->dcnt = dc_empty;
454 return EOK;
455}
456
457fdisk_part_t *fdisk_part_first(fdisk_dev_t *dev)
458{
459 link_t *link;
460
461 link = list_first(&dev->parts_ba);
462 if (link == NULL)
463 return NULL;
464
465 return list_get_instance(link, fdisk_part_t, ldev_ba);
466}
467
468fdisk_part_t *fdisk_part_next(fdisk_part_t *part)
469{
470 link_t *link;
471
472 link = list_next(&part->ldev_ba, &part->dev->parts_ba);
473 if (link == NULL)
474 return NULL;
475
476 return list_get_instance(link, fdisk_part_t, ldev_ba);
477}
478
479int fdisk_part_get_info(fdisk_part_t *part, fdisk_part_info_t *info)
480{
481 info->capacity = part->capacity;
482 info->fstype = part->fstype;
483 return EOK;
484}
485
486int fdisk_part_get_max_avail(fdisk_dev_t *dev, fdisk_cap_t *cap)
487{
488 return EOK;
489}
490
491int fdisk_part_create(fdisk_dev_t *dev, fdisk_part_spec_t *pspec,
492 fdisk_part_t **rpart)
493{
494 fdisk_part_t *part;
495 vbd_part_spec_t vpspec;
496 vbd_part_id_t partid;
497 int rc;
498
499 part = calloc(1, sizeof(fdisk_part_t));
500 if (part == NULL)
501 return ENOMEM;
502
503 rc = vbd_part_create(dev->fdisk->vbd, dev->sid, &vpspec, &partid);
504 if (rc != EOK) {
505 free(part);
506 return EIO;
507 }
508
509 rc = fdisk_part_add(dev, partid, rpart);
510 if (rc != EOK) {
511 /* Try rolling back */
512 (void) vbd_part_delete(dev->fdisk->vbd, partid);
513 return EIO;
514 }
515
516 (*rpart)->fstype = pspec->fstype;
517 (*rpart)->capacity = pspec->capacity;
518
519 return EOK;
520}
521
522int fdisk_part_destroy(fdisk_part_t *part)
523{
524 int rc;
525
526 rc = vbd_part_delete(part->dev->fdisk->vbd, part->part_id);
527 if (rc != EOK)
528 return EIO;
529
530 list_remove(&part->ldev_ba);
531 list_remove(&part->ldev_idx);
532 free(part);
533 return EOK;
534}
535
536void fdisk_pspec_init(fdisk_part_spec_t *pspec)
537{
538 memset(pspec, 0, sizeof(fdisk_part_spec_t));
539}
540
541int fdisk_cap_format(fdisk_cap_t *cap, char **rstr)
542{
543 int rc;
544 const char *sunit;
545
546 sunit = NULL;
547
548 if (cap->cunit < 0 || cap->cunit >= CU_LIMIT)
549 assert(false);
550
551 sunit = cu_str[cap->cunit];
552 rc = asprintf(rstr, "%" PRIu64 " %s", cap->value, sunit);
553 if (rc < 0)
554 return ENOMEM;
555
556 return EOK;
557}
558
559int fdisk_cap_parse(const char *str, fdisk_cap_t *cap)
560{
561 char *eptr;
562 char *p;
563 unsigned long val;
564 int i;
565
566 val = strtoul(str, &eptr, 10);
567
568 while (*eptr == ' ')
569 ++eptr;
570
571 if (*eptr == '\0') {
572 cap->cunit = cu_byte;
573 } else {
574 for (i = 0; i < CU_LIMIT; i++) {
575 if (str_lcasecmp(eptr, cu_str[i],
576 str_length(cu_str[i])) == 0) {
577 p = eptr + str_size(cu_str[i]);
578 while (*p == ' ')
579 ++p;
580 if (*p == '\0')
581 goto found;
582 }
583 }
584
585 return EINVAL;
586found:
587 cap->cunit = i;
588 }
589
590 cap->value = val;
591 return EOK;
592}
593
594int fdisk_ltype_format(label_type_t ltype, char **rstr)
595{
596 const char *sltype;
597 char *s;
598
599 sltype = NULL;
600 switch (ltype) {
601 case lt_mbr:
602 sltype = "MBR";
603 break;
604 case lt_gpt:
605 sltype = "GPT";
606 break;
607 }
608
609 s = str_dup(sltype);
610 if (s == NULL)
611 return ENOMEM;
612
613 *rstr = s;
614 return EOK;
615}
616
617int fdisk_fstype_format(fdisk_fstype_t fstype, char **rstr)
618{
619 const char *sfstype;
620 char *s;
621
622 sfstype = NULL;
623 switch (fstype) {
624 case fdfs_none:
625 sfstype = "None";
626 break;
627 case fdfs_unknown:
628 sfstype = "Unknown";
629 break;
630 case fdfs_exfat:
631 sfstype = "ExFAT";
632 break;
633 case fdfs_fat:
634 sfstype = "FAT";
635 break;
636 case fdfs_minix:
637 sfstype = "MINIX";
638 break;
639 case fdfs_ext4:
640 sfstype = "Ext4";
641 break;
642 }
643
644 s = str_dup(sfstype);
645 if (s == NULL)
646 return ENOMEM;
647
648 *rstr = s;
649 return EOK;
650}
651
652/** @}
653 */
Note: See TracBrowser for help on using the repository browser.