/**************************************************************************** * apps/nshlib/nsh_netcmds.c * * Copyright (C) 2007-2012, 2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name NuttX nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #ifdef CONFIG_NET #include /* Needed for open */ #include #include #include #include #include #include #include #include /* Needed for open */ #include /* Needed for basename */ #include #include #include #include #include #include #include #include #include #include #include #include #if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \ !defined(CONFIG_DISABLE_SIGNALS) # include # include #endif #if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0 # include # include #endif #if defined(CONFIG_NET_TCP) && CONFIG_NFILE_DESCRIPTORS > 0 # ifndef CONFIG_NSH_DISABLE_WGET # include # include # endif #endif #if defined(CONFIG_NSH_DHCPC) || defined(CONFIG_NSH_DNS) # ifdef CONFIG_HAVE_GETHOSTBYNAME # include # else # include # endif # include #endif #include "nsh.h" #include "nsh_console.h" /**************************************************************************** * Definitions ****************************************************************************/ /* Size of the ECHO data */ #define DEFAULT_PING_DATALEN 56 /* Get the larger value */ #ifndef MAX # define MAX(a,b) (a > b ? a : b) #endif /**************************************************************************** * Private Types ****************************************************************************/ #if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0 struct tftpc_args_s { bool binary; /* true:binary ("octet") false:text ("netascii") */ bool allocated; /* true: destpath is allocated */ char *destpath; /* Path at destination */ const char *srcpath; /* Path at src */ in_addr_t ipaddr; /* Host IP address */ }; #endif /**************************************************************************** * Private Function Prototypes ****************************************************************************/ /**************************************************************************** * Private Data ****************************************************************************/ #if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \ !defined(CONFIG_DISABLE_SIGNALS) static uint16_t g_pingid = 0; #endif /**************************************************************************** * Public Data ****************************************************************************/ /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: ping_newid ****************************************************************************/ #if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \ !defined(CONFIG_DISABLE_SIGNALS) static inline uint16_t ping_newid(void) { irqstate_t save = irqsave(); uint16_t ret = ++g_pingid; irqrestore(save); return ret; } #endif /**************************************************************************** * Name: net_statistics ****************************************************************************/ #if defined(CONFIG_NET_STATISTICS) && !defined(CONFIG_NSH_DISABLE_IFCONFIG) static inline void net_statistics(FAR struct nsh_vtbl_s *vtbl) { nsh_output(vtbl, " IP "); #ifdef CONFIG_NET_TCP nsh_output(vtbl, " TCP"); #endif #ifdef CONFIG_NET_UDP nsh_output(vtbl, " UDP"); #endif #ifdef CONFIG_NET_ICMP nsh_output(vtbl, " ICMP"); #endif nsh_output(vtbl, "\n"); /* Received packets */ nsh_output(vtbl, "Received %04x", g_netstats.ip.recv); #ifdef CONFIG_NET_TCP nsh_output(vtbl, " %04x", g_netstats.tcp.recv); #endif #ifdef CONFIG_NET_UDP nsh_output(vtbl, " %04x", g_netstats.udp.recv); #endif #ifdef CONFIG_NET_ICMP nsh_output(vtbl, " %04x", g_netstats.icmp.recv); #endif nsh_output(vtbl, "\n"); /* Dropped packets */ nsh_output(vtbl, "Dropped %04x", g_netstats.ip.drop); #ifdef CONFIG_NET_TCP nsh_output(vtbl, " %04x", g_netstats.tcp.drop); #endif #ifdef CONFIG_NET_UDP nsh_output(vtbl, " %04x", g_netstats.udp.drop); #endif #ifdef CONFIG_NET_ICMP nsh_output(vtbl, " %04x", g_netstats.icmp.drop); #endif nsh_output(vtbl, "\n"); nsh_output(vtbl, " IP VHL: %04x HBL: %04x\n", g_netstats.ip.vhlerr, g_netstats.ip.hblenerr); nsh_output(vtbl, " LBL: %04x Frg: %04x\n", g_netstats.ip.lblenerr, g_netstats.ip.fragerr); nsh_output(vtbl, " Checksum %04x",g_netstats.ip.chkerr); #ifdef CONFIG_NET_TCP nsh_output(vtbl, " %04x", g_netstats.tcp.chkerr); #endif #ifdef CONFIG_NET_UDP nsh_output(vtbl, " %04x", g_netstats.udp.chkerr); #endif #ifdef CONFIG_NET_ICMP nsh_output(vtbl, " ----"); #endif nsh_output(vtbl, "\n"); #ifdef CONFIG_NET_TCP nsh_output(vtbl, " TCP ACK: %04x SYN: %04x\n", g_netstats.tcp.ackerr, g_netstats.tcp.syndrop); nsh_output(vtbl, " RST: %04x %04x\n", g_netstats.tcp.rst, g_netstats.tcp.synrst); #endif nsh_output(vtbl, " Type %04x", g_netstats.ip.protoerr); #ifdef CONFIG_NET_TCP nsh_output(vtbl, " ----"); #endif #ifdef CONFIG_NET_UDP nsh_output(vtbl, " ----"); #endif #ifdef CONFIG_NET_ICMP nsh_output(vtbl, " %04x", g_netstats.icmp.typeerr); #endif nsh_output(vtbl, "\n"); /* Sent packets */ nsh_output(vtbl, "Sent ----", g_netstats.ip.sent); #ifdef CONFIG_NET_TCP nsh_output(vtbl, " %04x", g_netstats.tcp.sent); #endif #ifdef CONFIG_NET_UDP nsh_output(vtbl, " %04x", g_netstats.udp.sent); #endif #ifdef CONFIG_NET_ICMP nsh_output(vtbl, " %04x", g_netstats.icmp.sent); #endif nsh_output(vtbl, "\n"); #ifdef CONFIG_NET_TCP nsh_output(vtbl, " Rexmit ---- %04x", g_netstats.tcp.rexmit); #ifdef CONFIG_NET_UDP nsh_output(vtbl, " ----"); #endif #ifdef CONFIG_NET_ICMP nsh_output(vtbl, " ----"); #endif nsh_output(vtbl, "\n"); #endif nsh_output(vtbl, "\n"); } #else # define net_statistics(vtbl) #endif /**************************************************************************** * Name: ifconfig_callback ****************************************************************************/ int ifconfig_callback(FAR struct net_driver_s *dev, void *arg) { struct nsh_vtbl_s *vtbl = (struct nsh_vtbl_s*)arg; struct in_addr addr; uint8_t iff; const char *status; int ret; ret = netlib_getifstatus(dev->d_ifname, &iff); if (ret != OK) { nsh_output(vtbl, "\tGet %s interface flags error: %d\n", dev->d_ifname, ret); } if (iff & IFF_RUNNING) { status = "RUNNING"; } else if (iff & IFF_UP) { status = "UP"; } else { status = "DOWN"; } #ifdef CONFIG_NET_ETHERNET /* REVISIT: How will we handle Ethernet and SLIP networks together? */ nsh_output(vtbl, "%s\tHWaddr %s at %s\n", dev->d_ifname, ether_ntoa(&dev->d_mac), status); #endif addr.s_addr = dev->d_ipaddr; nsh_output(vtbl, "\tIPaddr:%s ", inet_ntoa(addr)); addr.s_addr = dev->d_draddr; nsh_output(vtbl, "DRaddr:%s ", inet_ntoa(addr)); addr.s_addr = dev->d_netmask; nsh_output(vtbl, "Mask:%s\n", inet_ntoa(addr)); #if defined(CONFIG_NSH_DHCPC) || defined(CONFIG_NSH_DNS) dns_getserver(&addr); nsh_output(vtbl, "\tDNSaddr:%s\n", inet_ntoa(addr)); #endif nsh_output(vtbl, "\n"); return OK; } /**************************************************************************** * Name: tftpc_parseargs ****************************************************************************/ #if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0 int tftpc_parseargs(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv, struct tftpc_args_s *args) { FAR const char *fmt = g_fmtarginvalid; bool badarg = false; int option; /* Get the ping options */ memset(args, 0, sizeof(struct tftpc_args_s)); while ((option = getopt(argc, argv, ":bnf:h:")) != ERROR) { switch (option) { case 'b': args->binary = true; break; case 'n': args->binary = false; break; case 'f': args->destpath = optarg; break; case 'h': if (!netlib_ipaddrconv(optarg, (FAR unsigned char*)&args->ipaddr)) { nsh_output(vtbl, g_fmtarginvalid, argv[0]); badarg = true; } break; case ':': nsh_output(vtbl, g_fmtargrequired, argv[0]); badarg = true; break; case '?': default: nsh_output(vtbl, g_fmtarginvalid, argv[0]); badarg = true; break; } } /* If a bad argument was encountered, then return without processing the command */ if (badarg) { return ERROR; } /* There should be exactly one parameter left on the command-line */ if (optind == argc-1) { args->srcpath = argv[optind]; } /* optind == argc means that there is nothing left on the command-line */ else if (optind >= argc) { fmt = g_fmtargrequired; goto errout; } /* optind < argc-1 means that there are too many arguments on the * command-line */ else { fmt = g_fmttoomanyargs; goto errout; } /* The HOST IP address is also required */ if (!args->ipaddr) { fmt = g_fmtargrequired; goto errout; } /* If the destpath was not provided, then we have do a little work. */ if (!args->destpath) { char *tmp1; char *tmp2; /* Copy the srcpath... baseanme might modify it */ fmt = g_fmtcmdoutofmemory; tmp1 = strdup(args->srcpath); if (!tmp1) { goto errout; } /* Get the basename of the srcpath */ tmp2 = basename(tmp1); if (!tmp2) { free(tmp1); goto errout; } /* Use that basename as the destpath */ args->destpath = strdup(tmp2); free(tmp1); if (!args->destpath) { goto errout; } args->allocated = true; } return OK; errout: nsh_output(vtbl, fmt, argv[0]); return ERROR; } #endif /**************************************************************************** * Name: wget_callback ****************************************************************************/ #if defined(CONFIG_NET_TCP) && CONFIG_NFILE_DESCRIPTORS > 0 #ifndef CONFIG_NSH_DISABLE_WGET static void wget_callback(FAR char **buffer, int offset, int datend, FAR int *buflen, FAR void *arg) { (void)write((int)arg, &((*buffer)[offset]), datend - offset); } #endif #endif /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: cmd_get ****************************************************************************/ #if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0 #ifndef CONFIG_NSH_DISABLE_GET int cmd_get(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { struct tftpc_args_s args; char *fullpath; /* Parse the input parameter list */ if (tftpc_parseargs(vtbl, argc, argv, &args) != OK) { return ERROR; } /* Get the full path to the local file */ fullpath = nsh_getfullpath(vtbl, args.destpath); /* Then perform the TFTP get operation */ if (tftpget(args.srcpath, fullpath, args.ipaddr, args.binary) != OK) { nsh_output(vtbl, g_fmtcmdfailed, argv[0], "tftpget", NSH_ERRNO); } /* Release any allocated memory */ if (args.allocated) { free(args.destpath); } free(fullpath); return OK; } #endif #endif /**************************************************************************** * Name: cmd_ifup ****************************************************************************/ #ifndef CONFIG_NSH_DISABLE_IFUPDOWN int cmd_ifup(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { FAR char *intf = NULL; int ret; if (argc != 2) { nsh_output(vtbl, "Please select nic_name:\n"); netdev_foreach(ifconfig_callback, vtbl); return OK; } intf = argv[1]; ret = netlib_ifup(intf); nsh_output(vtbl, "ifup %s...%s\n", intf, (ret == OK) ? "OK" : "Failed"); return ret; } #endif /**************************************************************************** * Name: cmd_ifdown ****************************************************************************/ #ifndef CONFIG_NSH_DISABLE_IFUPDOWN int cmd_ifdown(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { FAR char *intf = NULL; int ret; if (argc != 2) { nsh_output(vtbl, "Please select nic_name:\n"); netdev_foreach(ifconfig_callback, vtbl); return OK; } intf = argv[1]; ret = netlib_ifdown(intf); nsh_output(vtbl, "ifdown %s...%s\n", intf, (ret == OK) ? "OK" : "Failed"); return ret; } #endif /**************************************************************************** * Name: cmd_ifconfig ****************************************************************************/ #ifndef CONFIG_NSH_DISABLE_IFCONFIG int cmd_ifconfig(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { struct in_addr addr; in_addr_t gip; int i; FAR char *intf = NULL; FAR char *hostip = NULL; FAR char *gwip = NULL; FAR char *mask = NULL; FAR char *tmp = NULL; #ifdef CONFIG_NET_ETHERNET FAR char *hw = NULL; #endif #if defined(CONFIG_NSH_DHCPC) || defined(CONFIG_NSH_DNS) FAR char *dns = NULL; #endif bool badarg = false; uint8_t mac[IFHWADDRLEN]; #if defined(CONFIG_NSH_DHCPC) FAR void *handle; #endif /* With one or no arguments, ifconfig simply shows the status of ethernet * device: * * ifconfig * ifconfig [nic_name] */ if (argc <= 2) { netdev_foreach(ifconfig_callback, vtbl); net_statistics(vtbl); return OK; } /* If both the network interface name and an IP address are supplied as * arguments, then ifconfig will set the address of the Ethernet device: * * ifconfig nic_name ip_address */ if (argc > 2) { for (i = 0; i < argc; i++) { if (i == 1) { intf = argv[i]; } else if (i == 2) { hostip = argv[i]; } else { tmp = argv[i]; if (!strcmp(tmp, "dr") || !strcmp(tmp, "gw") || !strcmp(tmp, "gateway")) { if (argc-1 >= i+1) { gwip = argv[i+1]; i++; } else { badarg = true; } } else if (!strcmp(tmp, "netmask")) { if (argc-1 >= i+1) { mask = argv[i+1]; i++; } else { badarg = true; } } #ifdef CONFIG_NET_ETHERNET /* REVISIT: How will we handle Ethernet and SLIP networks together? */ else if (!strcmp(tmp, "hw")) { if (argc-1>=i+1) { hw = argv[i+1]; i++; badarg = !netlib_hwmacconv(hw, mac); } else { badarg = true; } } #endif #if defined(CONFIG_NSH_DHCPC) || defined(CONFIG_NSH_DNS) else if (!strcmp(tmp, "dns")) { if (argc-1 >= i+1) { dns = argv[i+1]; i++; } else { badarg = true; } } #endif } } } if (badarg) { nsh_output(vtbl, g_fmtargrequired, argv[0]); return ERROR; } #ifdef CONFIG_NET_ETHERNET /* Set Hardware Ethernet MAC address */ /* REVISIT: How will we handle Ethernet and SLIP networks together? */ if (hw) { ndbg("HW MAC: %s\n", hw); netlib_setmacaddr(intf, mac); } #endif #if defined(CONFIG_NSH_DHCPC) if (!strcmp(hostip, "dhcp")) { /* Set DHCP addr */ ndbg("DHCPC Mode\n"); gip = addr.s_addr = 0; } else #endif { /* Set host IP address */ ndbg("Host IP: %s\n", hostip); gip = addr.s_addr = inet_addr(hostip); } netlib_sethostaddr(intf, &addr); /* Set gateway */ if (gwip) { ndbg("Gateway: %s\n", gwip); gip = addr.s_addr = inet_addr(gwip); } else { if (gip) { ndbg("Gateway: default\n"); gip = NTOHL(gip); gip &= ~0x000000ff; gip |= 0x00000001; gip = HTONL(gip); } addr.s_addr = gip; } netlib_setdraddr(intf, &addr); /* Set network mask */ if (mask) { ndbg("Netmask: %s\n",mask); addr.s_addr = inet_addr(mask); } else { ndbg("Netmask: Default\n"); addr.s_addr = inet_addr("255.255.255.0"); } netlib_setnetmask(intf, &addr); #if defined(CONFIG_NSH_DHCPC) || defined(CONFIG_NSH_DNS) if (dns) { ndbg("DNS: %s\n", dns); addr.s_addr = inet_addr(dns); } else { ndbg("DNS: Default\n"); addr.s_addr = gip; } dns_setserver(&addr); #endif #if defined(CONFIG_NSH_DHCPC) /* Get the MAC address of the NIC */ if (!gip) { netlib_getmacaddr("eth0", mac); /* Set up the DHCPC modules */ handle = dhcpc_open(&mac, IFHWADDRLEN); /* Get an IP address. Note that there is no logic for renewing the IP address in this * example. The address should be renewed in ds.lease_time/2 seconds. */ if (handle) { struct dhcpc_state ds; (void)dhcpc_request(handle, &ds); netlib_sethostaddr("eth0", &ds.ipaddr); if (ds.netmask.s_addr != 0) { netlib_setnetmask("eth0", &ds.netmask); } if (ds.default_router.s_addr != 0) { netlib_setdraddr("eth0", &ds.default_router); } if (ds.dnsaddr.s_addr != 0) { dns_setserver(&ds.dnsaddr); } dhcpc_close(handle); } } #endif return OK; } #endif /**************************************************************************** * Name: cmd_ping ****************************************************************************/ #if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \ !defined(CONFIG_DISABLE_SIGNALS) #ifndef CONFIG_NSH_DISABLE_PING int cmd_ping(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { FAR const char *fmt = g_fmtarginvalid; const char *staddr; net_ipaddr_t ipaddr; uint32_t start; uint32_t next; uint32_t dsec = 10; uint32_t maxwait; uint16_t id; bool badarg = false; int count = 10; int option; int seqno; int replies = 0; int elapsed; int tmp; int i; /* Get the ping options */ while ((option = getopt(argc, argv, ":c:i:")) != ERROR) { switch (option) { case 'c': count = atoi(optarg); if (count < 1 || count > 10000) { nsh_output(vtbl, g_fmtargrange, argv[0]); badarg = true; } break; case 'i': tmp = atoi(optarg); if (tmp < 1 || tmp >= 4294) { nsh_output(vtbl, g_fmtargrange, argv[0]); badarg = true; } else { dsec = 10 * tmp; } break; case ':': nsh_output(vtbl, g_fmtargrequired, argv[0]); badarg = true; break; case '?': default: nsh_output(vtbl, g_fmtarginvalid, argv[0]); badarg = true; break; } } /* If a bad argument was encountered, then return without processing the command */ if (badarg) { return ERROR; } /* There should be exactly on parameter left on the command-line */ if (optind == argc-1) { staddr = argv[optind]; if (dns_gethostip(staddr, &ipaddr) < 0) { goto errout; } } else if (optind >= argc) { fmt = g_fmttoomanyargs; goto errout; } else { fmt = g_fmtargrequired; goto errout; } /* Get the ID to use */ id = ping_newid(); /* The maximum wait for a response will be the larger of the inter-ping time and * the configured maximum round-trip time. */ maxwait = MAX(dsec, CONFIG_NSH_MAX_ROUNDTRIP); /* Loop for the specified count */ nsh_output(vtbl, "PING %d.%d.%d.%d %d bytes of data\n", (ipaddr ) & 0xff, (ipaddr >> 8 ) & 0xff, (ipaddr >> 16 ) & 0xff, (ipaddr >> 24 ) & 0xff, DEFAULT_PING_DATALEN); start = clock_systimer(); for (i = 1; i <= count; i++) { /* Send the ECHO request and wait for the response */ next = clock_systimer(); seqno = icmp_ping(ipaddr, id, i, DEFAULT_PING_DATALEN, maxwait); /* Was any response returned? We can tell if a non-negative sequence * number was returned. */ if (seqno >= 0 && seqno <= i) { /* Get the elapsed time from the time that the request was * sent until the response was received. If we got a response * to an earlier request, then fudge the elpased time. */ elapsed = TICK2MSEC(clock_systimer() - next); if (seqno < i) { elapsed += 100 * dsec * (i - seqno); } /* Report the receipt of the reply */ nsh_output(vtbl, "%d bytes from %s: icmp_seq=%d time=%d ms\n", DEFAULT_PING_DATALEN, staddr, seqno, elapsed); replies++; } /* Wait for the remainder of the interval. If the last seqno> 1)) / count; nsh_output(vtbl, "%d packets transmitted, %d received, %d%% packet loss, time %d ms\n", count, replies, tmp, elapsed); return OK; errout: nsh_output(vtbl, fmt, argv[0]); return ERROR; } #endif #endif /* CONFIG_NET_ICMP && CONFIG_NET_ICMP_PING */ /**************************************************************************** * Name: cmd_put ****************************************************************************/ #if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0 #ifndef CONFIG_NSH_DISABLE_PUT int cmd_put(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { struct tftpc_args_s args; char *fullpath; /* Parse the input parameter list */ if (tftpc_parseargs(vtbl, argc, argv, &args) != OK) { return ERROR; } /* Get the full path to the local file */ fullpath = nsh_getfullpath(vtbl, args.srcpath); /* Then perform the TFTP put operation */ if (tftpput(fullpath, args.destpath, args.ipaddr, args.binary) != OK) { nsh_output(vtbl, g_fmtcmdfailed, argv[0], "tftpput", NSH_ERRNO); } /* Release any allocated memory */ if (args.allocated) { free(args.destpath); } free(fullpath); return OK; } #endif #endif /**************************************************************************** * Name: cmd_wget ****************************************************************************/ #if defined(CONFIG_NET_TCP) && CONFIG_NFILE_DESCRIPTORS > 0 #ifndef CONFIG_NSH_DISABLE_WGET int cmd_wget(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { char *localfile = NULL; char *allocfile = NULL; char *buffer = NULL; char *fullpath = NULL; char *url; const char *fmt; bool badarg = false; int option; int fd = -1; int ret; /* Get the wget options */ while ((option = getopt(argc, argv, ":o:")) != ERROR) { switch (option) { case 'o': localfile = optarg; break; case ':': nsh_output(vtbl, g_fmtargrequired, argv[0]); badarg = true; break; case '?': default: nsh_output(vtbl, g_fmtarginvalid, argv[0]); badarg = true; break; } } /* If a bad argument was encountered, then return without processing the command */ if (badarg) { return ERROR; } /* There should be exactly on parameter left on the command-line */ if (optind == argc-1) { url = argv[optind]; } else if (optind >= argc) { fmt = g_fmttoomanyargs; goto errout; } else { fmt = g_fmtargrequired; goto errout; } /* Get the local file name */ if (!localfile) { allocfile = strdup(url); localfile = basename(allocfile); } /* Get the full path to the local file */ fullpath = nsh_getfullpath(vtbl, localfile); /* Open the local file for writing */ fd = open(fullpath, O_WRONLY|O_CREAT|O_TRUNC, 0644); if (fd < 0) { nsh_output(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO); ret = ERROR; goto exit; } /* Allocate an I/O buffer */ buffer = malloc(512); if (!buffer) { fmt = g_fmtcmdoutofmemory; goto errout; } /* And perform the wget */ ret = wget(url, buffer, 512, wget_callback, (FAR void *)fd); if (ret < 0) { nsh_output(vtbl, g_fmtcmdfailed, argv[0], "wget", NSH_ERRNO); goto exit; } /* Free allocated resources */ exit: if (fd >= 0) { close(fd); } if (allocfile) { free(allocfile); } if (fullpath) { free(fullpath); } if (buffer) { free(buffer); } return ret; errout: nsh_output(vtbl, fmt, argv[0]); ret = ERROR; goto exit; } #endif #endif #endif /* CONFIG_NET */