sync up to tap_xxx rename + add with-ioutil for standalone openocd implemetnations
[fw/openocd] / src / helper / ioutil.c
1 /***************************************************************************\r
2  *   Copyright (C) 2007-2008 by Ã˜yvind Harboe                              *\r
3  *                                                                         *\r
4  *   This program is free software; you can redistribute it and/or modify  *\r
5  *   it under the terms of the GNU General Public License as published by  *\r
6  *   the Free Software Foundation; either version 2 of the License, or     *\r
7  *   (at your option) any later version.                                   *\r
8  *                                                                         *\r
9  *   This program is distributed in the hope that it will be useful,       *\r
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
12  *   GNU General Public License for more details.                          *\r
13  *                                                                         *\r
14  *   You should have received a copy of the GNU General Public License     *\r
15  *   along with this program; if not, write to the                         *\r
16  *   Free Software Foundation, Inc.,                                       *\r
17  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
18  ***************************************************************************/\r
19 \r
20 /* this file contains various functionality useful to standalone systems */\r
21 \r
22 #ifdef HAVE_CONFIG_H\r
23 #include "config.h"\r
24 #endif\r
25 \r
26 #include "log.h"\r
27 #include "types.h"\r
28 #include "configuration.h"\r
29 #include "target.h"\r
30 \r
31 #include "command.h"\r
32 \r
33 #include <time_support.h>\r
34 #include <sys/time.h>\r
35 #include <sys/types.h>\r
36 #include <strings.h>\r
37 #include <stdio.h>\r
38 #include <stdlib.h>\r
39 #include <string.h>\r
40 #include <unistd.h>\r
41 #if !BUILD_ECOSBOARD\r
42 #include <malloc.h>\r
43 #endif\r
44 #include <errno.h>\r
45 \r
46 \r
47 #include <fcntl.h>\r
48 #include <sys/stat.h>\r
49 #include <dirent.h>\r
50 #include <netinet/tcp.h>\r
51 #include <sys/ioctl.h>\r
52 #include <sys/socket.h>\r
53 #include <netinet/in.h>\r
54 #include <net/if.h>\r
55 #include <arpa/inet.h>\r
56 #include <sys/types.h>\r
57 #include <sys/socket.h>\r
58 #include <netdb.h>\r
59 #include <netinet/in.h>\r
60 #include <unistd.h>\r
61 #include <arpa/inet.h>\r
62 #include <stdio.h>\r
63 #include <string.h>\r
64 \r
65 \r
66 #include <unistd.h>\r
67 #include <stdio.h>\r
68 \r
69 int handle_rm_command(struct command_context_s *cmd_ctx, char *cmd,\r
70                 char **args, int argc)\r
71 {\r
72         if (argc != 1)\r
73         {\r
74                 command_print(cmd_ctx, "rm <filename>");\r
75                 return ERROR_INVALID_ARGUMENTS;\r
76         }\r
77 \r
78         if (unlink(args[0]) != 0)\r
79         {\r
80                 command_print(cmd_ctx, "failed: %d", errno);\r
81         }\r
82 \r
83         return ERROR_OK;\r
84 }\r
85 \r
86 \r
87 /* loads a file and returns a pointer to it in memory. The file contains\r
88  * a 0 byte(sentinel) after len bytes - the length of the file. */\r
89 int loadFile(const char *fileName, void **data, int *len)\r
90 {\r
91         FILE * pFile;\r
92         pFile = fopen(fileName,"rb");\r
93         if (pFile==NULL)\r
94         {\r
95                 LOG_ERROR("Can't open %s\n", fileName);\r
96                 return ERROR_FAIL;\r
97         }\r
98         if (fseek(pFile, 0, SEEK_END)!=0)\r
99         {\r
100                 LOG_ERROR("Can't open %s\n", fileName);\r
101                 fclose(pFile);\r
102                 return ERROR_FAIL;\r
103         }\r
104         *len=ftell(pFile);\r
105         if (*len==-1)\r
106         {\r
107                 LOG_ERROR("Can't open %s\n", fileName);\r
108                 fclose(pFile);\r
109                 return ERROR_FAIL;\r
110         }\r
111 \r
112         if (fseek(pFile, 0, SEEK_SET)!=0)\r
113         {\r
114                 LOG_ERROR("Can't open %s\n", fileName);\r
115                 fclose(pFile);\r
116                 return ERROR_FAIL;\r
117         }\r
118         *data=malloc(*len+1);\r
119         if (*data==NULL)\r
120         {\r
121                 LOG_ERROR("Can't open %s\n", fileName);\r
122                 fclose(pFile);\r
123                 return ERROR_FAIL;\r
124         }\r
125 \r
126         if (fread(*data, 1, *len, pFile)!=*len)\r
127         {\r
128                 fclose(pFile);\r
129                 free(*data);\r
130                 LOG_ERROR("Can't open %s\n", fileName);\r
131                 return ERROR_FAIL;\r
132         }\r
133         fclose(pFile);\r
134         *(((char *)(*data))+*len)=0; /* sentinel */\r
135 \r
136         return ERROR_OK;\r
137 \r
138 \r
139 \r
140 }\r
141 \r
142 \r
143 \r
144 int handle_cat_command(struct command_context_s *cmd_ctx, char *cmd,\r
145                 char **args, int argc)\r
146 {\r
147         if (argc != 1)\r
148         {\r
149                 command_print(cmd_ctx, "cat <filename>");\r
150                 return ERROR_INVALID_ARGUMENTS;\r
151         }\r
152 \r
153         // NOTE!!! we only have line printing capability so we print the entire file as a single line.\r
154         void *data;\r
155         int len;\r
156 \r
157         int retval = loadFile(args[0], &data, &len);\r
158         if (retval == ERROR_OK)\r
159         {\r
160                 command_print(cmd_ctx, "%s", data);\r
161                 free(data);\r
162         }\r
163         else\r
164         {\r
165                 command_print(cmd_ctx, "%s not found %d", args[0], retval);\r
166         }\r
167 \r
168         return ERROR_OK;\r
169 }\r
170 int handle_trunc_command(struct command_context_s *cmd_ctx, char *cmd,\r
171                 char **args, int argc)\r
172 {\r
173         if (argc != 1)\r
174         {\r
175                 command_print(cmd_ctx, "trunc <filename>");\r
176                 return ERROR_INVALID_ARGUMENTS;\r
177         }\r
178 \r
179         FILE *config_file = NULL;\r
180         config_file = fopen(args[0], "w");\r
181         if (config_file != NULL)\r
182                 fclose(config_file);\r
183 \r
184         return ERROR_OK;\r
185 }\r
186 \r
187 \r
188 int handle_meminfo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
189 {\r
190         static int prev = 0;\r
191         struct mallinfo info;\r
192 \r
193         if (argc != 0)\r
194         {\r
195                 command_print(cmd_ctx, "meminfo");\r
196                 return ERROR_INVALID_ARGUMENTS;\r
197         }\r
198 \r
199         info = mallinfo();\r
200 \r
201         if (prev > 0)\r
202         {\r
203                 command_print(cmd_ctx, "Diff:            %d", prev - info.fordblks);\r
204         }\r
205         prev = info.fordblks;\r
206 \r
207         command_print(cmd_ctx, "Available ram:   %d", info.fordblks );\r
208 \r
209         return ERROR_OK;\r
210 }\r
211 \r
212 \r
213 int handle_append_command(struct command_context_s *cmd_ctx, char *cmd,\r
214                 char **args, int argc)\r
215 {\r
216         if (argc < 1)\r
217         {\r
218                 command_print(cmd_ctx,\r
219                                 "append <filename> [<string1>, [<string2>, ...]]");\r
220                 return ERROR_INVALID_ARGUMENTS;\r
221         }\r
222 \r
223         FILE *config_file = NULL;\r
224         config_file = fopen(args[0], "a");\r
225         if (config_file != NULL)\r
226         {\r
227                 int i;\r
228                 fseek(config_file, 0, SEEK_END);\r
229 \r
230                 for (i = 1; i < argc; i++)\r
231                 {\r
232                         fwrite(args[i], strlen(args[i]), 1, config_file);\r
233                         if (i != argc - 1)\r
234                         {\r
235                                 fwrite(" ", 1, 1, config_file);\r
236                         }\r
237                 }\r
238                 fwrite("\n", 1, 1, config_file);\r
239                 fclose(config_file);\r
240         }\r
241 \r
242         return ERROR_OK;\r
243 }\r
244 \r
245 \r
246 \r
247 int handle_cp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
248 {\r
249         if (argc != 2)\r
250         {\r
251                 return ERROR_INVALID_ARGUMENTS;\r
252         }\r
253 \r
254         // NOTE!!! we only have line printing capability so we print the entire file as a single line.\r
255         void *data;\r
256         int len;\r
257 \r
258         int retval = loadFile(args[0], &data, &len);\r
259         if (retval != ERROR_OK)\r
260                 return retval;\r
261 \r
262         FILE *f = fopen(args[1], "wb");\r
263         if (f == NULL)\r
264                 retval = ERROR_INVALID_ARGUMENTS;\r
265 \r
266         int pos = 0;\r
267         for (;;)\r
268         {\r
269                 int chunk = len - pos;\r
270                 static const int maxChunk = 512 * 1024; // ~1/sec\r
271                 if (chunk > maxChunk)\r
272                 {\r
273                         chunk = maxChunk;\r
274                 }\r
275 \r
276                 if ((retval==ERROR_OK)&&(fwrite(((char *)data)+pos, 1, chunk, f)!=chunk))\r
277                         retval = ERROR_INVALID_ARGUMENTS;\r
278 \r
279                 if (retval != ERROR_OK)\r
280                 {\r
281                         break;\r
282                 }\r
283 \r
284                 command_print(cmd_ctx, "%d", len - pos);\r
285 \r
286                 pos += chunk;\r
287 \r
288                 if (pos == len)\r
289                         break;\r
290         }\r
291 \r
292         if (retval == ERROR_OK)\r
293         {\r
294                 command_print(cmd_ctx, "Copied %s to %s", args[0], args[1]);\r
295         } else\r
296         {\r
297                 command_print(cmd_ctx, "Failed: %d", retval);\r
298         }\r
299 \r
300         if (data != NULL)\r
301                 free(data);\r
302         if (f != NULL)\r
303                 fclose(f);\r
304 \r
305         if (retval != ERROR_OK)\r
306                 unlink(args[1]);\r
307 \r
308         return retval;\r
309 }\r
310 \r
311 \r
312 \r
313 \r
314 #define SHOW_RESULT(a, b) LOG_ERROR(#a " failed %d\n", (int)b)\r
315 \r
316 #define IOSIZE 512\r
317 void copyfile(char *name2, char *name1)\r
318 {\r
319 \r
320         int err;\r
321         char buf[IOSIZE];\r
322         int fd1, fd2;\r
323         ssize_t done, wrote;\r
324 \r
325         fd1 = open(name1, O_WRONLY | O_CREAT);\r
326         if (fd1 < 0)\r
327                 SHOW_RESULT( open, fd1 );\r
328 \r
329         fd2 = open(name2, O_RDONLY);\r
330         if (fd2 < 0)\r
331                 SHOW_RESULT( open, fd2 );\r
332 \r
333         for (;;)\r
334         {\r
335                 done = read(fd2, buf, IOSIZE );\r
336                 if (done < 0)\r
337                 {\r
338                         SHOW_RESULT( read, done );\r
339                         break;\r
340                 }\r
341 \r
342         if( done == 0 ) break;\r
343 \r
344                 wrote = write(fd1, buf, done);\r
345         if( wrote != done ) SHOW_RESULT( write, wrote );\r
346 \r
347         if( wrote != done ) break;\r
348         }\r
349 \r
350         err = close(fd1);\r
351     if( err < 0 ) SHOW_RESULT( close, err );\r
352 \r
353         err = close(fd2);\r
354     if( err < 0 ) SHOW_RESULT( close, err );\r
355 \r
356 }\r
357 \r
358 /* utility fn to copy a directory */\r
359 void copydir(char *name, char *destdir)\r
360 {\r
361         int err;\r
362         DIR *dirp;\r
363 \r
364         dirp = opendir(destdir);\r
365         if (dirp==NULL)\r
366         {\r
367                 mkdir(destdir, 0777);\r
368         } else\r
369         {\r
370                 err = closedir(dirp);\r
371         }\r
372 \r
373         dirp = opendir(name);\r
374     if( dirp == NULL ) SHOW_RESULT( opendir, -1 );\r
375 \r
376         for (;;)\r
377         {\r
378                 struct dirent *entry = readdir(dirp);\r
379 \r
380                 if (entry == NULL)\r
381                         break;\r
382 \r
383                 if (strcmp(entry->d_name, ".") == 0)\r
384                         continue;\r
385                 if (strcmp(entry->d_name, "..") == 0)\r
386                         continue;\r
387 \r
388                 int isDir = 0;\r
389                 struct stat buf;\r
390                 char fullPath[PATH_MAX];\r
391                 strncpy(fullPath, name, PATH_MAX);\r
392                 strcat(fullPath, "/");\r
393                 strncat(fullPath, entry->d_name, PATH_MAX - strlen(fullPath));\r
394 \r
395                 if (stat(fullPath, &buf) == -1)\r
396                 {\r
397                         LOG_ERROR("unable to read status from %s", fullPath);\r
398                         break;\r
399                 }\r
400                 isDir = S_ISDIR(buf.st_mode) != 0;\r
401 \r
402                 if (isDir)\r
403                         continue;\r
404 \r
405                 //        diag_printf("<INFO>: entry %14s",entry->d_name);\r
406                 char fullname[PATH_MAX];\r
407                 char fullname2[PATH_MAX];\r
408 \r
409                 strcpy(fullname, name);\r
410                 strcat(fullname, "/");\r
411                 strcat(fullname, entry->d_name);\r
412 \r
413                 strcpy(fullname2, destdir);\r
414                 strcat(fullname2, "/");\r
415                 strcat(fullname2, entry->d_name);\r
416                 //        diag_printf("from %s to %s\n", fullname, fullname2);\r
417                 copyfile(fullname, fullname2);\r
418 \r
419                 //       diag_printf("\n");\r
420         }\r
421 \r
422         err = closedir(dirp);\r
423     if( err < 0 ) SHOW_RESULT( stat, err );\r
424 }\r
425 \r
426 \r
427 \r
428 \r
429 static int\r
430 zylinjtag_Jim_Command_rm(Jim_Interp *interp,\r
431                                    int argc,\r
432                 Jim_Obj * const *argv)\r
433 {\r
434         int del;\r
435         if (argc != 2)\r
436         {\r
437                 Jim_WrongNumArgs(interp, 1, argv, "rm ?dirorfile?");\r
438                 return JIM_ERR;\r
439         }\r
440 \r
441         del = 0;\r
442         if (unlink(Jim_GetString(argv[1], NULL)) == 0)\r
443                 del = 1;\r
444         if (rmdir(Jim_GetString(argv[1], NULL)) == 0)\r
445                 del = 1;\r
446 \r
447         return del ? JIM_OK : JIM_ERR;\r
448 }\r
449 \r
450 \r
451 static int\r
452 zylinjtag_Jim_Command_ls(Jim_Interp *interp,\r
453                                    int argc,\r
454                 Jim_Obj * const *argv)\r
455 {\r
456         if (argc != 2)\r
457         {\r
458                 Jim_WrongNumArgs(interp, 1, argv, "ls ?dir?");\r
459                 return JIM_ERR;\r
460         }\r
461 \r
462         char *name = (char*) Jim_GetString(argv[1], NULL);\r
463 \r
464         DIR *dirp = NULL;\r
465         dirp = opendir(name);\r
466         if (dirp == NULL)\r
467         {\r
468                 return JIM_ERR;\r
469         }\r
470         Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);\r
471 \r
472         for (;;)\r
473         {\r
474                 struct dirent *entry = NULL;\r
475                 entry = readdir(dirp);\r
476                 if (entry == NULL)\r
477                         break;\r
478 \r
479                 if ((strcmp(".", entry->d_name)==0)||(strcmp("..", entry->d_name)==0))\r
480                         continue;\r
481 \r
482         Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, entry->d_name, strlen(entry->d_name)));\r
483         }\r
484         closedir(dirp);\r
485 \r
486         Jim_SetResult(interp, objPtr);\r
487 \r
488         return JIM_OK;\r
489 }\r
490 \r
491 int handle_peek_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
492 {\r
493         if (argc != 1)\r
494         {\r
495                 return ERROR_COMMAND_SYNTAX_ERROR;\r
496         }\r
497         volatile int *address=(volatile int *)strtoul(args[0], NULL, 0);\r
498         int value=*address;\r
499         command_print(cmd_ctx, "0x%x : 0x%x", address, value);\r
500         return ERROR_OK;\r
501 }\r
502 \r
503 int handle_poke_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
504 {\r
505         if (argc != 2)\r
506         {\r
507                 return ERROR_INVALID_ARGUMENTS;\r
508         }\r
509         volatile int *address=(volatile int *)strtoul(args[0], NULL, 0);\r
510         int value=strtoul(args[1], NULL, 0);\r
511         *address=value;\r
512         return ERROR_OK;\r
513 }\r
514 \r
515 static int\r
516 zylinjtag_Jim_Command_peek(Jim_Interp *interp,\r
517                                    int argc,\r
518                 Jim_Obj * const *argv)\r
519 {\r
520         if (argc != 2)\r
521         {\r
522                 Jim_WrongNumArgs(interp, 1, argv, "peek ?address?");\r
523                 return JIM_ERR;\r
524         }\r
525 \r
526         long address;\r
527         if (Jim_GetLong(interp, argv[1], &address) != JIM_OK)\r
528                 return JIM_ERR;\r
529 \r
530         int value = *((volatile int *) address);\r
531 \r
532         Jim_SetResult(interp, Jim_NewIntObj(interp, value));\r
533 \r
534         return JIM_OK;\r
535 }\r
536 \r
537 static int\r
538 zylinjtag_Jim_Command_poke(Jim_Interp *interp,\r
539                                    int argc,\r
540                 Jim_Obj * const *argv)\r
541 {\r
542         if (argc != 3)\r
543         {\r
544                 Jim_WrongNumArgs(interp, 1, argv, "poke ?address? ?value?");\r
545                 return JIM_ERR;\r
546         }\r
547 \r
548         long address;\r
549         if (Jim_GetLong(interp, argv[1], &address) != JIM_OK)\r
550                 return JIM_ERR;\r
551         long value;\r
552         if (Jim_GetLong(interp, argv[2], &value) != JIM_OK)\r
553                 return JIM_ERR;\r
554 \r
555         *((volatile int *) address) = value;\r
556 \r
557         return JIM_OK;\r
558 }\r
559 \r
560 int ioutil_init(struct command_context_s *cmd_ctx)\r
561 {\r
562         register_command(cmd_ctx, NULL, "rm", handle_rm_command, COMMAND_ANY,\r
563                         "remove file");\r
564 \r
565         register_command(cmd_ctx, NULL, "cat", handle_cat_command, COMMAND_ANY,\r
566                         "display file content");\r
567 \r
568         register_command(cmd_ctx, NULL, "trunc", handle_trunc_command, COMMAND_ANY,\r
569                         "truncate a file to 0 size");\r
570 \r
571         register_command(cmd_ctx, NULL, "cp", handle_cp_command,\r
572                                          COMMAND_ANY, "copy a file <from> <to>");\r
573 \r
574         register_command(cmd_ctx, NULL, "append_file", handle_append_command,\r
575                         COMMAND_ANY, "append a variable number of strings to a file");\r
576 \r
577         register_command(cmd_ctx, NULL, "meminfo", handle_meminfo_command,\r
578                         COMMAND_ANY, "display available ram memory");\r
579 \r
580     Jim_CreateCommand(interp, "rm", zylinjtag_Jim_Command_rm, NULL, NULL);\r
581 \r
582     Jim_CreateCommand(interp, "peek", zylinjtag_Jim_Command_peek, NULL, NULL);\r
583     Jim_CreateCommand(interp, "poke", zylinjtag_Jim_Command_poke, NULL, NULL);\r
584     Jim_CreateCommand(interp, "ls", zylinjtag_Jim_Command_ls, NULL, NULL);\r
585 \r
586 \r
587     return ERROR_OK;\r
588 }\r
589 \r
590 \r