command: Remove the cmd_tbl_t typedef
[oweals/u-boot.git] / fs / fs.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
4  */
5
6 #include <command.h>
7 #include <config.h>
8 #include <errno.h>
9 #include <common.h>
10 #include <env.h>
11 #include <lmb.h>
12 #include <mapmem.h>
13 #include <part.h>
14 #include <ext4fs.h>
15 #include <fat.h>
16 #include <fs.h>
17 #include <sandboxfs.h>
18 #include <ubifs_uboot.h>
19 #include <btrfs.h>
20 #include <asm/io.h>
21 #include <div64.h>
22 #include <linux/math64.h>
23 #include <efi_loader.h>
24
25 DECLARE_GLOBAL_DATA_PTR;
26
27 static struct blk_desc *fs_dev_desc;
28 static int fs_dev_part;
29 static struct disk_partition fs_partition;
30 static int fs_type = FS_TYPE_ANY;
31
32 static inline int fs_probe_unsupported(struct blk_desc *fs_dev_desc,
33                                       struct disk_partition *fs_partition)
34 {
35         printf("** Unrecognized filesystem type **\n");
36         return -1;
37 }
38
39 static inline int fs_ls_unsupported(const char *dirname)
40 {
41         return -1;
42 }
43
44 /* generic implementation of ls in terms of opendir/readdir/closedir */
45 __maybe_unused
46 static int fs_ls_generic(const char *dirname)
47 {
48         struct fs_dir_stream *dirs;
49         struct fs_dirent *dent;
50         int nfiles = 0, ndirs = 0;
51
52         dirs = fs_opendir(dirname);
53         if (!dirs)
54                 return -errno;
55
56         while ((dent = fs_readdir(dirs))) {
57                 if (dent->type == FS_DT_DIR) {
58                         printf("            %s/\n", dent->name);
59                         ndirs++;
60                 } else {
61                         printf(" %8lld   %s\n", dent->size, dent->name);
62                         nfiles++;
63                 }
64         }
65
66         fs_closedir(dirs);
67
68         printf("\n%d file(s), %d dir(s)\n\n", nfiles, ndirs);
69
70         return 0;
71 }
72
73 static inline int fs_exists_unsupported(const char *filename)
74 {
75         return 0;
76 }
77
78 static inline int fs_size_unsupported(const char *filename, loff_t *size)
79 {
80         return -1;
81 }
82
83 static inline int fs_read_unsupported(const char *filename, void *buf,
84                                       loff_t offset, loff_t len,
85                                       loff_t *actread)
86 {
87         return -1;
88 }
89
90 static inline int fs_write_unsupported(const char *filename, void *buf,
91                                       loff_t offset, loff_t len,
92                                       loff_t *actwrite)
93 {
94         return -1;
95 }
96
97 static inline int fs_ln_unsupported(const char *filename, const char *target)
98 {
99         return -1;
100 }
101
102 static inline void fs_close_unsupported(void)
103 {
104 }
105
106 static inline int fs_uuid_unsupported(char *uuid_str)
107 {
108         return -1;
109 }
110
111 static inline int fs_opendir_unsupported(const char *filename,
112                                          struct fs_dir_stream **dirs)
113 {
114         return -EACCES;
115 }
116
117 static inline int fs_unlink_unsupported(const char *filename)
118 {
119         return -1;
120 }
121
122 static inline int fs_mkdir_unsupported(const char *dirname)
123 {
124         return -1;
125 }
126
127 struct fstype_info {
128         int fstype;
129         char *name;
130         /*
131          * Is it legal to pass NULL as .probe()'s  fs_dev_desc parameter? This
132          * should be false in most cases. For "virtual" filesystems which
133          * aren't based on a U-Boot block device (e.g. sandbox), this can be
134          * set to true. This should also be true for the dummy entry at the end
135          * of fstypes[], since that is essentially a "virtual" (non-existent)
136          * filesystem.
137          */
138         bool null_dev_desc_ok;
139         int (*probe)(struct blk_desc *fs_dev_desc,
140                      struct disk_partition *fs_partition);
141         int (*ls)(const char *dirname);
142         int (*exists)(const char *filename);
143         int (*size)(const char *filename, loff_t *size);
144         int (*read)(const char *filename, void *buf, loff_t offset,
145                     loff_t len, loff_t *actread);
146         int (*write)(const char *filename, void *buf, loff_t offset,
147                      loff_t len, loff_t *actwrite);
148         void (*close)(void);
149         int (*uuid)(char *uuid_str);
150         /*
151          * Open a directory stream.  On success return 0 and directory
152          * stream pointer via 'dirsp'.  On error, return -errno.  See
153          * fs_opendir().
154          */
155         int (*opendir)(const char *filename, struct fs_dir_stream **dirsp);
156         /*
157          * Read next entry from directory stream.  On success return 0
158          * and directory entry pointer via 'dentp'.  On error return
159          * -errno.  See fs_readdir().
160          */
161         int (*readdir)(struct fs_dir_stream *dirs, struct fs_dirent **dentp);
162         /* see fs_closedir() */
163         void (*closedir)(struct fs_dir_stream *dirs);
164         int (*unlink)(const char *filename);
165         int (*mkdir)(const char *dirname);
166         int (*ln)(const char *filename, const char *target);
167 };
168
169 static struct fstype_info fstypes[] = {
170 #ifdef CONFIG_FS_FAT
171         {
172                 .fstype = FS_TYPE_FAT,
173                 .name = "fat",
174                 .null_dev_desc_ok = false,
175                 .probe = fat_set_blk_dev,
176                 .close = fat_close,
177                 .ls = fs_ls_generic,
178                 .exists = fat_exists,
179                 .size = fat_size,
180                 .read = fat_read_file,
181 #if CONFIG_IS_ENABLED(FAT_WRITE)
182                 .write = file_fat_write,
183                 .unlink = fat_unlink,
184                 .mkdir = fat_mkdir,
185 #else
186                 .write = fs_write_unsupported,
187                 .unlink = fs_unlink_unsupported,
188                 .mkdir = fs_mkdir_unsupported,
189 #endif
190                 .uuid = fs_uuid_unsupported,
191                 .opendir = fat_opendir,
192                 .readdir = fat_readdir,
193                 .closedir = fat_closedir,
194                 .ln = fs_ln_unsupported,
195         },
196 #endif
197
198 #if CONFIG_IS_ENABLED(FS_EXT4)
199         {
200                 .fstype = FS_TYPE_EXT,
201                 .name = "ext4",
202                 .null_dev_desc_ok = false,
203                 .probe = ext4fs_probe,
204                 .close = ext4fs_close,
205                 .ls = ext4fs_ls,
206                 .exists = ext4fs_exists,
207                 .size = ext4fs_size,
208                 .read = ext4_read_file,
209 #ifdef CONFIG_CMD_EXT4_WRITE
210                 .write = ext4_write_file,
211                 .ln = ext4fs_create_link,
212 #else
213                 .write = fs_write_unsupported,
214                 .ln = fs_ln_unsupported,
215 #endif
216                 .uuid = ext4fs_uuid,
217                 .opendir = fs_opendir_unsupported,
218                 .unlink = fs_unlink_unsupported,
219                 .mkdir = fs_mkdir_unsupported,
220         },
221 #endif
222 #ifdef CONFIG_SANDBOX
223         {
224                 .fstype = FS_TYPE_SANDBOX,
225                 .name = "sandbox",
226                 .null_dev_desc_ok = true,
227                 .probe = sandbox_fs_set_blk_dev,
228                 .close = sandbox_fs_close,
229                 .ls = sandbox_fs_ls,
230                 .exists = sandbox_fs_exists,
231                 .size = sandbox_fs_size,
232                 .read = fs_read_sandbox,
233                 .write = fs_write_sandbox,
234                 .uuid = fs_uuid_unsupported,
235                 .opendir = fs_opendir_unsupported,
236                 .unlink = fs_unlink_unsupported,
237                 .mkdir = fs_mkdir_unsupported,
238                 .ln = fs_ln_unsupported,
239         },
240 #endif
241 #ifdef CONFIG_CMD_UBIFS
242         {
243                 .fstype = FS_TYPE_UBIFS,
244                 .name = "ubifs",
245                 .null_dev_desc_ok = true,
246                 .probe = ubifs_set_blk_dev,
247                 .close = ubifs_close,
248                 .ls = ubifs_ls,
249                 .exists = ubifs_exists,
250                 .size = ubifs_size,
251                 .read = ubifs_read,
252                 .write = fs_write_unsupported,
253                 .uuid = fs_uuid_unsupported,
254                 .opendir = fs_opendir_unsupported,
255                 .unlink = fs_unlink_unsupported,
256                 .mkdir = fs_mkdir_unsupported,
257                 .ln = fs_ln_unsupported,
258         },
259 #endif
260 #ifdef CONFIG_FS_BTRFS
261         {
262                 .fstype = FS_TYPE_BTRFS,
263                 .name = "btrfs",
264                 .null_dev_desc_ok = false,
265                 .probe = btrfs_probe,
266                 .close = btrfs_close,
267                 .ls = btrfs_ls,
268                 .exists = btrfs_exists,
269                 .size = btrfs_size,
270                 .read = btrfs_read,
271                 .write = fs_write_unsupported,
272                 .uuid = btrfs_uuid,
273                 .opendir = fs_opendir_unsupported,
274                 .unlink = fs_unlink_unsupported,
275                 .mkdir = fs_mkdir_unsupported,
276                 .ln = fs_ln_unsupported,
277         },
278 #endif
279         {
280                 .fstype = FS_TYPE_ANY,
281                 .name = "unsupported",
282                 .null_dev_desc_ok = true,
283                 .probe = fs_probe_unsupported,
284                 .close = fs_close_unsupported,
285                 .ls = fs_ls_unsupported,
286                 .exists = fs_exists_unsupported,
287                 .size = fs_size_unsupported,
288                 .read = fs_read_unsupported,
289                 .write = fs_write_unsupported,
290                 .uuid = fs_uuid_unsupported,
291                 .opendir = fs_opendir_unsupported,
292                 .unlink = fs_unlink_unsupported,
293                 .mkdir = fs_mkdir_unsupported,
294                 .ln = fs_ln_unsupported,
295         },
296 };
297
298 static struct fstype_info *fs_get_info(int fstype)
299 {
300         struct fstype_info *info;
301         int i;
302
303         for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) {
304                 if (fstype == info->fstype)
305                         return info;
306         }
307
308         /* Return the 'unsupported' sentinel */
309         return info;
310 }
311
312 /**
313  * fs_get_type() - Get type of current filesystem
314  *
315  * Return: filesystem type
316  *
317  * Returns filesystem type representing the current filesystem, or
318  * FS_TYPE_ANY for any unrecognised filesystem.
319  */
320 int fs_get_type(void)
321 {
322         return fs_type;
323 }
324
325 /**
326  * fs_get_type_name() - Get type of current filesystem
327  *
328  * Return: Pointer to filesystem name
329  *
330  * Returns a string describing the current filesystem, or the sentinel
331  * "unsupported" for any unrecognised filesystem.
332  */
333 const char *fs_get_type_name(void)
334 {
335         return fs_get_info(fs_type)->name;
336 }
337
338 int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
339 {
340         struct fstype_info *info;
341         int part, i;
342 #ifdef CONFIG_NEEDS_MANUAL_RELOC
343         static int relocated;
344
345         if (!relocated) {
346                 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes);
347                                 i++, info++) {
348                         info->name += gd->reloc_off;
349                         info->probe += gd->reloc_off;
350                         info->close += gd->reloc_off;
351                         info->ls += gd->reloc_off;
352                         info->read += gd->reloc_off;
353                         info->write += gd->reloc_off;
354                 }
355                 relocated = 1;
356         }
357 #endif
358
359         part = blk_get_device_part_str(ifname, dev_part_str, &fs_dev_desc,
360                                         &fs_partition, 1);
361         if (part < 0)
362                 return -1;
363
364         for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
365                 if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY &&
366                                 fstype != info->fstype)
367                         continue;
368
369                 if (!fs_dev_desc && !info->null_dev_desc_ok)
370                         continue;
371
372                 if (!info->probe(fs_dev_desc, &fs_partition)) {
373                         fs_type = info->fstype;
374                         fs_dev_part = part;
375                         return 0;
376                 }
377         }
378
379         return -1;
380 }
381
382 /* set current blk device w/ blk_desc + partition # */
383 int fs_set_blk_dev_with_part(struct blk_desc *desc, int part)
384 {
385         struct fstype_info *info;
386         int ret, i;
387
388         if (part >= 1)
389                 ret = part_get_info(desc, part, &fs_partition);
390         else
391                 ret = part_get_info_whole_disk(desc, &fs_partition);
392         if (ret)
393                 return ret;
394         fs_dev_desc = desc;
395
396         for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
397                 if (!info->probe(fs_dev_desc, &fs_partition)) {
398                         fs_type = info->fstype;
399                         fs_dev_part = part;
400                         return 0;
401                 }
402         }
403
404         return -1;
405 }
406
407 void fs_close(void)
408 {
409         struct fstype_info *info = fs_get_info(fs_type);
410
411         info->close();
412
413         fs_type = FS_TYPE_ANY;
414 }
415
416 int fs_uuid(char *uuid_str)
417 {
418         struct fstype_info *info = fs_get_info(fs_type);
419
420         return info->uuid(uuid_str);
421 }
422
423 int fs_ls(const char *dirname)
424 {
425         int ret;
426
427         struct fstype_info *info = fs_get_info(fs_type);
428
429         ret = info->ls(dirname);
430
431         fs_close();
432
433         return ret;
434 }
435
436 int fs_exists(const char *filename)
437 {
438         int ret;
439
440         struct fstype_info *info = fs_get_info(fs_type);
441
442         ret = info->exists(filename);
443
444         fs_close();
445
446         return ret;
447 }
448
449 int fs_size(const char *filename, loff_t *size)
450 {
451         int ret;
452
453         struct fstype_info *info = fs_get_info(fs_type);
454
455         ret = info->size(filename, size);
456
457         fs_close();
458
459         return ret;
460 }
461
462 #ifdef CONFIG_LMB
463 /* Check if a file may be read to the given address */
464 static int fs_read_lmb_check(const char *filename, ulong addr, loff_t offset,
465                              loff_t len, struct fstype_info *info)
466 {
467         struct lmb lmb;
468         int ret;
469         loff_t size;
470         loff_t read_len;
471
472         /* get the actual size of the file */
473         ret = info->size(filename, &size);
474         if (ret)
475                 return ret;
476         if (offset >= size) {
477                 /* offset >= EOF, no bytes will be written */
478                 return 0;
479         }
480         read_len = size - offset;
481
482         /* limit to 'len' if it is smaller */
483         if (len && len < read_len)
484                 read_len = len;
485
486         lmb_init_and_reserve(&lmb, gd->bd, (void *)gd->fdt_blob);
487         lmb_dump_all(&lmb);
488
489         if (lmb_alloc_addr(&lmb, addr, read_len) == addr)
490                 return 0;
491
492         printf("** Reading file would overwrite reserved memory **\n");
493         return -ENOSPC;
494 }
495 #endif
496
497 static int _fs_read(const char *filename, ulong addr, loff_t offset, loff_t len,
498                     int do_lmb_check, loff_t *actread)
499 {
500         struct fstype_info *info = fs_get_info(fs_type);
501         void *buf;
502         int ret;
503
504 #ifdef CONFIG_LMB
505         if (do_lmb_check) {
506                 ret = fs_read_lmb_check(filename, addr, offset, len, info);
507                 if (ret)
508                         return ret;
509         }
510 #endif
511
512         /*
513          * We don't actually know how many bytes are being read, since len==0
514          * means read the whole file.
515          */
516         buf = map_sysmem(addr, len);
517         ret = info->read(filename, buf, offset, len, actread);
518         unmap_sysmem(buf);
519
520         /* If we requested a specific number of bytes, check we got it */
521         if (ret == 0 && len && *actread != len)
522                 debug("** %s shorter than offset + len **\n", filename);
523         fs_close();
524
525         return ret;
526 }
527
528 int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len,
529             loff_t *actread)
530 {
531         return _fs_read(filename, addr, offset, len, 0, actread);
532 }
533
534 int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
535              loff_t *actwrite)
536 {
537         struct fstype_info *info = fs_get_info(fs_type);
538         void *buf;
539         int ret;
540
541         buf = map_sysmem(addr, len);
542         ret = info->write(filename, buf, offset, len, actwrite);
543         unmap_sysmem(buf);
544
545         if (ret < 0 && len != *actwrite) {
546                 printf("** Unable to write file %s **\n", filename);
547                 ret = -1;
548         }
549         fs_close();
550
551         return ret;
552 }
553
554 struct fs_dir_stream *fs_opendir(const char *filename)
555 {
556         struct fstype_info *info = fs_get_info(fs_type);
557         struct fs_dir_stream *dirs = NULL;
558         int ret;
559
560         ret = info->opendir(filename, &dirs);
561         fs_close();
562         if (ret) {
563                 errno = -ret;
564                 return NULL;
565         }
566
567         dirs->desc = fs_dev_desc;
568         dirs->part = fs_dev_part;
569
570         return dirs;
571 }
572
573 struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs)
574 {
575         struct fstype_info *info;
576         struct fs_dirent *dirent;
577         int ret;
578
579         fs_set_blk_dev_with_part(dirs->desc, dirs->part);
580         info = fs_get_info(fs_type);
581
582         ret = info->readdir(dirs, &dirent);
583         fs_close();
584         if (ret) {
585                 errno = -ret;
586                 return NULL;
587         }
588
589         return dirent;
590 }
591
592 void fs_closedir(struct fs_dir_stream *dirs)
593 {
594         struct fstype_info *info;
595
596         if (!dirs)
597                 return;
598
599         fs_set_blk_dev_with_part(dirs->desc, dirs->part);
600         info = fs_get_info(fs_type);
601
602         info->closedir(dirs);
603         fs_close();
604 }
605
606 int fs_unlink(const char *filename)
607 {
608         int ret;
609
610         struct fstype_info *info = fs_get_info(fs_type);
611
612         ret = info->unlink(filename);
613
614         fs_close();
615
616         return ret;
617 }
618
619 int fs_mkdir(const char *dirname)
620 {
621         int ret;
622
623         struct fstype_info *info = fs_get_info(fs_type);
624
625         ret = info->mkdir(dirname);
626
627         fs_close();
628
629         return ret;
630 }
631
632 int fs_ln(const char *fname, const char *target)
633 {
634         struct fstype_info *info = fs_get_info(fs_type);
635         int ret;
636
637         ret = info->ln(fname, target);
638
639         if (ret < 0) {
640                 printf("** Unable to create link %s -> %s **\n", fname, target);
641                 ret = -1;
642         }
643         fs_close();
644
645         return ret;
646 }
647
648 int do_size(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[],
649             int fstype)
650 {
651         loff_t size;
652
653         if (argc != 4)
654                 return CMD_RET_USAGE;
655
656         if (fs_set_blk_dev(argv[1], argv[2], fstype))
657                 return 1;
658
659         if (fs_size(argv[3], &size) < 0)
660                 return CMD_RET_FAILURE;
661
662         env_set_hex("filesize", size);
663
664         return 0;
665 }
666
667 int do_load(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[],
668             int fstype)
669 {
670         unsigned long addr;
671         const char *addr_str;
672         const char *filename;
673         loff_t bytes;
674         loff_t pos;
675         loff_t len_read;
676         int ret;
677         unsigned long time;
678         char *ep;
679
680         if (argc < 2)
681                 return CMD_RET_USAGE;
682         if (argc > 7)
683                 return CMD_RET_USAGE;
684
685         if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
686                 return 1;
687
688         if (argc >= 4) {
689                 addr = simple_strtoul(argv[3], &ep, 16);
690                 if (ep == argv[3] || *ep != '\0')
691                         return CMD_RET_USAGE;
692         } else {
693                 addr_str = env_get("loadaddr");
694                 if (addr_str != NULL)
695                         addr = simple_strtoul(addr_str, NULL, 16);
696                 else
697                         addr = CONFIG_SYS_LOAD_ADDR;
698         }
699         if (argc >= 5) {
700                 filename = argv[4];
701         } else {
702                 filename = env_get("bootfile");
703                 if (!filename) {
704                         puts("** No boot file defined **\n");
705                         return 1;
706                 }
707         }
708         if (argc >= 6)
709                 bytes = simple_strtoul(argv[5], NULL, 16);
710         else
711                 bytes = 0;
712         if (argc >= 7)
713                 pos = simple_strtoul(argv[6], NULL, 16);
714         else
715                 pos = 0;
716
717 #ifdef CONFIG_CMD_BOOTEFI
718         efi_set_bootdev(argv[1], (argc > 2) ? argv[2] : "",
719                         (argc > 4) ? argv[4] : "");
720 #endif
721         time = get_timer(0);
722         ret = _fs_read(filename, addr, pos, bytes, 1, &len_read);
723         time = get_timer(time);
724         if (ret < 0)
725                 return 1;
726
727         printf("%llu bytes read in %lu ms", len_read, time);
728         if (time > 0) {
729                 puts(" (");
730                 print_size(div_u64(len_read, time) * 1000, "/s");
731                 puts(")");
732         }
733         puts("\n");
734
735         env_set_hex("fileaddr", addr);
736         env_set_hex("filesize", len_read);
737
738         return 0;
739 }
740
741 int do_ls(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[],
742           int fstype)
743 {
744         if (argc < 2)
745                 return CMD_RET_USAGE;
746         if (argc > 4)
747                 return CMD_RET_USAGE;
748
749         if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
750                 return 1;
751
752         if (fs_ls(argc >= 4 ? argv[3] : "/"))
753                 return 1;
754
755         return 0;
756 }
757
758 int file_exists(const char *dev_type, const char *dev_part, const char *file,
759                 int fstype)
760 {
761         if (fs_set_blk_dev(dev_type, dev_part, fstype))
762                 return 0;
763
764         return fs_exists(file);
765 }
766
767 int do_save(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[],
768             int fstype)
769 {
770         unsigned long addr;
771         const char *filename;
772         loff_t bytes;
773         loff_t pos;
774         loff_t len;
775         int ret;
776         unsigned long time;
777
778         if (argc < 6 || argc > 7)
779                 return CMD_RET_USAGE;
780
781         if (fs_set_blk_dev(argv[1], argv[2], fstype))
782                 return 1;
783
784         addr = simple_strtoul(argv[3], NULL, 16);
785         filename = argv[4];
786         bytes = simple_strtoul(argv[5], NULL, 16);
787         if (argc >= 7)
788                 pos = simple_strtoul(argv[6], NULL, 16);
789         else
790                 pos = 0;
791
792         time = get_timer(0);
793         ret = fs_write(filename, addr, pos, bytes, &len);
794         time = get_timer(time);
795         if (ret < 0)
796                 return 1;
797
798         printf("%llu bytes written in %lu ms", len, time);
799         if (time > 0) {
800                 puts(" (");
801                 print_size(div_u64(len, time) * 1000, "/s");
802                 puts(")");
803         }
804         puts("\n");
805
806         return 0;
807 }
808
809 int do_fs_uuid(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[],
810                int fstype)
811 {
812         int ret;
813         char uuid[37];
814         memset(uuid, 0, sizeof(uuid));
815
816         if (argc < 3 || argc > 4)
817                 return CMD_RET_USAGE;
818
819         if (fs_set_blk_dev(argv[1], argv[2], fstype))
820                 return 1;
821
822         ret = fs_uuid(uuid);
823         if (ret)
824                 return CMD_RET_FAILURE;
825
826         if (argc == 4)
827                 env_set(argv[3], uuid);
828         else
829                 printf("%s\n", uuid);
830
831         return CMD_RET_SUCCESS;
832 }
833
834 int do_fs_type(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
835 {
836         struct fstype_info *info;
837
838         if (argc < 3 || argc > 4)
839                 return CMD_RET_USAGE;
840
841         if (fs_set_blk_dev(argv[1], argv[2], FS_TYPE_ANY))
842                 return 1;
843
844         info = fs_get_info(fs_type);
845
846         if (argc == 4)
847                 env_set(argv[3], info->name);
848         else
849                 printf("%s\n", info->name);
850
851         fs_close();
852
853         return CMD_RET_SUCCESS;
854 }
855
856 int do_rm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[],
857           int fstype)
858 {
859         if (argc != 4)
860                 return CMD_RET_USAGE;
861
862         if (fs_set_blk_dev(argv[1], argv[2], fstype))
863                 return 1;
864
865         if (fs_unlink(argv[3]))
866                 return 1;
867
868         return 0;
869 }
870
871 int do_mkdir(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[],
872              int fstype)
873 {
874         int ret;
875
876         if (argc != 4)
877                 return CMD_RET_USAGE;
878
879         if (fs_set_blk_dev(argv[1], argv[2], fstype))
880                 return 1;
881
882         ret = fs_mkdir(argv[3]);
883         if (ret) {
884                 printf("** Unable to create a directory \"%s\" **\n", argv[3]);
885                 return 1;
886         }
887
888         return 0;
889 }
890
891 int do_ln(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[],
892           int fstype)
893 {
894         if (argc != 5)
895                 return CMD_RET_USAGE;
896
897         if (fs_set_blk_dev(argv[1], argv[2], fstype))
898                 return 1;
899
900         if (fs_ln(argv[3], argv[4]))
901                 return 1;
902
903         return 0;
904 }