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