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

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)