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