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

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)