1 /* radare2 - LGPL - Copyright 2018-2020 - pancake */
2 
3 #include <r_fs.h>
4 
5 #define PROMPT_PATH_BUFSIZE 1024
6 
handlePipes(RFS * fs,char * msg,const ut8 * data,const char * cwd)7 static bool handlePipes(RFS *fs, char *msg, const ut8 *data, const char *cwd) {
8 	char *red = strchr (msg, '>');
9 	if (!red) {
10 		return false;
11 	}
12 	*red++ = 0;
13 	r_str_trim (msg);
14 	red = r_str_trim_dup (red);
15 	if (*red != '/') {
16 		char *blu = r_str_newf ("%s/%s", cwd, red);
17 		free (red);
18 		red = blu;
19 	}
20 	RFSFile *f = r_fs_open (fs, red, true);
21 	if (!f) {
22 		eprintf ("Cannot open %s for writing\n", red);
23 		free (red);
24 		return true;
25 	}
26 	r_fs_write (fs, f, 0, data ? data : (ut8*)msg, strlen (data ? (char*)data : msg));
27 	free (red);
28 	r_fs_close (fs, f);
29 	r_fs_file_free (f);
30 	return true;
31 }
32 
r_fs_shell_prompt(RFSShell * shell,RFS * fs,const char * root)33 R_API int r_fs_shell_prompt(RFSShell* shell, RFS* fs, const char* root) {
34 	char buf[PROMPT_PATH_BUFSIZE];
35 	char path[PROMPT_PATH_BUFSIZE];
36 	char prompt[PROMPT_PATH_BUFSIZE];
37 	char str[2048];
38 	char* input;
39 	const char* ptr;
40 	RList* list = NULL;
41 	RListIter* iter;
42 	RFSFile* file = NULL;
43 
44 	if (root && *root) {
45 		strncpy (buf, root, sizeof (buf) - 1);
46 		r_str_trim_path (buf);
47 		list = r_fs_root (fs, buf);
48 		if (r_list_empty (list)) {
49 			printf ("Unknown root\n");
50 			r_list_free (list);
51 			return false;
52 		}
53 		r_str_ncpy (path, buf, sizeof (path) - 1);
54 	} else {
55 		strcpy (path, "/");
56 	}
57 
58 	PrintfCallback cb_printf = fs->csb.cb_printf;
59 	for (;;) {
60 		snprintf (prompt, sizeof (prompt), "[%.*s]> ", (int)sizeof (prompt) - 5, path);
61 		if (shell) {
62 			*shell->cwd = strdup (path);
63 			if (shell->set_prompt) {
64 				shell->set_prompt (prompt);
65 			}
66 			if (shell->readline) {
67 				ptr = shell->readline ();
68 			} else {
69 				if (!fgets (buf, sizeof (buf), stdin)) {
70 					break;
71 				}
72 				if (feof (stdin)) {
73 					break;
74 				}
75 				r_str_trim_tail (buf);
76 				ptr = buf;
77 			}
78 			if (!ptr) {
79 				break;
80 			}
81 			r_str_trim ((char *)ptr); // XXX abadidea
82 			if (shell->hist_add) {
83 				shell->hist_add (ptr);
84 			}
85 			if (ptr != buf) {
86 				r_str_ncpy (buf, ptr, sizeof (buf) - 1);
87 			}
88 		} else {
89 			printf ("%s", prompt);
90 			if (!fgets (buf, sizeof (buf), stdin)) {
91 				break;
92 			}
93 			if (feof (stdin)) {
94 				break;
95 			}
96 			r_str_trim_tail (buf);
97 		}
98 		char *wave = strchr (buf, '~');
99 		if (wave) {
100 			*wave++ = 0;
101 		}
102 
103 		if (!strcmp (buf, "q") || !strcmp (buf, "exit")) {
104 			r_list_free (list);
105 			return true;
106 		}
107 		if (buf[0] == '#') {
108 			// comment
109 			continue;
110 		} else if (buf[0] == ':') {
111 			char *msg = fs->cob.cmdstr (fs->cob.core, buf + 1);
112 			printf ("%s\n", msg);
113 			free (msg);
114 		} else if (buf[0] == '!') {
115 			r_sandbox_system (buf + 1, 1);
116 		} else if (!strncmp (buf, "echo", 4)) {
117 			char *msg = r_str_trim_dup (buf + 4);
118 			if (!handlePipes (fs, msg, NULL, path)) {
119 				cb_printf ("%s\n", msg);
120 			}
121 			free (msg);
122 		} else if (!strncmp (buf, "ls", 2)) {
123 			char *ptr = str;
124 			r_list_free (list);
125 			if (buf[2] == ' ') {
126 				if (buf[3] != '/') {
127 					snprintf (str, sizeof (str), "%s/%s", path, buf + 3);
128 					list = r_fs_dir (fs, str);
129 				} else {
130 					list = r_fs_dir (fs, buf + 3);
131 					ptr = buf + 3;
132 				}
133 			} else {
134 				ptr = path;
135 				list = r_fs_dir (fs, path);
136 			}
137 			if (list) {
138 				r_list_foreach (list, iter, file) {
139 					cb_printf ("%c %s\n", file->type, file->name);
140 				}
141 			}
142 			// mountpoints if any
143 			RFSRoot *r;
144 			char *me = strdup (ptr);
145 			r_list_foreach (fs->roots, iter, r) {
146 				char *base = strdup (r->path);
147 				char *ls = (char *)r_str_lchr (base, '/');
148 				if (ls) {
149 					ls++;
150 					*ls = 0;
151 				}
152 				// TODO: adjust contents between //
153 				if (!strcmp (me, base)) {
154 					cb_printf ("m %s\n", (r->path && r->path[0]) ? r->path + 1: "");
155 				}
156 				free (base);
157 			}
158 			free (me);
159 		} else if (!strncmp (buf, "pwd", 3)) {
160 			eprintf ("%s\n", path);
161 		} else if (!memcmp (buf, "cd ", 3)) {
162 			char opath[PROMPT_PATH_BUFSIZE];
163 			r_str_ncpy (opath, path, sizeof (opath));
164 			input = buf + 3;
165 			while (*input == ' ') {
166 				input++;
167 			}
168 			if (!strcmp (input, "..")) {
169 				char* p = (char*) r_str_lchr (path, '/');
170 				if (p) {
171 					p[(p == path)? 1: 0] = 0;
172 				}
173 			} else {
174 				strcat (path, "/");
175 				if (*input == '/') {
176 					strncpy (path, input, sizeof (opath) - 1);
177 				} else {
178 					if ((strlen (path) + strlen (input)) >= sizeof (path)) {
179 						// overflow
180 						path[0] = 0;
181 					} else {
182 						strcat (path, input);
183 					}
184 				}
185 				path[sizeof (path) - 1] = 0;
186 			}
187 			r_str_trim_path (path);
188 			r_list_free (list);
189 			list = r_fs_dir (fs, path);
190 			if (r_list_empty (list)) {
191 				RFSRoot *r;
192 				RListIter *iter;
193 				r_list_foreach (fs->roots, iter, r) {
194 					if (!strcmp (path, r->path)) {
195 						r_list_append (list, r->path);
196 					}
197 				}
198 			}
199 		} else if (!memcmp (buf, "cat ", 4)) {
200 			input = buf + 3;
201 			while (input[0] == ' ') {
202 				input++;
203 			}
204 			if (input[0] == '/') {
205 				if (root) {
206 					strncpy (str, root, sizeof (str) - 1);
207 				} else {
208 					str[0] = 0;
209 				}
210 			} else {
211 				strncpy (str, path, sizeof (str) - 1);
212 			}
213 			size_t n = strlen (str);
214 			snprintf (str + n, sizeof (str) - n, "/%s", input);
215 			char *p = strchr (str, '>');
216 			if (p) {
217 				*p = 0;
218 			}
219 			file = r_fs_open (fs, str, false);
220 			if (file) {
221 				if (p) {
222 					*p = '>';
223 				}
224 				r_fs_read (fs, file, 0, file->size);
225 				if (!handlePipes (fs, str, file->data, path)) {
226 					char *s = r_str_ndup ((const char *)file->data, file->size);
227 					cb_printf ("%s\n", s);
228 					free (s);
229 				}
230 				cb_printf ("\n");
231 				r_fs_close (fs, file);
232 			} else {
233 				eprintf ("Cannot open file\n");
234 			}
235 		} else if (!memcmp (buf, "mount", 5)) {
236 			RFSRoot* r;
237 			r_list_foreach (fs->roots, iter, r) {
238 				cb_printf ("%s %s\n", r->path, r->p->name);
239 			}
240 		} else if (!memcmp (buf, "get ", 4)) {
241 			char* s = 0;
242 			input = buf + 3;
243 			while (input[0] == ' ') {
244 				input++;
245 			}
246 			if (input[0] == '/') {
247 				if (root) {
248 					s = malloc (strlen (root) + strlen (input) + 2);
249 					if (!s) {
250 						goto beach;
251 					}
252 					strcpy (s, root);
253 				}
254 			} else {
255 				s = malloc (strlen (path) + strlen (input) + 2);
256 				if (!s) {
257 					goto beach;
258 				}
259 				strcpy (s, path);
260 			}
261 			if (!s) {
262 				s = calloc (strlen (input) + 32, 1);
263 				if (!s) {
264 					goto beach;
265 				}
266 			}
267 			strcat (s, "/");
268 			strcat (s, input);
269 			file = r_fs_open (fs, s, false);
270 			if (file) {
271 				r_fs_read (fs, file, 0, file->size);
272 				r_file_dump (input, file->data, file->size, 0);
273 				r_fs_close (fs, file);
274 			} else {
275 				char *f = r_str_newf ("./%s", input);
276 				if (!r_fs_dir_dump (fs, s, f)) {
277 					eprintf ("Cannot open file\n");
278 				}
279 				free (f);
280 			}
281 			free (s);
282 		} else if (!memcmp (buf, "help", 4) || !strcmp (buf, "?")) {
283 			cb_printf (
284 				"Usage: [command (arguments)]([~grep-expression])\n"
285 				" !cmd        ; escape to system\n"
286 				" :cmd        ; escape to the r2 repl\n"
287 				" ls [path]   ; list current directory\n"
288 				" cd path     ; change current directory\n"
289 				" cat file    ; print contents of file\n"
290 				" get file    ; dump file to disk\n"
291 				" mount       ; list mount points\n"
292 				" q/exit      ; leave prompt mode\n"
293 				" ?/help      ; show this help\n");
294 		} else {
295 			if (*buf) {
296 				eprintf ("Unknown command %s\n", buf);
297 			}
298 		}
299 		if (wave) {
300 			fs->csb.cb_grep (wave);
301 		}
302 		fs->csb.cb_flush ();
303 	}
304 beach:
305 	clearerr (stdin);
306 	printf ("\n");
307 	r_list_free (list);
308 	return true;
309 }
310 
311