1 /*
2  * Copyright (c) 2015 Travis Geiselbrecht
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 
9 #include <lk/err.h>
10 #include <lk/debug.h>
11 #include <string.h>
12 #include <stdio.h>
13 #include <lk/trace.h>
14 #include <stdlib.h>
15 #include <platform.h>
16 #include <lk/console_cmd.h>
17 #include <lib/fs.h>
18 
19 /* shell console hooks for manipulating the file system */
20 
21 static char *cwd = NULL;
22 
set_cwd(const char * path)23 static void set_cwd(const char *path) {
24     if (!path) {
25         free(cwd);
26         cwd = NULL;
27         return;
28     }
29 
30     size_t len = strlen(path) + 1;
31     char *new_cwd = realloc(cwd, len);
32     if (new_cwd) {
33         cwd = new_cwd;
34         memcpy(cwd, path, len);
35     }
36 }
37 
get_cwd(void)38 static const char *get_cwd(void) {
39     if (!cwd)
40         return "/";
41     return cwd;
42 }
43 
prepend_cwd(char * path,size_t len,const char * arg)44 static char *prepend_cwd(char *path, size_t len, const char *arg) {
45     path[0] = '\0';
46 
47     if (!arg || arg[0] != '/') {
48         strlcat(path, get_cwd(), len);
49         if (arg && path[strlen(path) - 1] != '/')
50             strlcat(path, "/", len);
51     }
52     if (arg) {
53         strlcat(path, arg, len);
54     }
55 
56     return path;
57 }
58 
cmd_ls(int argc,const console_cmd_args * argv)59 static int cmd_ls(int argc, const console_cmd_args *argv) {
60     status_t status = NO_ERROR;
61 
62     // construct the path
63     char *path = malloc(FS_MAX_PATH_LEN);
64     prepend_cwd(path, FS_MAX_PATH_LEN, (argc >= 2) ? argv[1].str : NULL);
65 
66     dirhandle *dhandle;
67     status = fs_open_dir(path, &dhandle);
68     if (status < 0) {
69         printf("error %d opening dir '%s'\n", status, path);
70         goto err;
71     }
72 
73     size_t pathlen = strlen(path);
74 
75     status_t err;
76     struct dirent ent;
77     while ((err = fs_read_dir(dhandle, &ent)) >= 0) {
78         struct file_stat stat;
79         filehandle *handle;
80 
81         // append our filename to the path
82         strlcat(path, "/", FS_MAX_PATH_LEN);
83         strlcat(path, ent.name, FS_MAX_PATH_LEN);
84 
85         err = fs_open_file(path, &handle);
86 
87         // restore the old path
88         path[pathlen] = '\0';
89 
90         if (err < 0) {
91             printf("error %d opening file '%s'\n", err, path);
92             continue;
93         }
94 
95         // stat the file
96         err = fs_stat_file(handle, &stat);
97         fs_close_file(handle);
98         if (err < 0) {
99             printf("error %d statting file\n", err);
100             continue;
101         }
102 
103         printf("%c %16llu %s\n", stat.is_dir ? 'd' : ' ', stat.size, ent.name);
104     }
105 
106     fs_close_dir(dhandle);
107 
108 err:
109     free(path);
110     return status;;
111 }
112 
cmd_cd(int argc,const console_cmd_args * argv)113 static int cmd_cd(int argc, const console_cmd_args *argv) {
114     if (argc < 2) {
115         set_cwd(NULL);
116     } else {
117         char *path = malloc(FS_MAX_PATH_LEN);
118         prepend_cwd(path, FS_MAX_PATH_LEN, (argc >= 2) ? argv[1].str : NULL);
119         fs_normalize_path(path);
120 
121         if (strlen(path) == 0) {
122             set_cwd(NULL);
123         } else {
124             set_cwd(path);
125         }
126         free(path);
127     }
128     puts(get_cwd());
129 
130     return 0;
131 }
132 
cmd_pwd(int argc,const console_cmd_args * argv)133 static int cmd_pwd(int argc, const console_cmd_args *argv) {
134     puts(get_cwd());
135 
136     return 0;
137 }
138 
cmd_mkdir(int argc,const console_cmd_args * argv)139 static int cmd_mkdir(int argc, const console_cmd_args *argv) {
140     if (argc < 2) {
141         printf("not enough arguments\n");
142         printf("usage: %s <path>\n", argv[0].str);
143         return -1;
144     }
145 
146     char *path = malloc(FS_MAX_PATH_LEN);
147 
148     int status = fs_make_dir(prepend_cwd(path, FS_MAX_PATH_LEN, argv[1].str));
149     if (status < 0) {
150         printf("error %d making directory '%s'\n", status, path);
151     }
152 
153     free(path);
154     return status;
155 }
156 
cmd_mkfile(int argc,const console_cmd_args * argv)157 static int cmd_mkfile(int argc, const console_cmd_args *argv) {
158     if (argc < 2) {
159         printf("not enough arguments\n");
160         printf("usage: %s <path> [length]\n", argv[0].str);
161         return -1;
162     }
163 
164     char *path = malloc(FS_MAX_PATH_LEN);
165     prepend_cwd(path, FS_MAX_PATH_LEN, argv[1].str);
166 
167     filehandle *handle;
168     status_t status = fs_create_file(path, &handle, (argc >= 2) ? argv[2].u : 0);
169     if (status < 0) {
170         printf("error %d making file '%s'\n", status, path);
171         goto err;
172     }
173 
174     fs_close_file(handle);
175 
176 err:
177     free(path);
178     return status;
179 }
180 
cmd_rm(int argc,const console_cmd_args * argv)181 static int cmd_rm(int argc, const console_cmd_args *argv) {
182     if (argc < 2) {
183         printf("not enough arguments\n");
184         printf("usage: %s <path>\n", argv[0].str);
185         return -1;
186     }
187 
188     char *path = malloc(FS_MAX_PATH_LEN);
189     prepend_cwd(path, FS_MAX_PATH_LEN, argv[1].str);
190 
191     status_t err = fs_remove_file(path);
192     if (err < 0) {
193         printf("error %d removing file '%s'\n", err, path);
194         return err;
195     }
196 
197     return 0;
198 }
199 
cmd_stat(int argc,const console_cmd_args * argv)200 static int cmd_stat(int argc, const console_cmd_args *argv) {
201     if (argc < 2) {
202         printf("not enough arguments\n");
203         printf("usage: %s <path>\n", argv[0].str);
204         return -1;
205     }
206 
207     int status;
208     struct file_stat stat;
209     filehandle *handle;
210 
211     char *path = malloc(FS_MAX_PATH_LEN);
212     prepend_cwd(path, FS_MAX_PATH_LEN, argv[1].str);
213 
214     status = fs_open_file(path, &handle);
215     if (status < 0) {
216         printf("error %d opening file '%s'\n", status, path);
217         goto err;
218     }
219 
220     status = fs_stat_file(handle, &stat);
221 
222     fs_close_file(handle);
223 
224     if (status < 0) {
225         printf("error %d statting file\n", status);
226         goto err;
227     }
228 
229     printf("stat successful:\n");
230     printf("\tis_dir: %d\n", stat.is_dir ? 1 : 0);
231     printf("\tsize: %lld\n", stat.size);
232 
233 
234 err:
235     free(path);
236     return status;
237 }
238 
cmd_cat(int argc,const console_cmd_args * argv)239 static int cmd_cat(int argc, const console_cmd_args *argv) {
240     status_t status = NO_ERROR;
241 
242     if (argc < 2) {
243         printf("not enough arguments\n");
244         printf("usage: %s <path>\n", argv[0].str);
245         return -1;
246     }
247 
248     char *path = malloc(FS_MAX_PATH_LEN);
249     prepend_cwd(path, FS_MAX_PATH_LEN, argv[1].str);
250 
251     filehandle *handle;
252     status = fs_open_file(path, &handle);
253     if (status < 0) {
254         printf("error %d opening file '%s'\n", status, path);
255         goto err;
256     }
257 
258     char buf[64];
259     ssize_t read_len;
260     off_t offset = 0;
261     while ((read_len = fs_read_file(handle, buf, offset, sizeof(buf))) > 0) {
262         for (int i = 0; i < read_len; i++) {
263             putchar(buf[i]);
264         }
265 
266         offset += read_len;
267     }
268 
269     fs_close_file(handle);
270 
271 err:
272     free(path);
273     return status;
274 }
275 
276 STATIC_COMMAND_START
277 STATIC_COMMAND("ls", "dir listing", &cmd_ls)
278 STATIC_COMMAND("cd", "change dir", &cmd_cd)
279 STATIC_COMMAND("pwd", "print working dir", &cmd_pwd)
280 STATIC_COMMAND("mkdir", "make dir", &cmd_mkdir)
281 STATIC_COMMAND("mkfile", "make file", &cmd_mkfile)
282 STATIC_COMMAND("rm", "remove file", &cmd_rm)
283 STATIC_COMMAND("stat", "stat file", &cmd_stat)
284 STATIC_COMMAND("cat", "cat file", &cmd_cat)
285 STATIC_COMMAND_END(fs_shell);
286