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

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)