jtag: linuxgpiod: drop extra parenthesis
[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, see <http://www.gnu.org/licenses/>. *
16 ***************************************************************************/
17
18 /* this file contains various functionality useful to standalone systems */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "log.h"
25 #include "time_support.h"
26
27 #ifdef HAVE_ARPA_INET_H
28 #include <arpa/inet.h>
29 #endif
30 #ifdef HAVE_DIRENT_H
31 #include <dirent.h>
32 #endif
33 #ifdef HAVE_NETDB_H
34 #include <netdb.h>
35 #endif
36 #ifdef HAVE_NET_IF_H
37 #include <net/if.h>
38 #endif
39 #ifdef HAVE_SYS_IOCTL_H
40 #include <sys/ioctl.h>
41 #endif
42 #ifdef HAVE_SYS_STAT_H
43 #include <sys/stat.h>
44 #endif
45 #ifdef HAVE_IFADDRS_H
46 #include <ifaddrs.h>
47 #endif
48 #ifdef HAVE_MALLOC_H
49 #include <malloc.h>
50 #endif
51
52 /* loads a file and returns a pointer to it in memory. The file contains
53 * a 0 byte(sentinel) after len bytes - the length of the file. */
54 static int load_file(const char *fileName, char **data, size_t *len)
55 {
56 /* ensure returned length is always sane */
57 *len = 0;
58
59 FILE *pFile;
60 pFile = fopen(fileName, "rb");
61 if (pFile == NULL) {
62 LOG_ERROR("Can't open %s", fileName);
63 return ERROR_FAIL;
64 }
65 if (fseek(pFile, 0, SEEK_END) != 0) {
66 LOG_ERROR("Can't open %s", fileName);
67 fclose(pFile);
68 return ERROR_FAIL;
69 }
70 long fsize = ftell(pFile);
71 if (fsize == -1) {
72 LOG_ERROR("Can't open %s", fileName);
73 fclose(pFile);
74 return ERROR_FAIL;
75 }
76 *len = fsize;
77
78 if (fseek(pFile, 0, SEEK_SET) != 0) {
79 LOG_ERROR("Can't open %s", fileName);
80 fclose(pFile);
81 return ERROR_FAIL;
82 }
83 *data = malloc(*len + 1);
84 if (*data == NULL) {
85 LOG_ERROR("Can't open %s", fileName);
86 fclose(pFile);
87 return ERROR_FAIL;
88 }
89
90 if (fread(*data, 1, *len, pFile) != *len) {
91 fclose(pFile);
92 free(*data);
93 LOG_ERROR("Can't open %s", fileName);
94 return ERROR_FAIL;
95 }
96 fclose(pFile);
97
98 /* 0-byte after buffer (not included in *len) serves as a sentinel */
99 (*data)[*len] = 0;
100
101 return ERROR_OK;
102 }
103
104 COMMAND_HANDLER(handle_cat_command)
105 {
106 if (CMD_ARGC != 1)
107 return ERROR_COMMAND_SYNTAX_ERROR;
108
109 /* NOTE!!! we only have line printing capability so we print the entire file as a single
110 * line. */
111 char *data;
112 size_t len;
113
114 int retval = load_file(CMD_ARGV[0], &data, &len);
115 if (retval == ERROR_OK) {
116 command_print(CMD, "%s", data);
117 free(data);
118 } else
119 command_print(CMD, "%s not found", CMD_ARGV[0]);
120
121 return ERROR_OK;
122 }
123
124 COMMAND_HANDLER(handle_trunc_command)
125 {
126 if (CMD_ARGC != 1)
127 return ERROR_COMMAND_SYNTAX_ERROR;
128
129 FILE *config_file = NULL;
130 config_file = fopen(CMD_ARGV[0], "w");
131 if (config_file != NULL)
132 fclose(config_file);
133
134 return ERROR_OK;
135 }
136
137 #ifdef HAVE_MALLOC_H
138 COMMAND_HANDLER(handle_meminfo_command)
139 {
140 static int prev;
141 struct mallinfo info;
142
143 if (CMD_ARGC != 0)
144 return ERROR_COMMAND_SYNTAX_ERROR;
145
146 info = mallinfo();
147
148 if (prev > 0)
149 command_print(CMD, "Diff: %d", prev - info.fordblks);
150 prev = info.fordblks;
151
152 command_print(CMD, "Available ram: %d", info.fordblks);
153
154 return ERROR_OK;
155 }
156 #endif
157
158 COMMAND_HANDLER(handle_append_command)
159 {
160 if (CMD_ARGC < 1)
161 return ERROR_COMMAND_SYNTAX_ERROR;
162
163 int retval = ERROR_FAIL;
164 FILE *config_file = NULL;
165
166 config_file = fopen(CMD_ARGV[0], "a");
167 if (config_file != NULL) {
168 fseek(config_file, 0, SEEK_END);
169
170 unsigned i;
171 for (i = 1; i < CMD_ARGC; i++) {
172 if (fwrite(CMD_ARGV[i], 1, strlen(CMD_ARGV[i]),
173 config_file) != strlen(CMD_ARGV[i]))
174 break;
175 if (i != CMD_ARGC - 1) {
176 if (fwrite(" ", 1, 1, config_file) != 1)
177 break;
178 }
179 }
180 if ((i == CMD_ARGC) && (fwrite("\n", 1, 1, config_file) == 1))
181 retval = ERROR_OK;
182
183 fclose(config_file);
184 }
185
186 return retval;
187 }
188
189 COMMAND_HANDLER(handle_cp_command)
190 {
191 if (CMD_ARGC != 2)
192 return ERROR_COMMAND_SYNTAX_ERROR;
193
194 /* NOTE!!! we only have line printing capability so we print the entire file as a single
195 * line. */
196 char *data;
197 size_t len;
198
199 int retval = load_file(CMD_ARGV[0], &data, &len);
200 if (retval != ERROR_OK)
201 return retval;
202
203 FILE *f = fopen(CMD_ARGV[1], "wb");
204 if (f == NULL)
205 retval = ERROR_COMMAND_SYNTAX_ERROR;
206
207 size_t pos = 0;
208 for (;; ) {
209 size_t chunk = len - pos;
210 static const size_t maxChunk = 512 * 1024; /* ~1/sec */
211 if (chunk > maxChunk)
212 chunk = maxChunk;
213
214 if ((retval == ERROR_OK) && (fwrite(data + pos, 1, chunk, f) != chunk))
215 retval = ERROR_COMMAND_SYNTAX_ERROR;
216
217 if (retval != ERROR_OK)
218 break;
219
220 command_print(CMD, "%zu", len - pos);
221
222 pos += chunk;
223
224 if (pos == len)
225 break;
226 }
227
228 if (retval == ERROR_OK)
229 command_print(CMD, "Copied %s to %s", CMD_ARGV[0], CMD_ARGV[1]);
230 else
231 command_print(CMD, "copy failed");
232
233 free(data);
234 if (f != NULL)
235 fclose(f);
236
237 if (retval != ERROR_OK)
238 unlink(CMD_ARGV[1]);
239
240 return retval;
241 }
242
243 COMMAND_HANDLER(handle_rm_command)
244 {
245 if (CMD_ARGC != 1)
246 return ERROR_COMMAND_SYNTAX_ERROR;
247
248 bool del = false;
249 if (rmdir(CMD_ARGV[0]) == 0)
250 del = true;
251 else if (unlink(CMD_ARGV[0]) == 0)
252 del = true;
253
254 return del ? ERROR_OK : ERROR_FAIL;
255 }
256
257 static int ioutil_Jim_Command_ls(Jim_Interp *interp,
258 int argc,
259 Jim_Obj * const *argv)
260 {
261 if (argc != 2) {
262 Jim_WrongNumArgs(interp, 1, argv, "ls ?dir?");
263 return JIM_ERR;
264 }
265
266 const char *name = Jim_GetString(argv[1], NULL);
267
268 DIR *dirp = NULL;
269 dirp = opendir(name);
270 if (dirp == NULL)
271 return JIM_ERR;
272 Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
273
274 for (;; ) {
275 struct dirent *entry = NULL;
276 entry = readdir(dirp);
277 if (entry == NULL)
278 break;
279
280 if ((strcmp(".", entry->d_name) == 0) || (strcmp("..", entry->d_name) == 0))
281 continue;
282
283 Jim_ListAppendElement(interp, objPtr,
284 Jim_NewStringObj(interp, entry->d_name, strlen(entry->d_name)));
285 }
286 closedir(dirp);
287
288 Jim_SetResult(interp, objPtr);
289
290 return JIM_OK;
291 }
292
293 static int ioutil_Jim_Command_peek(Jim_Interp *interp,
294 int argc,
295 Jim_Obj *const *argv)
296 {
297 if (argc != 2) {
298 Jim_WrongNumArgs(interp, 1, argv, "peek ?address?");
299 return JIM_ERR;
300 }
301
302 long address;
303 if (Jim_GetLong(interp, argv[1], &address) != JIM_OK)
304 return JIM_ERR;
305
306 int value = *((volatile int *) address);
307
308 Jim_SetResult(interp, Jim_NewIntObj(interp, value));
309
310 return JIM_OK;
311 }
312
313 static int ioutil_Jim_Command_poke(Jim_Interp *interp,
314 int argc,
315 Jim_Obj *const *argv)
316 {
317 if (argc != 3) {
318 Jim_WrongNumArgs(interp, 1, argv, "poke ?address? ?value?");
319 return JIM_ERR;
320 }
321
322 long address;
323 if (Jim_GetLong(interp, argv[1], &address) != JIM_OK)
324 return JIM_ERR;
325 long value;
326 if (Jim_GetLong(interp, argv[2], &value) != JIM_OK)
327 return JIM_ERR;
328
329 *((volatile int *) address) = value;
330
331 return JIM_OK;
332 }
333
334 /* not so pretty code to fish out ip number*/
335 static int ioutil_Jim_Command_ip(Jim_Interp *interp, int argc,
336 Jim_Obj *const *argv)
337 {
338 #if !defined(__CYGWIN__)
339 Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
340
341 struct ifaddrs *ifa = NULL, *ifp = NULL;
342
343 if (getifaddrs(&ifp) < 0)
344 return JIM_ERR;
345
346 for (ifa = ifp; ifa; ifa = ifa->ifa_next) {
347 char ip[200];
348 socklen_t salen;
349
350 if (ifa->ifa_addr->sa_family == AF_INET)
351 salen = sizeof(struct sockaddr_in);
352 else if (ifa->ifa_addr->sa_family == AF_INET6)
353 salen = sizeof(struct sockaddr_in6);
354 else
355 continue;
356
357 if (getnameinfo(ifa->ifa_addr, salen, ip, sizeof(ip), NULL, 0,
358 NI_NUMERICHOST) < 0)
359 continue;
360
361 Jim_AppendString(interp, tclOutput, ip, strlen(ip));
362 break;
363
364 }
365
366 freeifaddrs(ifp);
367 #else
368 Jim_Obj *tclOutput = Jim_NewStringObj(interp, "fixme!!!", 0);
369 LOG_ERROR("NOT IMPLEMENTED!!!");
370 #endif
371 Jim_SetResult(interp, tclOutput);
372
373 return JIM_OK;
374 }
375
376 #ifdef HAVE_SYS_IOCTL_H
377 #ifdef SIOCGIFHWADDR
378 /* not so pretty code to fish out eth0 mac address */
379 static int ioutil_Jim_Command_mac(Jim_Interp *interp, int argc,
380 Jim_Obj *const *argv)
381 {
382 struct ifreq *ifr, *ifend;
383 struct ifreq ifreq;
384 struct ifconf ifc;
385 struct ifreq ifs[5];
386 int SockFD;
387
388 SockFD = socket(AF_INET, SOCK_DGRAM, 0);
389 if (SockFD < 0)
390 return JIM_ERR;
391
392 ifc.ifc_len = sizeof(ifs);
393 ifc.ifc_req = ifs;
394 if (ioctl(SockFD, SIOCGIFCONF, &ifc) < 0) {
395 close(SockFD);
396 return JIM_ERR;
397 }
398
399 ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
400 for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
401 /* if (ifr->ifr_addr.sa_family == AF_INET) */
402 {
403 if (strcmp("eth0", ifr->ifr_name) != 0)
404 continue;
405 strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name) - 1);
406 if (ioctl(SockFD, SIOCGIFHWADDR, &ifreq) < 0) {
407 close(SockFD);
408 return JIM_ERR;
409 }
410
411 close(SockFD);
412
413 Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
414
415 char buffer[256];
416 sprintf(buffer, "%02x-%02x-%02x-%02x-%02x-%02x",
417 ifreq.ifr_hwaddr.sa_data[0]&0xff,
418 ifreq.ifr_hwaddr.sa_data[1]&0xff,
419 ifreq.ifr_hwaddr.sa_data[2]&0xff,
420 ifreq.ifr_hwaddr.sa_data[3]&0xff,
421 ifreq.ifr_hwaddr.sa_data[4]&0xff,
422 ifreq.ifr_hwaddr.sa_data[5]&0xff);
423
424 Jim_AppendString(interp, tclOutput, buffer, strlen(buffer));
425
426 Jim_SetResult(interp, tclOutput);
427
428 return JIM_OK;
429 }
430 }
431 close(SockFD);
432
433 return JIM_ERR;
434
435 }
436 #endif
437 #endif
438
439 static const struct command_registration ioutil_command_handlers[] = {
440 {
441 .name = "cat",
442 .handler = handle_cat_command,
443 .mode = COMMAND_ANY,
444 .help = "display text file content",
445 .usage = "file_name",
446 },
447 {
448 .name = "trunc",
449 .handler = handle_trunc_command,
450 .mode = COMMAND_ANY,
451 .help = "truncate a file to zero length",
452 .usage = "file_name",
453 },
454 {
455 .name = "cp",
456 .handler = handle_cp_command,
457 .mode = COMMAND_ANY,
458 .help = "copy a file",
459 .usage = "src_file_name dst_file_name",
460 },
461 {
462 .name = "append_file",
463 .handler = handle_append_command,
464 .mode = COMMAND_ANY,
465 .help = "append a variable number of strings to a file",
466 .usage = "file_name [<string1>, [<string2>, ...]]",
467 },
468 #ifdef HAVE_MALLOC_H
469 {
470 .name = "meminfo",
471 .handler = handle_meminfo_command,
472 .mode = COMMAND_ANY,
473 .help = "display free heap space",
474 .usage = "",
475 },
476 #endif
477 {
478 .name = "rm",
479 .mode = COMMAND_ANY,
480 .handler = handle_rm_command,
481 .help = "remove a directory or file",
482 .usage = "file_name",
483 },
484
485 /*
486 * Peek and poke are security holes -- they manipulate
487 * server-internal addresses.
488 */
489
490 /* jim handlers */
491 {
492 .name = "peek",
493 .mode = COMMAND_ANY,
494 .jim_handler = ioutil_Jim_Command_peek,
495 .help = "peek at a memory address",
496 .usage = "address",
497 },
498 {
499 .name = "poke",
500 .mode = COMMAND_ANY,
501 .jim_handler = ioutil_Jim_Command_poke,
502 .help = "poke at a memory address",
503 .usage = "address value",
504 },
505 {
506 .name = "ls",
507 .mode = COMMAND_ANY,
508 .jim_handler = ioutil_Jim_Command_ls,
509 .help = "show a listing of files",
510 .usage = "dirname",
511 },
512 #ifdef HAVE_SYS_IOCTL_H
513 #ifdef SIOCGIFHWADDR
514 {
515 .name = "mac",
516 .mode = COMMAND_ANY,
517 .jim_handler = ioutil_Jim_Command_mac,
518 .help = "show MAC address",
519 },
520 #endif
521 #endif
522 {
523 .name = "ip",
524 .jim_handler = ioutil_Jim_Command_ip,
525 .mode = COMMAND_ANY,
526 .help = "show IP address",
527 },
528 COMMAND_REGISTRATION_DONE
529 };
530
531 int ioutil_init(struct command_context *cmd_ctx)
532 {
533 return register_commands(cmd_ctx, NULL, ioutil_command_handlers);
534 }

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)