f1123cd82d5db25649f5d86956f6cb60058d17ff
[openocd.git] / src / helper / ioutil.c
1 /***************************************************************************
2 * Copyright (C) 2007-2010 by √ėyvind Harboe *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
16 ***************************************************************************/
17
18 /* this file contains various functionality useful to standalone systems */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "log.h"
25 #include "time_support.h"
26
27 #ifdef HAVE_ARPA_INET_H
28 #include <arpa/inet.h>
29 #endif
30 #ifdef HAVE_DIRENT_H
31 #include <dirent.h>
32 #endif
33 #ifdef HAVE_NETDB_H
34 #include <netdb.h>
35 #endif
36 #ifdef HAVE_NET_IF_H
37 #include <net/if.h>
38 #endif
39 #ifdef HAVE_SYS_IOCTL_H
40 #include <sys/ioctl.h>
41 #endif
42 #ifdef HAVE_SYS_STAT_H
43 #include <sys/stat.h>
44 #endif
45 #ifdef HAVE_IFADDRS_H
46 #include <ifaddrs.h>
47 #endif
48 #ifdef HAVE_MALLOC_H
49 #include <malloc.h>
50 #endif
51
52 /* loads a file and returns a pointer to it in memory. The file contains
53 * a 0 byte(sentinel) after len bytes - the length of the file. */
54 static int load_file(const char *fileName, char **data, size_t *len)
55 {
56 /* ensure returned length is always sane */
57 *len = 0;
58
59 FILE *pFile;
60 pFile = fopen(fileName, "rb");
61 if (pFile == NULL) {
62 LOG_ERROR("Can't open %s", fileName);
63 return ERROR_FAIL;
64 }
65 if (fseek(pFile, 0, SEEK_END) != 0) {
66 LOG_ERROR("Can't open %s", fileName);
67 fclose(pFile);
68 return ERROR_FAIL;
69 }
70 long fsize = ftell(pFile);
71 if (fsize == -1) {
72 LOG_ERROR("Can't open %s", fileName);
73 fclose(pFile);
74 return ERROR_FAIL;
75 }
76 *len = fsize;
77
78 if (fseek(pFile, 0, SEEK_SET) != 0) {
79 LOG_ERROR("Can't open %s", fileName);
80 fclose(pFile);
81 return ERROR_FAIL;
82 }
83 *data = malloc(*len + 1);
84 if (*data == NULL) {
85 LOG_ERROR("Can't open %s", fileName);
86 fclose(pFile);
87 return ERROR_FAIL;
88 }
89
90 if (fread(*data, 1, *len, pFile) != *len) {
91 fclose(pFile);
92 free(*data);
93 LOG_ERROR("Can't open %s", fileName);
94 return ERROR_FAIL;
95 }
96 fclose(pFile);
97
98 /* 0-byte after buffer (not included in *len) serves as a sentinel */
99 (*data)[*len] = 0;
100
101 return ERROR_OK;
102 }
103
104 COMMAND_HANDLER(handle_cat_command)
105 {
106 if (CMD_ARGC != 1)
107 return ERROR_COMMAND_SYNTAX_ERROR;
108
109 /* NOTE!!! we only have line printing capability so we print the entire file as a single
110 * line. */
111 char *data;
112 size_t len;
113
114 int retval = load_file(CMD_ARGV[0], &data, &len);
115 if (retval == ERROR_OK) {
116 command_print(CMD_CTX, "%s", data);
117 free(data);
118 } else
119 command_print(CMD_CTX, "%s not found", CMD_ARGV[0]);
120
121 return ERROR_OK;
122 }
123
124 COMMAND_HANDLER(handle_trunc_command)
125 {
126 if (CMD_ARGC != 1)
127 return ERROR_COMMAND_SYNTAX_ERROR;
128
129 FILE *config_file = NULL;
130 config_file = fopen(CMD_ARGV[0], "w");
131 if (config_file != NULL)
132 fclose(config_file);
133
134 return ERROR_OK;
135 }
136
137 #ifdef HAVE_MALLOC_H
138 COMMAND_HANDLER(handle_meminfo_command)
139 {
140 static int prev;
141 struct mallinfo info;
142
143 if (CMD_ARGC != 0)
144 return ERROR_COMMAND_SYNTAX_ERROR;
145
146 info = mallinfo();
147
148 if (prev > 0)
149 command_print(CMD_CTX, "Diff: %d", prev - info.fordblks);
150 prev = info.fordblks;
151
152 command_print(CMD_CTX, "Available ram: %d", info.fordblks);
153
154 return ERROR_OK;
155 }
156 #endif
157
158 COMMAND_HANDLER(handle_append_command)
159 {
160 if (CMD_ARGC < 1)
161 return ERROR_COMMAND_SYNTAX_ERROR;
162
163 int retval = ERROR_FAIL;
164 FILE *config_file = NULL;
165
166 config_file = fopen(CMD_ARGV[0], "a");
167 if (config_file != NULL) {
168 fseek(config_file, 0, SEEK_END);
169
170 unsigned i;
171 for (i = 1; i < CMD_ARGC; i++) {
172 if (fwrite(CMD_ARGV[i], 1, strlen(CMD_ARGV[i]),
173 config_file) != strlen(CMD_ARGV[i]))
174 break;
175 if (i != CMD_ARGC - 1) {
176 if (fwrite(" ", 1, 1, config_file) != 1)
177 break;
178 }
179 }
180 if ((i == CMD_ARGC) && (fwrite("\n", 1, 1, config_file) == 1))
181 retval = ERROR_OK;
182
183 fclose(config_file);
184 }
185
186 return retval;
187 }
188
189 COMMAND_HANDLER(handle_cp_command)
190 {
191 if (CMD_ARGC != 2)
192 return ERROR_COMMAND_SYNTAX_ERROR;
193
194 /* NOTE!!! we only have line printing capability so we print the entire file as a single
195 * line. */
196 char *data;
197 size_t len;
198
199 int retval = load_file(CMD_ARGV[0], &data, &len);
200 if (retval != ERROR_OK)
201 return retval;
202
203 FILE *f = fopen(CMD_ARGV[1], "wb");
204 if (f == NULL)
205 retval = ERROR_COMMAND_SYNTAX_ERROR;
206
207 size_t pos = 0;
208 for (;; ) {
209 size_t chunk = len - pos;
210 static const size_t maxChunk = 512 * 1024; /* ~1/sec */
211 if (chunk > maxChunk)
212 chunk = maxChunk;
213
214 if ((retval == ERROR_OK) && (fwrite(data + pos, 1, chunk, f) != chunk))
215 retval = ERROR_COMMAND_SYNTAX_ERROR;
216
217 if (retval != ERROR_OK)
218 break;
219
220 command_print(CMD_CTX, "%zu", len - pos);
221
222 pos += chunk;
223
224 if (pos == len)
225 break;
226 }
227
228 if (retval == ERROR_OK)
229 command_print(CMD_CTX, "Copied %s to %s", CMD_ARGV[0], CMD_ARGV[1]);
230 else
231 command_print(CMD_CTX, "copy failed");
232
233 if (data != NULL)
234 free(data);
235 if (f != NULL)
236 fclose(f);
237
238 if (retval != ERROR_OK)
239 unlink(CMD_ARGV[1]);
240
241 return retval;
242 }
243
244 COMMAND_HANDLER(handle_rm_command)
245 {
246 if (CMD_ARGC != 1)
247 return ERROR_COMMAND_SYNTAX_ERROR;
248
249 bool del = false;
250 if (rmdir(CMD_ARGV[0]) == 0)
251 del = true;
252 else if (unlink(CMD_ARGV[0]) == 0)
253 del = true;
254
255 return del ? ERROR_OK : ERROR_FAIL;
256 }
257
258 static int ioutil_Jim_Command_ls(Jim_Interp *interp,
259 int argc,
260 Jim_Obj * const *argv)
261 {
262 if (argc != 2) {
263 Jim_WrongNumArgs(interp, 1, argv, "ls ?dir?");
264 return JIM_ERR;
265 }
266
267 const char *name = Jim_GetString(argv[1], NULL);
268
269 DIR *dirp = NULL;
270 dirp = opendir(name);
271 if (dirp == NULL)
272 return JIM_ERR;
273 Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
274
275 for (;; ) {
276 struct dirent *entry = NULL;
277 entry = readdir(dirp);
278 if (entry == NULL)
279 break;
280
281 if ((strcmp(".", entry->d_name) == 0) || (strcmp("..", entry->d_name) == 0))
282 continue;
283
284 Jim_ListAppendElement(interp, objPtr,
285 Jim_NewStringObj(interp, entry->d_name, strlen(entry->d_name)));
286 }
287 closedir(dirp);
288
289 Jim_SetResult(interp, objPtr);
290
291 return JIM_OK;
292 }
293
294 static int ioutil_Jim_Command_peek(Jim_Interp *interp,
295 int argc,
296 Jim_Obj *const *argv)
297 {
298 if (argc != 2) {
299 Jim_WrongNumArgs(interp, 1, argv, "peek ?address?");
300 return JIM_ERR;
301 }
302
303 long address;
304 if (Jim_GetLong(interp, argv[1], &address) != JIM_OK)
305 return JIM_ERR;
306
307 int value = *((volatile int *) address);
308
309 Jim_SetResult(interp, Jim_NewIntObj(interp, value));
310
311 return JIM_OK;
312 }
313
314 static int ioutil_Jim_Command_poke(Jim_Interp *interp,
315 int argc,
316 Jim_Obj *const *argv)
317 {
318 if (argc != 3) {
319 Jim_WrongNumArgs(interp, 1, argv, "poke ?address? ?value?");
320 return JIM_ERR;
321 }
322
323 long address;
324 if (Jim_GetLong(interp, argv[1], &address) != JIM_OK)
325 return JIM_ERR;
326 long value;
327 if (Jim_GetLong(interp, argv[2], &value) != JIM_OK)
328 return JIM_ERR;
329
330 *((volatile int *) address) = value;
331
332 return JIM_OK;
333 }
334
335 /* not so pretty code to fish out ip number*/
336 static int ioutil_Jim_Command_ip(Jim_Interp *interp, int argc,
337 Jim_Obj *const *argv)
338 {
339 #if !defined(__CYGWIN__)
340 Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
341
342 struct ifaddrs *ifa = NULL, *ifp = NULL;
343
344 if (getifaddrs(&ifp) < 0)
345 return JIM_ERR;
346
347 for (ifa = ifp; ifa; ifa = ifa->ifa_next) {
348 char ip[200];
349 socklen_t salen;
350
351 if (ifa->ifa_addr->sa_family == AF_INET)
352 salen = sizeof(struct sockaddr_in);
353 else if (ifa->ifa_addr->sa_family == AF_INET6)
354 salen = sizeof(struct sockaddr_in6);
355 else
356 continue;
357
358 if (getnameinfo(ifa->ifa_addr, salen, ip, sizeof(ip), NULL, 0,
359 NI_NUMERICHOST) < 0)
360 continue;
361
362 Jim_AppendString(interp, tclOutput, ip, strlen(ip));
363 break;
364
365 }
366
367 freeifaddrs(ifp);
368 #else
369 Jim_Obj *tclOutput = Jim_NewStringObj(interp, "fixme!!!", 0);
370 LOG_ERROR("NOT IMPLEMENTED!!!");
371 #endif
372 Jim_SetResult(interp, tclOutput);
373
374 return JIM_OK;
375 }
376
377 #ifdef HAVE_SYS_IOCTL_H
378 #ifdef SIOCGIFHWADDR
379 /* not so pretty code to fish out eth0 mac address */
380 static int ioutil_Jim_Command_mac(Jim_Interp *interp, int argc,
381 Jim_Obj *const *argv)
382 {
383 struct ifreq *ifr, *ifend;
384 struct ifreq ifreq;
385 struct ifconf ifc;
386 struct ifreq ifs[5];
387 int SockFD;
388
389 SockFD = socket(AF_INET, SOCK_DGRAM, 0);
390 if (SockFD < 0)
391 return JIM_ERR;
392
393 ifc.ifc_len = sizeof(ifs);
394 ifc.ifc_req = ifs;
395 if (ioctl(SockFD, SIOCGIFCONF, &ifc) < 0) {
396 close(SockFD);
397 return JIM_ERR;
398 }
399
400 ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
401 for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
402 /* if (ifr->ifr_addr.sa_family == AF_INET) */
403 {
404 if (strcmp("eth0", ifr->ifr_name) != 0)
405 continue;
406 strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
407 if (ioctl(SockFD, SIOCGIFHWADDR, &ifreq) < 0) {
408 close(SockFD);
409 return JIM_ERR;
410 }
411
412 close(SockFD);
413
414 Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
415
416 char buffer[256];
417 sprintf(buffer, "%02x-%02x-%02x-%02x-%02x-%02x",
418 ifreq.ifr_hwaddr.sa_data[0]&0xff,
419 ifreq.ifr_hwaddr.sa_data[1]&0xff,
420 ifreq.ifr_hwaddr.sa_data[2]&0xff,
421 ifreq.ifr_hwaddr.sa_data[3]&0xff,
422 ifreq.ifr_hwaddr.sa_data[4]&0xff,
423 ifreq.ifr_hwaddr.sa_data[5]&0xff);
424
425 Jim_AppendString(interp, tclOutput, buffer, strlen(buffer));
426
427 Jim_SetResult(interp, tclOutput);
428
429 return JIM_OK;
430 }
431 }
432 close(SockFD);
433
434 return JIM_ERR;
435
436 }
437 #endif
438 #endif
439
440 static const struct command_registration ioutil_command_handlers[] = {
441 {
442 .name = "cat",
443 .handler = handle_cat_command,
444 .mode = COMMAND_ANY,
445 .help = "display text file content",
446 .usage = "file_name",
447 },
448 {
449 .name = "trunc",
450 .handler = handle_trunc_command,
451 .mode = COMMAND_ANY,
452 .help = "truncate a file to zero length",
453 .usage = "file_name",
454 },
455 {
456 .name = "cp",
457 .handler = handle_cp_command,
458 .mode = COMMAND_ANY,
459 .help = "copy a file",
460 .usage = "src_file_name dst_file_name",
461 },
462 {
463 .name = "append_file",
464 .handler = handle_append_command,
465 .mode = COMMAND_ANY,
466 .help = "append a variable number of strings to a file",
467 .usage = "file_name [<string1>, [<string2>, ...]]",
468 },
469 #ifdef HAVE_MALLOC_H
470 {
471 .name = "meminfo",
472 .handler = handle_meminfo_command,
473 .mode = COMMAND_ANY,
474 .help = "display free heap space",
475 },
476 #endif
477 {
478 .name = "rm",
479 .mode = COMMAND_ANY,
480 .handler = handle_rm_command,
481 .help = "remove a directory or file",
482 .usage = "file_name",
483 },
484
485 /*
486 * Peek and poke are security holes -- they manipulate
487 * server-internal addresses.
488 */
489
490 /* jim handlers */
491 {
492 .name = "peek",
493 .mode = COMMAND_ANY,
494 .jim_handler = ioutil_Jim_Command_peek,
495 .help = "peek at a memory address",
496 .usage = "address",
497 },
498 {
499 .name = "poke",
500 .mode = COMMAND_ANY,
501 .jim_handler = ioutil_Jim_Command_poke,
502 .help = "poke at a memory address",
503 .usage = "address value",
504 },
505 {
506 .name = "ls",
507 .mode = COMMAND_ANY,
508 .jim_handler = ioutil_Jim_Command_ls,
509 .help = "show a listing of files",
510 .usage = "dirname",
511 },
512 #ifdef HAVE_SYS_IOCTL_H
513 #ifdef SIOCGIFHWADDR
514 {
515 .name = "mac",
516 .mode = COMMAND_ANY,
517 .jim_handler = ioutil_Jim_Command_mac,
518 .help = "show MAC address",
519 },
520 #endif
521 #endif
522 {
523 .name = "ip",
524 .jim_handler = ioutil_Jim_Command_ip,
525 .mode = COMMAND_ANY,
526 .help = "show IP address",
527 },
528 COMMAND_REGISTRATION_DONE
529 };
530
531 int ioutil_init(struct command_context *cmd_ctx)
532 {
533 return register_commands(cmd_ctx, NULL, ioutil_command_handlers);
534 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)