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