1 /*
2 * Copyright (c) 2016 Intel Corporation
3 * Copyright (c) 2023 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <errno.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <zephyr/shell/shell.h>
12 #include <zephyr/init.h>
13 #include <zephyr/fs/fs.h>
14 #include <zephyr/sd/sd_spec.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <inttypes.h>
18 #include <limits.h>
19
20 #define STORAGE_PARTITION storage_partition
21 #define STORAGE_PARTITION_ID FIXED_PARTITION_ID(STORAGE_PARTITION)
22
23 #ifdef CONFIG_FILE_SYSTEM_SHELL_MOUNT_COMMAND
24 /* FAT */
25 #ifdef CONFIG_FAT_FILESYSTEM_ELM
26 #include <ff.h>
27 #define FATFS_MNTP "/RAM:"
28 /* FatFs work area */
29 FATFS fat_fs;
30 /* mounting info */
31 static struct fs_mount_t fatfs_mnt = {
32 .type = FS_FATFS,
33 .fs_data = &fat_fs,
34 };
35 #endif
36 /* LITTLEFS */
37 #ifdef CONFIG_FILE_SYSTEM_LITTLEFS
38 #include <zephyr/fs/littlefs.h>
39
40 /* TODO: Implement dynamic storage dev selection */
41 #ifdef CONFIG_FS_LITTLEFS_BLK_DEV
42
43 #if defined(CONFIG_DISK_DRIVER_SDMMC)
44 #define DISK_NAME "SD"
45 #elif defined(CONFIG_DISK_DRIVER_MMC)
46 #define DISK_NAME "SD2"
47 #else
48 #error "No disk device defined, is your board supported?"
49 #endif
50
51 FS_LITTLEFS_DECLARE_CUSTOM_CONFIG(
52 lfs_data,
53 CONFIG_SDHC_BUFFER_ALIGNMENT,
54 SDMMC_DEFAULT_BLOCK_SIZE,
55 SDMMC_DEFAULT_BLOCK_SIZE,
56 SDMMC_DEFAULT_BLOCK_SIZE,
57 2 * SDMMC_DEFAULT_BLOCK_SIZE);
58
59 static struct fs_mount_t littlefs_mnt = {
60 .type = FS_LITTLEFS,
61 .fs_data = &lfs_data,
62 .flags = FS_MOUNT_FLAG_USE_DISK_ACCESS,
63 .storage_dev = DISK_NAME,
64 };
65 #else
66 #include <zephyr/storage/flash_map.h>
67
68 FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(lfs_data);
69 static struct fs_mount_t littlefs_mnt = {
70 .type = FS_LITTLEFS,
71 .fs_data = &lfs_data,
72 .storage_dev = (void *)STORAGE_PARTITION_ID,
73 };
74 #endif
75 #endif
76 #endif
77
78 #define BUF_CNT 64
79
80 #define MAX_PATH_LEN 128
81 #define MAX_FILENAME_LEN 128
82 #define MAX_INPUT_LEN 20
83
84 #define SHELL_FS "fs"
85
86 /* Maintenance guarantees this begins with '/' and is NUL-terminated. */
87 static char cwd[MAX_PATH_LEN] = "/";
88
create_abs_path(const char * name,char * path,size_t len)89 static void create_abs_path(const char *name, char *path, size_t len)
90 {
91 if (name[0] == '/') {
92 strncpy(path, name, len);
93 path[len - 1] = '\0';
94 } else {
95 if (cwd[1] == '\0') {
96 __ASSERT_NO_MSG(len >= 2);
97 *path++ = '/';
98 --len;
99
100 strncpy(path, name, len);
101 path[len - 1] = '\0';
102 } else {
103 strncpy(path, cwd, len);
104 path[len - 1] = '\0';
105
106 size_t plen = strlen(path);
107
108 if (plen < len) {
109 path += plen;
110 *path++ = '/';
111 len -= plen + 1U;
112 strncpy(path, name, len);
113 path[len - 1] = '\0';
114 }
115 }
116 }
117 }
118
cmd_cd(const struct shell * sh,size_t argc,char ** argv)119 static int cmd_cd(const struct shell *sh, size_t argc, char **argv)
120 {
121 char path[MAX_PATH_LEN];
122 struct fs_dirent entry;
123 int err;
124
125 if (argc < 2) {
126 strcpy(cwd, "/");
127 return 0;
128 }
129
130 if (strcmp(argv[1], "..") == 0) {
131 char *prev = strrchr(cwd, '/');
132
133 if (!prev || prev == cwd) {
134 strcpy(cwd, "/");
135 } else {
136 *prev = '\0';
137 }
138
139 /* No need to test that a parent exists */
140 return 0;
141 }
142
143 create_abs_path(argv[1], path, sizeof(path));
144
145 err = fs_stat(path, &entry);
146 if (err) {
147 shell_error(sh, "%s doesn't exist", path);
148 return -ENOEXEC;
149 }
150
151 if (entry.type != FS_DIR_ENTRY_DIR) {
152 shell_error(sh, "%s is not a directory", path);
153 return -ENOEXEC;
154 }
155
156 strncpy(cwd, path, sizeof(cwd));
157 cwd[sizeof(cwd) - 1] = '\0';
158
159 return 0;
160 }
161
cmd_ls(const struct shell * sh,size_t argc,char ** argv)162 static int cmd_ls(const struct shell *sh, size_t argc, char **argv)
163 {
164 char path[MAX_PATH_LEN];
165 struct fs_dir_t dir;
166 int err;
167
168 if (argc < 2) {
169 strncpy(path, cwd, sizeof(path));
170 path[sizeof(path) - 1] = '\0';
171 } else {
172 create_abs_path(argv[1], path, sizeof(path));
173 }
174
175 fs_dir_t_init(&dir);
176
177 err = fs_opendir(&dir, path);
178 if (err) {
179 shell_error(sh, "Unable to open %s (err %d)", path, err);
180 return -ENOEXEC;
181 }
182
183 while (1) {
184 struct fs_dirent entry;
185
186 err = fs_readdir(&dir, &entry);
187 if (err) {
188 shell_error(sh, "Unable to read directory");
189 break;
190 }
191
192 /* Check for end of directory listing */
193 if (entry.name[0] == '\0') {
194 break;
195 }
196
197 shell_print(sh, "%s%s", entry.name,
198 (entry.type == FS_DIR_ENTRY_DIR) ? "/" : "");
199 }
200
201 fs_closedir(&dir);
202
203 return 0;
204 }
205
cmd_pwd(const struct shell * sh,size_t argc,char ** argv)206 static int cmd_pwd(const struct shell *sh, size_t argc, char **argv)
207 {
208 shell_print(sh, "%s", cwd);
209
210 return 0;
211 }
212
cmd_trunc(const struct shell * sh,size_t argc,char ** argv)213 static int cmd_trunc(const struct shell *sh, size_t argc, char **argv)
214 {
215 char path[MAX_PATH_LEN];
216 struct fs_file_t file;
217 int length;
218 int err;
219
220 create_abs_path(argv[1], path, sizeof(path));
221
222 if (argc > 2) {
223 length = strtol(argv[2], NULL, 0);
224 } else {
225 length = 0;
226 }
227
228 fs_file_t_init(&file);
229 err = fs_open(&file, path, FS_O_WRITE);
230 if (err) {
231 shell_error(sh, "Failed to open %s (%d)", path, err);
232 return -ENOEXEC;;
233 }
234
235 err = fs_truncate(&file, length);
236 if (err) {
237 shell_error(sh, "Failed to truncate %s (%d)", path, err);
238 err = -ENOEXEC;
239 }
240
241 fs_close(&file);
242
243 return err;
244 }
245
cmd_mkdir(const struct shell * sh,size_t argc,char ** argv)246 static int cmd_mkdir(const struct shell *sh, size_t argc, char **argv)
247 {
248 int err;
249 char path[MAX_PATH_LEN];
250
251 create_abs_path(argv[1], path, sizeof(path));
252
253 err = fs_mkdir(path);
254 if (err) {
255 shell_error(sh, "Error creating dir[%d]", err);
256 err = -ENOEXEC;
257 }
258
259 return err;
260 }
261
cmd_rm(const struct shell * sh,size_t argc,char ** argv)262 static int cmd_rm(const struct shell *sh, size_t argc, char **argv)
263 {
264 int err;
265 char path[MAX_PATH_LEN];
266
267 create_abs_path(argv[1], path, sizeof(path));
268
269 err = fs_unlink(path);
270 if (err) {
271 shell_error(sh, "Failed to remove %s (%d)", path, err);
272 err = -ENOEXEC;
273 }
274
275 return err;
276 }
277
cmd_read(const struct shell * sh,size_t argc,char ** argv)278 static int cmd_read(const struct shell *sh, size_t argc, char **argv)
279 {
280 char path[MAX_PATH_LEN];
281 struct fs_dirent dirent;
282 struct fs_file_t file;
283 int count;
284 off_t offset;
285 int err;
286
287 create_abs_path(argv[1], path, sizeof(path));
288
289 if (argc > 2) {
290 count = strtol(argv[2], NULL, 0);
291 if (count <= 0) {
292 count = INT_MAX;
293 }
294 } else {
295 count = INT_MAX;
296 }
297
298 if (argc > 3) {
299 offset = strtol(argv[3], NULL, 0);
300 } else {
301 offset = 0;
302 }
303
304 err = fs_stat(path, &dirent);
305 if (err) {
306 shell_error(sh, "Failed to obtain file %s (err: %d)",
307 path, err);
308 return -ENOEXEC;
309 }
310
311 if (dirent.type != FS_DIR_ENTRY_FILE) {
312 shell_error(sh, "Not a file %s", path);
313 return -ENOEXEC;
314 }
315
316 shell_print(sh, "File size: %zd", dirent.size);
317
318 fs_file_t_init(&file);
319 err = fs_open(&file, path, FS_O_READ);
320 if (err) {
321 shell_error(sh, "Failed to open %s (%d)", path, err);
322 return -ENOEXEC;
323 }
324
325 if (offset > 0) {
326 err = fs_seek(&file, offset, FS_SEEK_SET);
327 if (err) {
328 shell_error(sh, "Failed to seek %s (%d)",
329 path, err);
330 fs_close(&file);
331 return -ENOEXEC;
332 }
333 }
334
335 while (count > 0) {
336 ssize_t read;
337 uint8_t buf[16];
338 int i;
339
340 read = fs_read(&file, buf, MIN(count, sizeof(buf)));
341 if (read <= 0) {
342 break;
343 }
344
345 shell_fprintf(sh, SHELL_NORMAL, "%08X ", (uint32_t)offset);
346
347 for (i = 0; i < read; i++) {
348 shell_fprintf(sh, SHELL_NORMAL, "%02X ", buf[i]);
349 }
350 for (; i < sizeof(buf); i++) {
351 shell_fprintf(sh, SHELL_NORMAL, " ");
352 }
353 i = sizeof(buf) - i;
354 shell_fprintf(sh, SHELL_NORMAL, "%*c", i*3, ' ');
355
356 for (i = 0; i < read; i++) {
357 shell_fprintf(sh, SHELL_NORMAL, "%c", buf[i] < 32 ||
358 buf[i] > 127 ? '.' : buf[i]);
359 }
360
361 shell_print(sh, "");
362
363 offset += read;
364 count -= read;
365 }
366
367 fs_close(&file);
368
369 return 0;
370 }
371
cmd_cat(const struct shell * sh,size_t argc,char ** argv)372 static int cmd_cat(const struct shell *sh, size_t argc, char **argv)
373 {
374 char path[MAX_PATH_LEN];
375 uint8_t buf[BUF_CNT];
376 struct fs_dirent dirent;
377 struct fs_file_t file;
378 int err;
379 ssize_t read;
380
381 fs_file_t_init(&file);
382
383 for (size_t i = 1; i < argc; ++i) {
384 create_abs_path(argv[i], path, sizeof(path));
385
386 err = fs_stat(path, &dirent);
387 if (err < 0) {
388 shell_error(sh, "Failed to obtain file %s (err: %d)",
389 path, err);
390 continue;
391 }
392
393 if (dirent.type != FS_DIR_ENTRY_FILE) {
394 shell_error(sh, "Not a file %s", path);
395 continue;
396 }
397
398 err = fs_open(&file, path, FS_O_READ);
399 if (err < 0) {
400 shell_error(sh, "Failed to open %s (%d)", path, err);
401 continue;
402 }
403
404 while (true) {
405 read = fs_read(&file, buf, sizeof(buf));
406 if (read <= 0) {
407 break;
408 }
409
410 for (int j = 0; j < read; j++) {
411 shell_fprintf(sh, SHELL_NORMAL, "%c", buf[j]);
412 }
413 }
414
415 if (read < 0) {
416 shell_error(sh, "Failed to read from file %s (err: %zd)",
417 path, read);
418 }
419
420 fs_close(&file);
421 }
422
423 return 0;
424 }
425
cmd_statvfs(const struct shell * sh,size_t argc,char ** argv)426 static int cmd_statvfs(const struct shell *sh, size_t argc, char **argv)
427 {
428 int err;
429 char path[MAX_PATH_LEN];
430 struct fs_statvfs stat;
431
432 create_abs_path(argv[1], path, sizeof(path));
433
434 err = fs_statvfs(path, &stat);
435 if (err < 0) {
436 shell_error(sh, "Failed to statvfs %s (%d)", path, err);
437 return -ENOEXEC;
438 }
439
440 shell_fprintf(sh, SHELL_NORMAL,
441 "bsize %lu, frsize %lu, blocks %lu, bfree %lu\n",
442 stat.f_bsize, stat.f_frsize, stat.f_blocks, stat.f_bfree);
443
444 return 0;
445 }
446
cmd_write(const struct shell * sh,size_t argc,char ** argv)447 static int cmd_write(const struct shell *sh, size_t argc, char **argv)
448 {
449 char path[MAX_PATH_LEN];
450 uint8_t buf[BUF_CNT];
451 uint8_t buf_len;
452 int arg_offset;
453 struct fs_file_t file;
454 off_t offset = -1;
455 int err;
456
457 create_abs_path(argv[1], path, sizeof(path));
458
459 if (!strcmp(argv[2], "-o")) {
460 if (argc < 4) {
461 shell_error(sh, "Missing argument");
462 return -ENOEXEC;
463 }
464
465 offset = strtol(argv[3], NULL, 0);
466
467 arg_offset = 4;
468 } else {
469 arg_offset = 2;
470 }
471
472 fs_file_t_init(&file);
473 err = fs_open(&file, path, FS_O_CREATE | FS_O_WRITE);
474 if (err) {
475 shell_error(sh, "Failed to open %s (%d)", path, err);
476 return -ENOEXEC;
477 }
478
479 if (offset < 0) {
480 err = fs_seek(&file, 0, FS_SEEK_END);
481 } else {
482 err = fs_seek(&file, offset, FS_SEEK_SET);
483 }
484 if (err) {
485 shell_error(sh, "Failed to seek %s (%d)", path, err);
486 fs_close(&file);
487 return -ENOEXEC;
488 }
489
490 buf_len = 0U;
491 while (arg_offset < argc) {
492 buf[buf_len++] = strtol(argv[arg_offset++], NULL, 16);
493
494 if ((buf_len == BUF_CNT) || (arg_offset == argc)) {
495 err = fs_write(&file, buf, buf_len);
496 if (err < 0) {
497 shell_error(sh, "Failed to write %s (%d)",
498 path, err);
499 fs_close(&file);
500 return -ENOEXEC;
501 }
502
503 buf_len = 0U;
504 }
505 }
506
507 fs_close(&file);
508
509 return 0;
510 }
511
512 #ifdef CONFIG_FILE_SYSTEM_SHELL_TEST_COMMANDS
513 const static uint8_t speed_types[][4] = { "B", "KiB", "MiB", "GiB" };
514 const static uint32_t speed_divisor = 1024;
515
file_size_output(const struct shell * sh,double size)516 static void file_size_output(const struct shell *sh, double size)
517 {
518 uint8_t speed_index = 0;
519
520 while (size >= (double)speed_divisor && speed_index < ARRAY_SIZE(speed_types)) {
521 size /= (double)speed_divisor;
522 ++speed_index;
523 }
524
525 shell_print(sh, "File size: %.1f%s",
526 size, speed_types[speed_index]);
527 }
528
speed_output(const struct shell * sh,uint64_t total_time,double loops,double size)529 static void speed_output(const struct shell *sh, uint64_t total_time, double loops, double size)
530 {
531 double time_per_loop = (double)total_time / loops;
532 double throughput = size;
533 uint8_t speed_index = 0;
534
535 if (time_per_loop > 0) {
536 throughput /= (time_per_loop / 1000.0);
537 }
538
539 while (throughput >= (double)speed_divisor && speed_index < ARRAY_SIZE(speed_types)) {
540 throughput /= (double)speed_divisor;
541 ++speed_index;
542 }
543
544 shell_print(sh, "Total: %llums, Per loop: ~%.0fms, Speed: ~%.1f%sps",
545 total_time, time_per_loop, throughput, speed_types[speed_index]);
546 }
547
cmd_read_test(const struct shell * sh,size_t argc,char ** argv)548 static int cmd_read_test(const struct shell *sh, size_t argc, char **argv)
549 {
550 char path[MAX_PATH_LEN];
551 struct fs_dirent dirent;
552 struct fs_file_t file;
553 int err;
554 uint32_t repeat;
555 uint8_t random_data[CONFIG_FILE_SYSTEM_SHELL_BUFFER_SIZE];
556 uint32_t i;
557 uint64_t start_time;
558 uint64_t loop_time;
559 uint64_t total_time = 0;
560 uint32_t loops = 0;
561 uint32_t size;
562
563 if (argc < 3) {
564 shell_error(sh, "Missing parameters: read_test <path> <repeat>");
565 return -EINVAL;
566 }
567
568 create_abs_path(argv[1], path, sizeof(path));
569 repeat = strtol(argv[2], NULL, 0);
570
571 if (repeat == 0 || repeat > 10) {
572 shell_error(sh, "<repeat> must be between 1 and 10.");
573 return -EINVAL;
574 }
575
576 err = fs_stat(path, &dirent);
577
578 if (err != 0) {
579 shell_error(sh, "File status failed: %d", err);
580 return err;
581 }
582
583 if (dirent.type != FS_DIR_ENTRY_FILE) {
584 shell_error(sh, "Provided path is not a file");
585 return -ENOENT;
586 }
587
588 /* Store size of file so we can ensure it was fully read */
589 size = dirent.size;
590 file_size_output(sh, (double)size);
591
592 while (loops < repeat) {
593 start_time = k_uptime_get();
594
595 fs_file_t_init(&file);
596 err = fs_open(&file, path, FS_O_READ);
597 if (err) {
598 shell_error(sh, "Failed to open %s (%d)", path, err);
599 return -ENOEXEC;
600 }
601
602 /* Read data in chunk by chunk until the full size has been read */
603 i = 0;
604 while (1) {
605 err = fs_read(&file, random_data, sizeof(random_data));
606 if (err < 0) {
607 shell_error(sh, "Failed to write %s (%d)",
608 path, err);
609 fs_close(&file);
610 return -ENOEXEC;
611 }
612
613 i += err;
614
615 if (err < sizeof(random_data)) {
616 /* Read finished */
617 break;
618 }
619 }
620
621 /* Ensure file contents is fully written then close file */
622 fs_close(&file);
623
624 if (i != size) {
625 shell_error(sh, "File read error, expected %d bytes but only read %d",
626 size, i);
627 return -EINVAL;
628 }
629
630 ++loops;
631 loop_time = k_uptime_delta(&start_time);
632 total_time += loop_time;
633 shell_print(sh, "Loop #%u done in %llums.", loops, loop_time);
634 }
635
636 speed_output(sh, total_time, (double)loops, (double)size);
637
638 return 0;
639 }
640
cmd_erase_write_test(const struct shell * sh,size_t argc,char ** argv)641 static int cmd_erase_write_test(const struct shell *sh, size_t argc, char **argv)
642 {
643 char path[MAX_PATH_LEN];
644 struct fs_file_t file;
645 int err;
646 uint32_t size;
647 uint32_t repeat;
648 uint8_t random_data[CONFIG_FILE_SYSTEM_SHELL_BUFFER_SIZE];
649 uint32_t i;
650 uint64_t start_time;
651 uint64_t loop_time;
652 uint64_t total_time = 0;
653 uint32_t loops = 0;
654
655 if (argc < 4) {
656 shell_error(sh, "Missing parameters: erase_write_test <path> <size> <repeat>");
657 return -EINVAL;
658 }
659
660 create_abs_path(argv[1], path, sizeof(path));
661 size = strtol(argv[2], NULL, 0);
662 repeat = strtol(argv[3], NULL, 0);
663
664 if (size == 0) {
665 shell_error(sh, "<size> must be at least 1.");
666 return -EINVAL;
667 }
668
669 if (repeat == 0 || repeat > 10) {
670 shell_error(sh, "<repeat> must be between 1 and 10.");
671 return -EINVAL;
672 }
673
674 /* Generate random data, the contents is not important */
675 i = 0;
676 while (i < sizeof(random_data)) {
677 random_data[i] = (uint8_t)(i % 255);
678 ++i;
679 }
680
681 while (loops < repeat) {
682 start_time = k_uptime_get();
683
684 fs_file_t_init(&file);
685 err = fs_open(&file, path, FS_O_CREATE | FS_O_WRITE);
686 if (err) {
687 shell_error(sh, "Failed to open %s (%d)", path, err);
688 return -ENOEXEC;
689 }
690
691 /* Truncate the file size to 0 (if supported, erase if not) */
692 err = fs_truncate(&file, 0);
693
694 if (err == -ENOTSUP) {
695 fs_close(&file);
696
697 err = fs_unlink(path);
698 if (err) {
699 shell_error(sh, "Failed to delete %s (%d)", path, err);
700 return -ENOEXEC;
701 }
702
703 err = fs_open(&file, path, FS_O_CREATE | FS_O_WRITE);
704 if (err) {
705 shell_error(sh, "Failed to open %s (%d)", path, err);
706 return -ENOEXEC;
707 }
708 } else if (err) {
709 shell_error(sh, "Failed to truncate %s (%d)", path, err);
710 fs_close(&file);
711 return -ENOEXEC;
712 }
713
714 /* Write data out chunk by chunk until the full size has been written */
715 i = 0;
716 while (i < size) {
717 uint32_t write_size = size - i;
718
719 if (write_size > sizeof(random_data)) {
720 write_size = sizeof(random_data);
721 }
722
723 err = fs_write(&file, random_data, write_size);
724 if (err < 0) {
725 shell_error(sh, "Failed to write %s (%d)",
726 path, err);
727 fs_close(&file);
728 return -ENOEXEC;
729 }
730
731 i += write_size;
732 }
733
734 /* Ensure file contents is fully written then close file */
735 fs_sync(&file);
736 fs_close(&file);
737
738 ++loops;
739 loop_time = k_uptime_delta(&start_time);
740 total_time += loop_time;
741 shell_print(sh, "Loop #%u done in %llums.", loops, loop_time);
742 }
743
744 speed_output(sh, total_time, (double)loops, (double)size);
745
746 return 0;
747 }
748 #endif
749
750 #ifdef CONFIG_FILE_SYSTEM_SHELL_MOUNT_COMMAND
751
mntpt_prepare(char * mntpt)752 static char *mntpt_prepare(char *mntpt)
753 {
754 char *cpy_mntpt;
755
756 cpy_mntpt = k_malloc(strlen(mntpt) + 1);
757 if (cpy_mntpt) {
758 strcpy(cpy_mntpt, mntpt);
759 }
760 return cpy_mntpt;
761 }
762
763 #if defined(CONFIG_FAT_FILESYSTEM_ELM)
cmd_mount_fat(const struct shell * sh,size_t argc,char ** argv)764 static int cmd_mount_fat(const struct shell *sh, size_t argc, char **argv)
765 {
766 char *mntpt;
767 int res;
768
769 mntpt = mntpt_prepare(argv[1]);
770 if (!mntpt) {
771 shell_error(sh,
772 "Failed to allocate buffer for mount point");
773 return -ENOEXEC;
774 }
775
776 fatfs_mnt.mnt_point = (const char *)mntpt;
777 res = fs_mount(&fatfs_mnt);
778 if (res != 0) {
779 shell_error(sh,
780 "Error mounting FAT fs. Error Code [%d]", res);
781 k_free((void *)fatfs_mnt.mnt_point);
782 fatfs_mnt.mnt_point = NULL;
783 return -ENOEXEC;
784 }
785
786 shell_print(sh, "Successfully mounted fat fs:%s",
787 fatfs_mnt.mnt_point);
788
789 return 0;
790 }
791 #endif
792
793 #if defined(CONFIG_FILE_SYSTEM_LITTLEFS)
cmd_mount_littlefs(const struct shell * sh,size_t argc,char ** argv)794 static int cmd_mount_littlefs(const struct shell *sh, size_t argc, char **argv)
795 {
796 if (littlefs_mnt.mnt_point != NULL) {
797 return -EBUSY;
798 }
799
800 char *mntpt = mntpt_prepare(argv[1]);
801
802 if (!mntpt) {
803 shell_error(sh, "Failed to allocate mount point");
804 return -ENOEXEC; /* ?!? */
805 }
806
807 littlefs_mnt.mnt_point = mntpt;
808
809 int rc = fs_mount(&littlefs_mnt);
810
811 if (rc != 0) {
812 shell_error(sh, "Error mounting as littlefs: %d", rc);
813 k_free((void *)littlefs_mnt.mnt_point);
814 littlefs_mnt.mnt_point = NULL;
815 return -ENOEXEC;
816 }
817
818 return rc;
819 }
820 #endif
821
822 SHELL_STATIC_SUBCMD_SET_CREATE(sub_fs_mount,
823 #if defined(CONFIG_FAT_FILESYSTEM_ELM)
824 SHELL_CMD_ARG(fat, NULL,
825 "Mount fatfs. fs mount fat <mount-point>",
826 cmd_mount_fat, 2, 0),
827 #endif
828
829 #if defined(CONFIG_FILE_SYSTEM_LITTLEFS)
830 SHELL_CMD_ARG(littlefs, NULL,
831 "Mount littlefs. fs mount littlefs <mount-point>",
832 cmd_mount_littlefs, 2, 0),
833 #endif
834
835 SHELL_SUBCMD_SET_END
836 );
837 #endif
838
839 SHELL_STATIC_SUBCMD_SET_CREATE(sub_fs,
840 SHELL_CMD(cd, NULL, "Change working directory", cmd_cd),
841 SHELL_CMD(ls, NULL, "List files in current directory", cmd_ls),
842 SHELL_CMD_ARG(mkdir, NULL, "Create directory", cmd_mkdir, 2, 0),
843 #ifdef CONFIG_FILE_SYSTEM_SHELL_MOUNT_COMMAND
844 SHELL_CMD(mount, &sub_fs_mount,
845 "<Mount fs, syntax:- fs mount <fs type> <mount-point>", NULL),
846 #endif
847 SHELL_CMD(pwd, NULL, "Print current working directory", cmd_pwd),
848 SHELL_CMD_ARG(read, NULL, "Read from file", cmd_read, 2, 255),
849 SHELL_CMD_ARG(cat, NULL,
850 "Concatenate files and print on the standard output",
851 cmd_cat, 2, 255),
852 SHELL_CMD_ARG(rm, NULL, "Remove file", cmd_rm, 2, 0),
853 SHELL_CMD_ARG(statvfs, NULL, "Show file system state", cmd_statvfs, 2, 0),
854 SHELL_CMD_ARG(trunc, NULL, "Truncate file", cmd_trunc, 2, 255),
855 SHELL_CMD_ARG(write, NULL, "Write file", cmd_write, 3, 255),
856 #ifdef CONFIG_FILE_SYSTEM_SHELL_TEST_COMMANDS
857 SHELL_CMD_ARG(read_test, NULL, "Read file test",
858 cmd_read_test, 2, 2),
859 SHELL_CMD_ARG(erase_write_test, NULL, "Erase/write file test",
860 cmd_erase_write_test, 3, 3),
861 #endif
862 SHELL_SUBCMD_SET_END
863 );
864
865 SHELL_CMD_REGISTER(fs, &sub_fs, "File system commands", NULL);
866