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

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)