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