add jim_handler to command_registration
[openocd.git] / src / helper / ioutil.c
1 /***************************************************************************
2 * Copyright (C) 2007-2008 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, write to the *
16 * Free Software Foundation, Inc., *
17 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
18 ***************************************************************************/
19
20 /* this file contains various functionality useful to standalone systems */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "log.h"
27 #include "time_support.h"
28
29 #ifdef HAVE_ARPA_INET_H
30 #include <arpa/inet.h>
31 #endif
32 #ifdef HAVE_DIRENT_H
33 #include <dirent.h>
34 #endif
35 #ifdef HAVE_NETDB_H
36 #include <netdb.h>
37 #endif
38 #ifdef HAVE_NET_IF_H
39 #include <net/if.h>
40 #endif
41 //#ifdef HAVE_NETINET_TCP_H
42 //#include <netinet/tcp.h>
43 //#endif
44 #ifdef HAVE_SYS_IOCTL_H
45 #include <sys/ioctl.h>
46 #endif
47 #ifdef HAVE_SYS_STAT_H
48 #include <sys/stat.h>
49 #endif
50 #ifdef HAVE_IFADDRS_H
51 #include <ifaddrs.h>
52 #endif
53 #ifdef HAVE_MALLOC_H
54 #if !BUILD_ECOSBOARD
55 #include <malloc.h>
56 #endif
57 #endif
58
59
60 COMMAND_HANDLER(handle_rm_command)
61 {
62 if (CMD_ARGC != 1)
63 {
64 command_print(CMD_CTX, "rm <filename>");
65 return ERROR_INVALID_ARGUMENTS;
66 }
67
68 if (unlink(CMD_ARGV[0]) != 0)
69 {
70 command_print(CMD_CTX, "failed: %d", errno);
71 }
72
73 return ERROR_OK;
74 }
75
76
77 /* loads a file and returns a pointer to it in memory. The file contains
78 * a 0 byte(sentinel) after len bytes - the length of the file. */
79 int loadFile(const char *fileName, void **data, size_t *len)
80 {
81 // ensure returned length is always sane
82 *len = 0;
83
84 FILE * pFile;
85 pFile = fopen(fileName,"rb");
86 if (pFile == NULL)
87 {
88 LOG_ERROR("Can't open %s\n", fileName);
89 return ERROR_FAIL;
90 }
91 if (fseek(pFile, 0, SEEK_END) != 0)
92 {
93 LOG_ERROR("Can't open %s\n", fileName);
94 fclose(pFile);
95 return ERROR_FAIL;
96 }
97 long fsize = ftell(pFile);
98 if (fsize == -1)
99 {
100 LOG_ERROR("Can't open %s\n", fileName);
101 fclose(pFile);
102 return ERROR_FAIL;
103 }
104 *len = fsize;
105
106 if (fseek(pFile, 0, SEEK_SET) != 0)
107 {
108 LOG_ERROR("Can't open %s\n", fileName);
109 fclose(pFile);
110 return ERROR_FAIL;
111 }
112 *data = malloc(*len + 1);
113 if (*data == NULL)
114 {
115 LOG_ERROR("Can't open %s\n", fileName);
116 fclose(pFile);
117 return ERROR_FAIL;
118 }
119
120 if (fread(*data, 1, *len, pFile)!=*len)
121 {
122 fclose(pFile);
123 free(*data);
124 LOG_ERROR("Can't open %s\n", fileName);
125 return ERROR_FAIL;
126 }
127 fclose(pFile);
128
129 // 0-byte after buffer (not included in *len) serves as a sentinel
130 char *buf = (char *)*data;
131 buf[*len] = 0;
132
133 return ERROR_OK;
134 }
135
136 COMMAND_HANDLER(handle_cat_command)
137 {
138 if (CMD_ARGC != 1)
139 {
140 command_print(CMD_CTX, "cat <filename>");
141 return ERROR_INVALID_ARGUMENTS;
142 }
143
144 // NOTE!!! we only have line printing capability so we print the entire file as a single line.
145 void *data;
146 size_t len;
147
148 int retval = loadFile(CMD_ARGV[0], &data, &len);
149 if (retval == ERROR_OK)
150 {
151 command_print(CMD_CTX, "%s", (char *)data);
152 free(data);
153 }
154 else
155 {
156 command_print(CMD_CTX, "%s not found %d", CMD_ARGV[0], retval);
157 }
158
159 return ERROR_OK;
160 }
161
162 COMMAND_HANDLER(handle_trunc_command)
163 {
164 if (CMD_ARGC != 1)
165 {
166 command_print(CMD_CTX, "trunc <filename>");
167 return ERROR_INVALID_ARGUMENTS;
168 }
169
170 FILE *config_file = NULL;
171 config_file = fopen(CMD_ARGV[0], "w");
172 if (config_file != NULL)
173 fclose(config_file);
174
175 return ERROR_OK;
176 }
177
178 COMMAND_HANDLER(handle_meminfo_command)
179 {
180 static int prev = 0;
181 struct mallinfo info;
182
183 if (CMD_ARGC != 0)
184 {
185 command_print(CMD_CTX, "meminfo");
186 return ERROR_INVALID_ARGUMENTS;
187 }
188
189 info = mallinfo();
190
191 if (prev > 0)
192 {
193 command_print(CMD_CTX, "Diff: %d", prev - info.fordblks);
194 }
195 prev = info.fordblks;
196
197 command_print(CMD_CTX, "Available ram: %d", info.fordblks);
198
199 return ERROR_OK;
200 }
201
202
203 COMMAND_HANDLER(handle_append_command)
204 {
205 if (CMD_ARGC < 1)
206 {
207 command_print(CMD_CTX,
208 "append <filename> [<string1>, [<string2>, ...]]");
209 return ERROR_INVALID_ARGUMENTS;
210 }
211
212 int retval = ERROR_FAIL;
213 FILE *config_file = NULL;
214 config_file = fopen(CMD_ARGV[0], "a");
215 if (config_file != NULL)
216 {
217 fseek(config_file, 0, SEEK_END);
218
219 unsigned i;
220 for (i = 1; i < CMD_ARGC; i++)
221 {
222 if (fwrite(CMD_ARGV[i], 1, strlen(CMD_ARGV[i]), config_file) != strlen(CMD_ARGV[i]))
223 break;
224 if (i != CMD_ARGC - 1)
225 {
226 if (fwrite(" ", 1, 1, config_file) != 1)
227 break;
228 }
229 }
230 if ((i == CMD_ARGC) && (fwrite("\n", 1, 1, config_file) == 1))
231 {
232 retval = ERROR_OK;
233 }
234 fclose(config_file);
235 }
236
237 return retval;
238 }
239
240
241
242 COMMAND_HANDLER(handle_cp_command)
243 {
244 if (CMD_ARGC != 2)
245 {
246 return ERROR_INVALID_ARGUMENTS;
247 }
248
249 // NOTE!!! we only have line printing capability so we print the entire file as a single line.
250 void *data;
251 size_t len;
252
253 int retval = loadFile(CMD_ARGV[0], &data, &len);
254 if (retval != ERROR_OK)
255 return retval;
256
257 FILE *f = fopen(CMD_ARGV[1], "wb");
258 if (f == NULL)
259 retval = ERROR_INVALID_ARGUMENTS;
260
261 size_t pos = 0;
262 for (;;)
263 {
264 size_t chunk = len - pos;
265 static const size_t maxChunk = 512 * 1024; // ~1/sec
266 if (chunk > maxChunk)
267 {
268 chunk = maxChunk;
269 }
270
271 if ((retval == ERROR_OK) && (fwrite(((char *)data) + pos, 1, chunk, f) != chunk))
272 retval = ERROR_INVALID_ARGUMENTS;
273
274 if (retval != ERROR_OK)
275 {
276 break;
277 }
278
279 command_print(CMD_CTX, "%zu", len - pos);
280
281 pos += chunk;
282
283 if (pos == len)
284 break;
285 }
286
287 if (retval == ERROR_OK)
288 {
289 command_print(CMD_CTX, "Copied %s to %s", CMD_ARGV[0], CMD_ARGV[1]);
290 } else
291 {
292 command_print(CMD_CTX, "Failed: %d", retval);
293 }
294
295 if (data != NULL)
296 free(data);
297 if (f != NULL)
298 fclose(f);
299
300 if (retval != ERROR_OK)
301 unlink(CMD_ARGV[1]);
302
303 return retval;
304 }
305
306
307
308
309 #define SHOW_RESULT(a, b) LOG_ERROR(#a " failed %d\n", (int)b)
310
311 #define IOSIZE 512
312 void copyfile(char *name2, char *name1)
313 {
314
315 int err;
316 char buf[IOSIZE];
317 int fd1, fd2;
318 ssize_t done, wrote;
319
320 fd1 = open(name1, O_WRONLY | O_CREAT, 0664);
321 if (fd1 < 0)
322 SHOW_RESULT(open, fd1);
323
324 fd2 = open(name2, O_RDONLY);
325 if (fd2 < 0)
326 SHOW_RESULT(open, fd2);
327
328 for (;;)
329 {
330 done = read(fd2, buf, IOSIZE);
331 if (done < 0)
332 {
333 SHOW_RESULT(read, done);
334 break;
335 }
336
337 if (done == 0) break;
338
339 wrote = write(fd1, buf, done);
340 if (wrote != done) SHOW_RESULT(write, wrote);
341
342 if (wrote != done) break;
343 }
344
345 err = close(fd1);
346 if (err < 0) SHOW_RESULT(close, err);
347
348 err = close(fd2);
349 if (err < 0) SHOW_RESULT(close, err);
350
351 }
352
353 /* utility fn to copy a directory */
354 void copydir(char *name, char *destdir)
355 {
356 int err;
357 DIR *dirp;
358
359 dirp = opendir(destdir);
360 if (dirp == NULL)
361 {
362 mkdir(destdir, 0777);
363 } else
364 {
365 err = closedir(dirp);
366 }
367
368 dirp = opendir(name);
369 if (dirp == NULL) SHOW_RESULT(opendir, -1);
370
371 for (;;)
372 {
373 struct dirent *entry = readdir(dirp);
374
375 if (entry == NULL)
376 break;
377
378 if (strcmp(entry->d_name, ".") == 0)
379 continue;
380 if (strcmp(entry->d_name, "..") == 0)
381 continue;
382
383 int isDir = 0;
384 struct stat buf;
385 char fullPath[PATH_MAX];
386 strncpy(fullPath, name, PATH_MAX);
387 strcat(fullPath, "/");
388 strncat(fullPath, entry->d_name, PATH_MAX - strlen(fullPath));
389
390 if (stat(fullPath, &buf) == -1)
391 {
392 LOG_ERROR("unable to read status from %s", fullPath);
393 break;
394 }
395 isDir = S_ISDIR(buf.st_mode) != 0;
396
397 if (isDir)
398 continue;
399
400 // diag_printf("<INFO>: entry %14s",entry->d_name);
401 char fullname[PATH_MAX];
402 char fullname2[PATH_MAX];
403
404 strcpy(fullname, name);
405 strcat(fullname, "/");
406 strcat(fullname, entry->d_name);
407
408 strcpy(fullname2, destdir);
409 strcat(fullname2, "/");
410 strcat(fullname2, entry->d_name);
411 // diag_printf("from %s to %s\n", fullname, fullname2);
412 copyfile(fullname, fullname2);
413
414 // diag_printf("\n");
415 }
416
417 err = closedir(dirp);
418 if (err < 0) SHOW_RESULT(stat, err);
419 }
420
421
422
423
424 static int
425 zylinjtag_Jim_Command_rm(Jim_Interp *interp,
426 int argc,
427 Jim_Obj * const *argv)
428 {
429 int del;
430 if (argc != 2)
431 {
432 Jim_WrongNumArgs(interp, 1, argv, "rm ?dirorfile?");
433 return JIM_ERR;
434 }
435
436 del = 0;
437 if (unlink(Jim_GetString(argv[1], NULL)) == 0)
438 del = 1;
439 if (rmdir(Jim_GetString(argv[1], NULL)) == 0)
440 del = 1;
441
442 return del ? JIM_OK : JIM_ERR;
443 }
444
445
446 static int
447 zylinjtag_Jim_Command_ls(Jim_Interp *interp,
448 int argc,
449 Jim_Obj * const *argv)
450 {
451 if (argc != 2)
452 {
453 Jim_WrongNumArgs(interp, 1, argv, "ls ?dir?");
454 return JIM_ERR;
455 }
456
457 char *name = (char*) Jim_GetString(argv[1], NULL);
458
459 DIR *dirp = NULL;
460 dirp = opendir(name);
461 if (dirp == NULL)
462 {
463 return JIM_ERR;
464 }
465 Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
466
467 for (;;)
468 {
469 struct dirent *entry = NULL;
470 entry = readdir(dirp);
471 if (entry == NULL)
472 break;
473
474 if ((strcmp(".", entry->d_name) == 0)||(strcmp("..", entry->d_name) == 0))
475 continue;
476
477 Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, entry->d_name, strlen(entry->d_name)));
478 }
479 closedir(dirp);
480
481 Jim_SetResult(interp, objPtr);
482
483 return JIM_OK;
484 }
485
486 static int
487 zylinjtag_Jim_Command_peek(Jim_Interp *interp,
488 int argc,
489 Jim_Obj * const *argv)
490 {
491 if (argc != 2)
492 {
493 Jim_WrongNumArgs(interp, 1, argv, "peek ?address?");
494 return JIM_ERR;
495 }
496
497 long address;
498 if (Jim_GetLong(interp, argv[1], &address) != JIM_OK)
499 return JIM_ERR;
500
501 int value = *((volatile int *) address);
502
503 Jim_SetResult(interp, Jim_NewIntObj(interp, value));
504
505 return JIM_OK;
506 }
507
508 static int
509 zylinjtag_Jim_Command_poke(Jim_Interp *interp,
510 int argc,
511 Jim_Obj * const *argv)
512 {
513 if (argc != 3)
514 {
515 Jim_WrongNumArgs(interp, 1, argv, "poke ?address? ?value?");
516 return JIM_ERR;
517 }
518
519 long address;
520 if (Jim_GetLong(interp, argv[1], &address) != JIM_OK)
521 return JIM_ERR;
522 long value;
523 if (Jim_GetLong(interp, argv[2], &value) != JIM_OK)
524 return JIM_ERR;
525
526 *((volatile int *) address) = value;
527
528 return JIM_OK;
529 }
530
531
532 /* not so pretty code to fish out ip number*/
533 static int zylinjtag_Jim_Command_ip(Jim_Interp *interp, int argc,
534 Jim_Obj * const *argv)
535 {
536 #if !defined(__CYGWIN__)
537 Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
538
539 struct ifaddrs *ifa = NULL, *ifp = NULL;
540
541 if (getifaddrs(&ifp) < 0)
542 {
543 return JIM_ERR;
544 }
545
546 for (ifa = ifp; ifa; ifa = ifa->ifa_next)
547 {
548 char ip[200];
549 socklen_t salen;
550
551 if (ifa->ifa_addr->sa_family == AF_INET)
552 salen = sizeof(struct sockaddr_in);
553 else if (ifa->ifa_addr->sa_family == AF_INET6)
554 salen = sizeof(struct sockaddr_in6);
555 else
556 continue;
557
558 if (getnameinfo(ifa->ifa_addr, salen, ip, sizeof(ip), NULL, 0,
559 NI_NUMERICHOST) < 0)
560 {
561 continue;
562 }
563
564 Jim_AppendString(interp, tclOutput, ip, strlen(ip));
565 break;
566
567 }
568
569 freeifaddrs(ifp);
570 #else
571 Jim_Obj *tclOutput = Jim_NewStringObj(interp, "fixme!!!", 0);
572 LOG_ERROR("NOT IMPLEMENTED!!!");
573 #endif
574 Jim_SetResult(interp, tclOutput);
575
576 return JIM_OK;
577 }
578
579 /* not so pretty code to fish out eth0 mac address */
580 static int zylinjtag_Jim_Command_mac(Jim_Interp *interp, int argc,
581 Jim_Obj * const *argv)
582 {
583
584
585 struct ifreq *ifr, *ifend;
586 struct ifreq ifreq;
587 struct ifconf ifc;
588 struct ifreq ifs[5];
589 int SockFD;
590
591 SockFD = socket(AF_INET, SOCK_DGRAM, 0);
592 if (SockFD < 0)
593 {
594 return JIM_ERR;
595 }
596
597 ifc.ifc_len = sizeof(ifs);
598 ifc.ifc_req = ifs;
599 if (ioctl(SockFD, SIOCGIFCONF, &ifc) < 0)
600 {
601 close(SockFD);
602 return JIM_ERR;
603 }
604
605 ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
606 for (ifr = ifc.ifc_req; ifr < ifend; ifr++)
607 {
608 //if (ifr->ifr_addr.sa_family == AF_INET)
609 {
610 if (strcmp("eth0", ifr->ifr_name) != 0)
611 continue;
612 strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
613 if (ioctl(SockFD, SIOCGIFHWADDR, &ifreq) < 0)
614 {
615 close(SockFD);
616 return JIM_ERR;
617 }
618
619 close(SockFD);
620
621
622 Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
623
624 char buffer[256];
625 sprintf(buffer, "%02x-%02x-%02x-%02x-%02x-%02x",
626 ifreq.ifr_hwaddr.sa_data[0]&0xff,
627 ifreq.ifr_hwaddr.sa_data[1]&0xff,
628 ifreq.ifr_hwaddr.sa_data[2]&0xff,
629 ifreq.ifr_hwaddr.sa_data[3]&0xff,
630 ifreq.ifr_hwaddr.sa_data[4]&0xff,
631 ifreq.ifr_hwaddr.sa_data[5]&0xff);
632
633 Jim_AppendString(interp, tclOutput, buffer, strlen(buffer));
634
635 Jim_SetResult(interp, tclOutput);
636
637 return JIM_OK;
638 }
639 }
640 close(SockFD);
641
642 return JIM_ERR;
643
644 }
645
646 static const struct command_registration ioutil_command_handlers[] = {
647 {
648 .name = "rm",
649 .handler = &handle_rm_command,
650 .mode = COMMAND_ANY,
651 .help = "remove file",
652 .usage= "<file_name>",
653 },
654 {
655 .name = "cat",
656 .handler = &handle_cat_command,
657 .mode = COMMAND_ANY,
658 .help = "display file content",
659 .usage= "<file_name>",
660 },
661 {
662 .name = "trunc",
663 .handler = &handle_trunc_command,
664 .mode = COMMAND_ANY,
665 .help = "truncate a file 0 size",
666 .usage= "<file_name>",
667 },
668 {
669 .name = "cp",
670 .handler = &handle_cp_command,
671 .mode = COMMAND_ANY,
672 .help = "copy a file",
673 .usage = "<src> <dst>",
674 },
675 {
676 .name = "append_file",
677 .handler = &handle_append_command,
678 .mode = COMMAND_ANY,
679 .help = "append a variable number of strings to a file",
680 .usage= "<file_name> [<string> ...]",
681 },
682 {
683 .name = "meminfo",
684 .handler = &handle_meminfo_command,
685 .mode = COMMAND_ANY,
686 .help = "display available ram memory",
687 },
688 // jim handlers
689 {
690 .name = "rm",
691 .mode = COMMAND_ANY,
692 .jim_handler = &zylinjtag_Jim_Command_rm,
693 .help = "remove a file",
694 .usage = "<file>",
695 },
696 {
697 .name = "peek",
698 .mode = COMMAND_ANY,
699 .jim_handler = &zylinjtag_Jim_Command_peek,
700 .help = "peek at a memory address",
701 .usage = "<addr>",
702 },
703 {
704 .name = "poke",
705 .mode = COMMAND_ANY,
706 .jim_handler = &zylinjtag_Jim_Command_poke,
707 .help = "poke at a memory address",
708 .usage = "<addr> <value>",
709 },
710 {
711 .name = "ls",
712 .mode = COMMAND_ANY,
713 .jim_handler = &zylinjtag_Jim_Command_ls,
714 .help = "show a listing of files",
715 .usage = "<dir>",
716 },
717 {
718 .name = "mac",
719 .mode = COMMAND_ANY,
720 .jim_handler = &zylinjtag_Jim_Command_mac,
721 .help = "show MAC address",
722 },
723 {
724 .name = "ip",
725 .jim_handler = &zylinjtag_Jim_Command_ip,
726 .mode = COMMAND_ANY,
727 .help = "show IP address",
728 },
729 COMMAND_REGISTRATION_DONE
730 };
731
732 int ioutil_init(struct command_context *cmd_ctx)
733 {
734 return register_commands(cmd_ctx, NULL, ioutil_command_handlers);
735 }

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)