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

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)