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 != 0) {
147 shell_error(sh, "%s doesn't exist", path);
148 return -ENOENT;
149 }
150
151 if (entry.type != FS_DIR_ENTRY_DIR) {
152 shell_error(sh, "%s is not a directory", path);
153 return -ENOTDIR;
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 != 0) {
179 shell_error(sh, "Unable to open %s (err %d)", path, err);
180 return -EIO;
181 }
182
183 while (1) {
184 struct fs_dirent entry;
185
186 err = fs_readdir(&dir, &entry);
187 if (err != 0) {
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, (entry.type == FS_DIR_ENTRY_DIR) ? "/" : "");
198 }
199
200 fs_closedir(&dir);
201
202 return 0;
203 }
204
cmd_pwd(const struct shell * sh,size_t argc,char ** argv)205 static int cmd_pwd(const struct shell *sh, size_t argc, char **argv)
206 {
207 shell_print(sh, "%s", cwd);
208
209 return 0;
210 }
211
cmd_trunc(const struct shell * sh,size_t argc,char ** argv)212 static int cmd_trunc(const struct shell *sh, size_t argc, char **argv)
213 {
214 char path[MAX_PATH_LEN];
215 struct fs_file_t file;
216 int length;
217 int err;
218
219 create_abs_path(argv[1], path, sizeof(path));
220
221 if (argc > 2) {
222 length = strtol(argv[2], NULL, 0);
223 } else {
224 length = 0;
225 }
226
227 fs_file_t_init(&file);
228 err = fs_open(&file, path, FS_O_WRITE);
229 if (err != 0) {
230 shell_error(sh, "Failed to open %s (%d)", path, err);
231 return -EIO;
232 }
233
234 err = fs_truncate(&file, length);
235 if (err != 0) {
236 shell_error(sh, "Failed to truncate %s (%d)", path, err);
237 err = -EIO;
238 }
239
240 fs_close(&file);
241
242 return err;
243 }
244
cmd_mkdir(const struct shell * sh,size_t argc,char ** argv)245 static int cmd_mkdir(const struct shell *sh, size_t argc, char **argv)
246 {
247 int err;
248 char path[MAX_PATH_LEN];
249
250 create_abs_path(argv[1], path, sizeof(path));
251
252 err = fs_mkdir(path);
253 if (err != 0) {
254 shell_error(sh, "Error creating dir[%d]", err);
255 err = -EIO;
256 }
257
258 return err;
259 }
260
cmd_rm(const struct shell * sh,size_t argc,char ** argv)261 static int cmd_rm(const struct shell *sh, size_t argc, char **argv)
262 {
263 int err;
264 char path[MAX_PATH_LEN];
265
266 create_abs_path(argv[1], path, sizeof(path));
267
268 err = fs_unlink(path);
269 if (err != 0) {
270 shell_error(sh, "Failed to remove %s (%d)", path, err);
271 err = -EIO;
272 }
273
274 return err;
275 }
276
cmd_cp(const struct shell * sh,size_t argc,char ** argv)277 static int cmd_cp(const struct shell *sh, size_t argc, char **argv)
278 {
279 int err;
280 int close_err;
281 char path_src[MAX_PATH_LEN];
282 char path_dst[MAX_PATH_LEN];
283 struct fs_file_t file_src;
284 struct fs_file_t file_dst;
285 uint8_t buf[BUF_CNT];
286 ssize_t buf_len;
287 ssize_t num_written;
288
289 create_abs_path(argv[1], path_src, sizeof(path_src));
290 create_abs_path(argv[2], path_dst, sizeof(path_dst));
291
292 fs_file_t_init(&file_src);
293 fs_file_t_init(&file_dst);
294
295 err = fs_open(&file_src, path_src, FS_O_READ);
296 if (err != 0) {
297 shell_error(sh, "Failed to open %s (%d)", path_src, err);
298 err = -EIO;
299 goto exit;
300 }
301
302 err = fs_open(&file_dst, path_dst, FS_O_CREATE | FS_O_TRUNC | FS_O_WRITE);
303 if (err != 0) {
304 shell_error(sh, "Failed to open %s (%d)", path_dst, err);
305 err = -EIO;
306 goto close_src;
307 }
308
309 while (true) {
310 buf_len = fs_read(&file_src, buf, BUF_CNT);
311 if (buf_len < 0) {
312 shell_error(sh, "Failed to read %s (%d)", path_src, (int)buf_len);
313 err = -EIO;
314 goto close;
315 }
316 if (buf_len == 0) {
317 break;
318 }
319
320 num_written = fs_write(&file_dst, buf, buf_len);
321 if (num_written < 0) {
322 shell_error(sh, "Failed to write %s (%d)", path_dst, (int)num_written);
323 err = -EIO;
324 goto close;
325 }
326 if (num_written != buf_len) {
327 shell_error(sh, "Failed to write %s", path_dst);
328 err = -EIO;
329 goto close;
330 }
331 }
332
333 close:
334 close_err = fs_close(&file_dst);
335 if (close_err != 0) {
336 shell_error(sh, "Failed to close %s", path_dst);
337 err = -EIO;
338 }
339
340 close_src:
341 close_err = fs_close(&file_src);
342 if (close_err != 0) {
343 shell_error(sh, "Failed to close %s", path_src);
344 err = -EIO;
345 }
346
347 exit:
348 return err;
349 }
350
cmd_read(const struct shell * sh,size_t argc,char ** argv)351 static int cmd_read(const struct shell *sh, size_t argc, char **argv)
352 {
353 char path[MAX_PATH_LEN];
354 struct fs_dirent dirent;
355 struct fs_file_t file;
356 int count;
357 off_t offset;
358 int err;
359
360 create_abs_path(argv[1], path, sizeof(path));
361
362 if (argc > 2) {
363 count = strtol(argv[2], NULL, 0);
364 if (count <= 0) {
365 count = INT_MAX;
366 }
367 } else {
368 count = INT_MAX;
369 }
370
371 if (argc > 3) {
372 offset = strtol(argv[3], NULL, 0);
373 } else {
374 offset = 0;
375 }
376
377 err = fs_stat(path, &dirent);
378 if (err != 0) {
379 shell_error(sh, "Failed to obtain file %s (err: %d)", path, err);
380 return -EIO;
381 }
382
383 if (dirent.type != FS_DIR_ENTRY_FILE) {
384 shell_error(sh, "Not a file %s", path);
385 return -EIO;
386 }
387
388 shell_print(sh, "File size: %zd", dirent.size);
389
390 fs_file_t_init(&file);
391 err = fs_open(&file, path, FS_O_READ);
392 if (err != 0) {
393 shell_error(sh, "Failed to open %s (%d)", path, err);
394 return -EIO;
395 }
396
397 if (offset > 0) {
398 err = fs_seek(&file, offset, FS_SEEK_SET);
399 if (err != 0) {
400 shell_error(sh, "Failed to seek %s (%d)", path, err);
401 fs_close(&file);
402 return -EIO;
403 }
404 }
405
406 ssize_t read;
407 while (count > 0) {
408 uint8_t buf[16];
409 int i;
410
411 read = fs_read(&file, buf, MIN(count, sizeof(buf)));
412 if (read <= 0) {
413 break;
414 }
415
416 shell_fprintf(sh, SHELL_NORMAL, "%08X ", (uint32_t)offset);
417
418 for (i = 0; i < read; i++) {
419 shell_fprintf(sh, SHELL_NORMAL, "%02X ", buf[i]);
420 }
421 for (; i < sizeof(buf); i++) {
422 shell_fprintf(sh, SHELL_NORMAL, " ");
423 }
424 i = sizeof(buf) - i;
425 shell_fprintf(sh, SHELL_NORMAL, "%*c", i * 3, ' ');
426
427 for (i = 0; i < read; i++) {
428 shell_fprintf(sh, SHELL_NORMAL, "%c",
429 buf[i] < 32 || buf[i] > 127 ? '.' : buf[i]);
430 }
431
432 shell_print(sh, "");
433
434 offset += read;
435 count -= read;
436 }
437
438 if (read < 0) {
439 shell_error(sh, "Failed to read from file %s (err: %zd)", path, read);
440 }
441
442 fs_close(&file);
443
444 return 0;
445 }
446
cmd_cat(const struct shell * sh,size_t argc,char ** argv)447 static int cmd_cat(const struct shell *sh, size_t argc, char **argv)
448 {
449 char path[MAX_PATH_LEN];
450 uint8_t buf[BUF_CNT];
451 struct fs_dirent dirent;
452 struct fs_file_t file;
453 int err;
454 ssize_t read;
455
456 fs_file_t_init(&file);
457
458 for (size_t i = 1; i < argc; ++i) {
459 create_abs_path(argv[i], path, sizeof(path));
460
461 err = fs_stat(path, &dirent);
462 if (err < 0) {
463 shell_error(sh, "Failed to obtain file %s (err: %d)", path, err);
464 continue;
465 }
466
467 if (dirent.type != FS_DIR_ENTRY_FILE) {
468 shell_error(sh, "Not a file %s", path);
469 continue;
470 }
471
472 err = fs_open(&file, path, FS_O_READ);
473 if (err < 0) {
474 shell_error(sh, "Failed to open %s (%d)", path, err);
475 continue;
476 }
477
478 while (true) {
479 read = fs_read(&file, buf, sizeof(buf));
480 if (read <= 0) {
481 break;
482 }
483
484 for (int j = 0; j < read; j++) {
485 shell_fprintf(sh, SHELL_NORMAL, "%c", buf[j]);
486 }
487 }
488
489 if (read < 0) {
490 shell_error(sh, "Failed to read from file %s (err: %zd)", path, read);
491 }
492
493 fs_close(&file);
494 }
495
496 return 0;
497 }
498
cmd_statvfs(const struct shell * sh,size_t argc,char ** argv)499 static int cmd_statvfs(const struct shell *sh, size_t argc, char **argv)
500 {
501 int err;
502 char path[MAX_PATH_LEN];
503 struct fs_statvfs stat;
504
505 create_abs_path(argv[1], path, sizeof(path));
506
507 err = fs_statvfs(path, &stat);
508 if (err < 0) {
509 shell_error(sh, "Failed to statvfs %s (%d)", path, err);
510 return -EIO;
511 }
512
513 shell_fprintf(sh, SHELL_NORMAL, "bsize %lu, frsize %lu, blocks %lu, bfree %lu\n",
514 stat.f_bsize, stat.f_frsize, stat.f_blocks, stat.f_bfree);
515
516 return 0;
517 }
518
cmd_write(const struct shell * sh,size_t argc,char ** argv)519 static int cmd_write(const struct shell *sh, size_t argc, char **argv)
520 {
521 char path[MAX_PATH_LEN];
522 uint8_t buf[BUF_CNT];
523 uint8_t buf_len;
524 int arg_offset;
525 struct fs_file_t file;
526 off_t offset = -1;
527 int err;
528
529 create_abs_path(argv[1], path, sizeof(path));
530
531 if (!strcmp(argv[2], "-o")) {
532 if (argc < 4) {
533 shell_error(sh, "Missing argument");
534 return -EINVAL;
535 }
536
537 offset = strtol(argv[3], NULL, 0);
538
539 arg_offset = 4;
540 } else {
541 arg_offset = 2;
542 }
543
544 fs_file_t_init(&file);
545 err = fs_open(&file, path, FS_O_CREATE | FS_O_WRITE);
546 if (err != 0) {
547 shell_error(sh, "Failed to open %s (%d)", path, err);
548 return -EIO;
549 }
550
551 if (offset < 0) {
552 err = fs_seek(&file, 0, FS_SEEK_END);
553 } else {
554 err = fs_seek(&file, offset, FS_SEEK_SET);
555 }
556 if (err != 0) {
557 shell_error(sh, "Failed to seek %s (%d)", path, err);
558 fs_close(&file);
559 return -EIO;
560 }
561
562 buf_len = 0U;
563 while (arg_offset < argc) {
564 buf[buf_len++] = strtol(argv[arg_offset++], NULL, 16);
565
566 if ((buf_len == BUF_CNT) || (arg_offset == argc)) {
567 err = fs_write(&file, buf, buf_len);
568 if (err < 0) {
569 shell_error(sh, "Failed to write %s (%d)", path, err);
570 fs_close(&file);
571 return -EIO;
572 }
573
574 buf_len = 0U;
575 }
576 }
577
578 fs_close(&file);
579
580 return 0;
581 }
582
583 #ifdef CONFIG_FILE_SYSTEM_SHELL_TEST_COMMANDS
584 const static uint8_t speed_types[][4] = {"B", "KiB", "MiB", "GiB"};
585 const static uint32_t speed_divisor = 1024;
586
file_size_output(const struct shell * sh,double size)587 static void file_size_output(const struct shell *sh, double size)
588 {
589 uint8_t speed_index = 0;
590
591 while (size >= (double)speed_divisor && speed_index < ARRAY_SIZE(speed_types)) {
592 size /= (double)speed_divisor;
593 ++speed_index;
594 }
595
596 shell_print(sh, "File size: %.1f%s", size, speed_types[speed_index]);
597 }
598
speed_output(const struct shell * sh,uint64_t total_time,double loops,double size)599 static void speed_output(const struct shell *sh, uint64_t total_time, double loops, double size)
600 {
601 double time_per_loop = (double)total_time / loops;
602 double throughput = size;
603 uint8_t speed_index = 0;
604
605 if (time_per_loop > 0) {
606 throughput /= (time_per_loop / 1000.0);
607 }
608
609 while (throughput >= (double)speed_divisor && speed_index < ARRAY_SIZE(speed_types)) {
610 throughput /= (double)speed_divisor;
611 ++speed_index;
612 }
613
614 shell_print(sh, "Total: %llums, Per loop: ~%.0fms, Speed: ~%.1f%sps", total_time,
615 time_per_loop, throughput, speed_types[speed_index]);
616 }
617
cmd_read_test(const struct shell * sh,size_t argc,char ** argv)618 static int cmd_read_test(const struct shell *sh, size_t argc, char **argv)
619 {
620 char path[MAX_PATH_LEN];
621 struct fs_dirent dirent;
622 struct fs_file_t file;
623 int err;
624 uint32_t repeat;
625 uint8_t random_data[CONFIG_FILE_SYSTEM_SHELL_BUFFER_SIZE];
626 uint32_t i;
627 uint64_t start_time;
628 uint64_t loop_time;
629 uint64_t total_time = 0;
630 uint32_t loops = 0;
631 uint32_t size;
632
633 if (argc < 3) {
634 shell_error(sh, "Missing parameters: read_test <path> <repeat>");
635 return -EINVAL;
636 }
637
638 create_abs_path(argv[1], path, sizeof(path));
639 repeat = strtol(argv[2], NULL, 0);
640
641 if (repeat == 0 || repeat > 10) {
642 shell_error(sh, "<repeat> must be between 1 and 10.");
643 return -EINVAL;
644 }
645
646 err = fs_stat(path, &dirent);
647
648 if (err != 0) {
649 shell_error(sh, "File status failed: %d", err);
650 return err;
651 }
652
653 if (dirent.type != FS_DIR_ENTRY_FILE) {
654 shell_error(sh, "Provided path is not a file");
655 return -ENOENT;
656 }
657
658 /* Store size of file so we can ensure it was fully read */
659 size = dirent.size;
660 file_size_output(sh, (double)size);
661
662 while (loops < repeat) {
663 start_time = k_uptime_get();
664
665 fs_file_t_init(&file);
666 err = fs_open(&file, path, FS_O_READ);
667 if (err != 0) {
668 shell_error(sh, "Failed to open %s (%d)", path, err);
669 return -EIO;
670 }
671
672 /* Read data in chunk by chunk until the full size has been read */
673 i = 0;
674 while (1) {
675 err = fs_read(&file, random_data, sizeof(random_data));
676 if (err < 0) {
677 shell_error(sh, "Failed to read %s (%d)", path, err);
678 fs_close(&file);
679 return -EIO;
680 }
681
682 i += err;
683
684 if (err == 0) {
685 /* Read finished */
686 break;
687 }
688 }
689
690 /* Ensure file contents is fully read then close file */
691 fs_close(&file);
692
693 if (i != size) {
694 shell_error(sh, "File read error, expected %d bytes but only read %d", size,
695 i);
696 return -EIO;
697 }
698
699 ++loops;
700 loop_time = k_uptime_delta(&start_time);
701 total_time += loop_time;
702 shell_print(sh, "Loop #%u done in %llums.", loops, loop_time);
703 }
704
705 speed_output(sh, total_time, (double)loops, (double)size);
706
707 return 0;
708 }
709
cmd_erase_write_test(const struct shell * sh,size_t argc,char ** argv)710 static int cmd_erase_write_test(const struct shell *sh, size_t argc, char **argv)
711 {
712 char path[MAX_PATH_LEN];
713 struct fs_file_t file;
714 int err;
715 uint32_t size;
716 uint32_t repeat;
717 uint8_t random_data[CONFIG_FILE_SYSTEM_SHELL_BUFFER_SIZE];
718 uint32_t i;
719 uint64_t start_time;
720 uint64_t loop_time;
721 uint64_t total_time = 0;
722 uint32_t loops = 0;
723
724 if (argc < 4) {
725 shell_error(sh, "Missing parameters: erase_write_test <path> <size> <repeat>");
726 return -EINVAL;
727 }
728
729 create_abs_path(argv[1], path, sizeof(path));
730 size = strtol(argv[2], NULL, 0);
731 repeat = strtol(argv[3], NULL, 0);
732
733 if (size == 0) {
734 shell_error(sh, "<size> must be at least 1.");
735 return -EINVAL;
736 }
737
738 if (repeat == 0 || repeat > 10) {
739 shell_error(sh, "<repeat> must be between 1 and 10.");
740 return -EINVAL;
741 }
742
743 /* Generate random data, the contents is not important */
744 i = 0;
745 while (i < sizeof(random_data)) {
746 random_data[i] = (uint8_t)(i % 255);
747 ++i;
748 }
749
750 while (loops < repeat) {
751 start_time = k_uptime_get();
752
753 fs_file_t_init(&file);
754 err = fs_open(&file, path, FS_O_CREATE | FS_O_WRITE);
755 if (err != 0) {
756 shell_error(sh, "Failed to open %s (%d)", path, err);
757 return -EIO;
758 }
759
760 /* Truncate the file size to 0 (if supported, erase if not) */
761 err = fs_truncate(&file, 0);
762
763 if (err == -ENOTSUP) {
764 fs_close(&file);
765
766 err = fs_unlink(path);
767 if (err != 0) {
768 shell_error(sh, "Failed to delete %s (%d)", path, err);
769 return -EIO;
770 }
771
772 err = fs_open(&file, path, FS_O_CREATE | FS_O_WRITE);
773 if (err != 0) {
774 shell_error(sh, "Failed to open %s (%d)", path, err);
775 return -EIO;
776 }
777 } else if (err != 0) {
778 shell_error(sh, "Failed to truncate %s (%d)", path, err);
779 fs_close(&file);
780 return -EIO;
781 }
782
783 /* Write data out chunk by chunk until the full size has been written */
784 i = 0;
785 while (i < size) {
786 uint32_t write_size = size - i;
787
788 if (write_size > sizeof(random_data)) {
789 write_size = sizeof(random_data);
790 }
791
792 err = fs_write(&file, random_data, write_size);
793 if (err < 0) {
794 shell_error(sh, "Failed to write %s (%d)", path, err);
795 fs_close(&file);
796 return -EIO;
797 }
798
799 i += write_size;
800 }
801
802 /* Ensure file contents is fully written then close file */
803 fs_sync(&file);
804 fs_close(&file);
805
806 ++loops;
807 loop_time = k_uptime_delta(&start_time);
808 total_time += loop_time;
809 shell_print(sh, "Loop #%u done in %llums.", loops, loop_time);
810 }
811
812 speed_output(sh, total_time, (double)loops, (double)size);
813
814 return 0;
815 }
816 #endif
817
818 #ifdef CONFIG_FILE_SYSTEM_SHELL_MOUNT_COMMAND
819
mntpt_prepare(char * mntpt)820 static char *mntpt_prepare(char *mntpt)
821 {
822 char *cpy_mntpt;
823
824 cpy_mntpt = k_malloc(strlen(mntpt) + 1);
825 if (cpy_mntpt != NULL) {
826 strcpy(cpy_mntpt, mntpt);
827 }
828 return cpy_mntpt;
829 }
830
831 #if defined(CONFIG_FAT_FILESYSTEM_ELM)
cmd_mount_fat(const struct shell * sh,size_t argc,char ** argv)832 static int cmd_mount_fat(const struct shell *sh, size_t argc, char **argv)
833 {
834 char *mntpt;
835 int res;
836
837 mntpt = mntpt_prepare(argv[1]);
838 if (mntpt == NULL) {
839 shell_error(sh, "Failed to allocate buffer for mount point");
840 return -EIO;
841 }
842
843 fatfs_mnt.mnt_point = (const char *)mntpt;
844 res = fs_mount(&fatfs_mnt);
845 if (res != 0) {
846 shell_error(sh, "Error mounting FAT fs. Error Code [%d]", res);
847 k_free((void *)fatfs_mnt.mnt_point);
848 fatfs_mnt.mnt_point = NULL;
849 return -EIO;
850 }
851
852 shell_print(sh, "Successfully mounted fat fs:%s", fatfs_mnt.mnt_point);
853
854 return 0;
855 }
856 #endif
857
858 #if defined(CONFIG_FILE_SYSTEM_LITTLEFS)
cmd_mount_littlefs(const struct shell * sh,size_t argc,char ** argv)859 static int cmd_mount_littlefs(const struct shell *sh, size_t argc, char **argv)
860 {
861 if (littlefs_mnt.mnt_point != NULL) {
862 return -EBUSY;
863 }
864
865 char *mntpt = mntpt_prepare(argv[1]);
866
867 if (mntpt == NULL) {
868 shell_error(sh, "Failed to allocate mount point");
869 return -EIO;
870 }
871
872 littlefs_mnt.mnt_point = mntpt;
873
874 int rc = fs_mount(&littlefs_mnt);
875
876 if (rc != 0) {
877 shell_error(sh, "Error mounting as littlefs: %d", rc);
878 k_free((void *)littlefs_mnt.mnt_point);
879 littlefs_mnt.mnt_point = NULL;
880 return -EIO;
881 }
882
883 return rc;
884 }
885 #endif
886
887 SHELL_STATIC_SUBCMD_SET_CREATE(sub_fs_mount,
888 #if defined(CONFIG_FAT_FILESYSTEM_ELM)
889 SHELL_CMD_ARG(fat, NULL,
890 "Mount fatfs. fs mount fat <mount-point>",
891 cmd_mount_fat, 2, 0),
892 #endif
893
894 #if defined(CONFIG_FILE_SYSTEM_LITTLEFS)
895 SHELL_CMD_ARG(littlefs, NULL,
896 "Mount littlefs. fs mount littlefs <mount-point>",
897 cmd_mount_littlefs, 2, 0),
898 #endif
899
900 SHELL_SUBCMD_SET_END
901 );
902 #endif
903
904 SHELL_STATIC_SUBCMD_SET_CREATE(sub_fs,
905 SHELL_CMD(cd, NULL, "Change working directory", cmd_cd),
906 SHELL_CMD(ls, NULL, "List files in current directory", cmd_ls),
907 SHELL_CMD_ARG(mkdir, NULL, "Create directory", cmd_mkdir, 2, 0),
908 #ifdef CONFIG_FILE_SYSTEM_SHELL_MOUNT_COMMAND
909 SHELL_CMD(mount, &sub_fs_mount,
910 "<Mount fs, syntax:- fs mount <fs type> <mount-point>", NULL),
911 #endif
912 SHELL_CMD(pwd, NULL, "Print current working directory", cmd_pwd),
913 SHELL_CMD_ARG(read, NULL, "Read from file", cmd_read, 2, 255),
914 SHELL_CMD_ARG(cat, NULL,
915 "Concatenate files and print on the standard output",
916 cmd_cat, 2, 255),
917 SHELL_CMD_ARG(rm, NULL, "Remove file", cmd_rm, 2, 0),
918 SHELL_CMD_ARG(cp, NULL, "Copy file", cmd_cp, 3, 0),
919 SHELL_CMD_ARG(statvfs, NULL, "Show file system state", cmd_statvfs, 2, 0),
920 SHELL_CMD_ARG(trunc, NULL, "Truncate file", cmd_trunc, 2, 255),
921 SHELL_CMD_ARG(write, NULL, "Write file", cmd_write, 3, 255),
922 #ifdef CONFIG_FILE_SYSTEM_SHELL_TEST_COMMANDS
923 SHELL_CMD_ARG(read_test, NULL, "Read file test", cmd_read_test, 2, 2),
924 SHELL_CMD_ARG(erase_write_test, NULL, "Erase/write file test", cmd_erase_write_test, 3, 3),
925 #endif
926 SHELL_SUBCMD_SET_END
927 );
928
929 SHELL_CMD_REGISTER(fs, &sub_fs, "File system commands", NULL);
930