nuttx-apps/fsutils/ipcfg/ipcfg_binary.c
2021-06-08 13:19:50 -05:00

576 lines
14 KiB
C

/****************************************************************************
* apps/fsutils/ipcfg/ipcfg_binary.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <debug.h>
#include "fsutils/ipcfg.h"
#include "ipcfg.h"
#ifdef CONFIG_IPCFG_BINARY
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: ipcfg_open (for binary mode)
*
* Description:
* Form the complete path to the ipcfg file and open it.
*
* Input Parameters:
* path - The full path to the IP configuration file
* oflags - File open flags
* mode - File creation mode
*
* Returned Value:
* The open file descriptor is returned on success; a negated errno value
* is returned on any failure.
*
****************************************************************************/
#ifdef CONFIG_IPCFG_BINARY
static int ipcfg_open(FAR const char *path, int oflags, mode_t mode)
{
int fd;
int ret;
/* Now open the file */
fd = open(path, oflags, mode);
if (fd < 0)
{
ret = -errno;
if (ret != -ENOENT)
{
ferr("ERROR: Failed to open %s: %d\n", path, ret);
}
return ret;
}
#if defined(CONFIG_IPCFG_OFFSET) && CONFIG_IPCFG_OFFSET > 0
/* If the binary file is accessed on a character device as a binary
* file, then there is also an option to seek to a location on the
* media before reading or writing the file.
*/
ret = lseek(fd, CONFIG_IPCFG_OFFSET, SEEK_SET);
if (ret < 0)
{
ret = -errno;
ferr("ERROR: Failed to seek to $ld: %d\n",
(long)CONFIG_IPCFG_OFFSET, ret);
close(fd);
return ret;
}
#endif
return fd;
}
#endif
/****************************************************************************
* Name: ipcfg_read_binary
*
* Description:
* Read from a binary IP Configuration file.
*
* Input Parameters:
* fd - File descriptor of the open file to read from
* buffer - Location to read from
* nbytes - Number of bytes to read
*
* Returned Value:
* Zero is returned on success; a negated errno value is returned on any
* failure.
*
****************************************************************************/
static int ipcfg_read_binary(int fd, FAR void *buffer, size_t nbytes)
{
ssize_t nread;
int ret;
/* Read from the file */
nread = read(fd, buffer, nbytes);
if (nread < 0)
{
ret = -errno;
ferr("ERROR: Failed to read from file: %d\n", ret);
}
else if (nread != nbytes)
{
ret = -EIO;
ferr("ERROR: Bad read size: %ld\n", (long)nread);
}
else
{
ret = OK;
}
return ret;
}
/****************************************************************************
* Name: ipcfg_write_binary
*
* Description:
* Write to a binary IP Configuration file.
*
* Input Parameters:
* fd - File descriptor of the open file to write to
* buffer - Location to write to
* nbytes - Number of bytes to wrtie
*
* Returned Value:
* Zero is returned on success; a negated errno value is returned on any
* failure.
*
****************************************************************************/
#ifdef CONFIG_IPCFG_WRITABLE
static int ipcfg_write_binary(int fd, FAR const void *buffer, size_t nbytes)
{
ssize_t nwritten;
int ret;
/* Read from the file */
nwritten = write(fd, buffer, nbytes);
if (nwritten < 0)
{
ret = -errno;
ferr("ERROR: Failed to write to file: %d\n", ret);
}
else if (nwritten != nbytes)
{
ret = -EIO;
ferr("ERROR: Bad write size: %ld\n", (long)nwritten);
}
else
{
ret = OK;
}
return ret;
}
#endif
/****************************************************************************
* Name: ipcfg_find_binary
*
* Description:
* Read the location of IPv4 data in a binary IP Configuration file.
*
* Input Parameters:
* fd - File descriptor of the open file to read from
* af - Identifies the address family whose IP configuration is
* requested. May be either AF_INET or AF_INET6.
*
* Returned Value:
* Zero is returned on success; a negated errno value is returned on any
* failure.
*
****************************************************************************/
static int ipcfg_find_binary(int fd, sa_family_t af)
{
struct ipcfg_header_s hdr;
off_t pos;
int ret;
for (; ; )
{
/* Read the header (careful.. could be uninitialized in the case of a
* character driver).
*/
ret = ipcfg_read_binary(fd, &hdr, sizeof(struct ipcfg_header_s));
if (ret < 0)
{
/* Return on any read error */
return (int)ret;
}
else if (hdr.version == IPCFG_VERSION && hdr.type == af)
{
return OK;
}
else if (hdr.version != IPCFG_VERSION ||
(hdr.type != AF_INET && hdr.type != AF_INET6))
{
return -EINVAL;
}
else if (hdr.next == 0)
{
ferr("ERROR: IP configuration not found\n");
return -ENOENT;
}
/* Skip to the next IP configuration record */
pos = lseek(fd, hdr.next, SEEK_CUR);
if (pos < 0)
{
ret = -errno;
ferr("ERROR: lseek failed: %d\n", ret);
return ret;
}
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ipcfg_read_binary_ipv4
*
* Description:
* Read IPv4 configuration from a binary IP Configuration file.
*
* Input Parameters:
* path - The full path to the IP configuration file
* ipv4cfg - Location to read IPv4 configration to
*
* Returned Value:
* Zero is returned on success; a negated errno value is returned on any
* failure.
*
****************************************************************************/
#ifdef CONFIG_NET_IPv4
int ipcfg_read_binary_ipv4(FAR const char *path,
FAR struct ipv4cfg_s *ipv4cfg)
{
int fd;
int ret;
DEBUGASSERT(path != NULL && ipv4cfg != NULL);
/* Open the file for reading */
fd = ipcfg_open(path, O_RDONLY, 0666);
if (fd < 0)
{
return fd;
}
/* Find the IPv4 binary in the IP configuration file */
ret = ipcfg_find_binary(fd, AF_INET);
if (ret < 0)
{
goto errout_with_fd;
}
/* Read the IPv4 Configuration */
ret = ipcfg_read_binary(fd, ipv4cfg, sizeof(struct ipv4cfg_s));
errout_with_fd:
close(fd);
return ret;
}
#endif
/****************************************************************************
* Name: ipcfg_read_binary_ipv6
*
* Description:
* Read IPv6 configuration from a binary IP Configuration file.
*
* Input Parameters:
* path - The full path to the IP configuration file
* ipv6cfg - Location to read IPv6 configration to
*
* Returned Value:
* Zero is returned on success; a negated errno value is returned on any
* failure.
*
****************************************************************************/
#ifdef CONFIG_NET_IPv6
int ipcfg_read_binary_ipv6(FAR const char *path,
FAR struct ipv6cfg_s *ipv6cfg)
{
int fd;
int ret;
DEBUGASSERT(fd >= 0 && ipv6cfg != NULL);
/* Open the file for reading */
fd = ipcfg_open(path, O_RDONLY, 0666);
if (fd < 0)
{
return fd;
}
/* Find the IPv6 binary in the IP configuration file */
ret = ipcfg_find_binary(fd, AF_INET6);
if (ret < 0)
{
goto errout_with_fd;
}
/* Read the IPv6 Configuration */
ret = ipcfg_read_binary(fd, ipv6cfg, sizeof(struct ipv6cfg_s));
errout_with_fd:
close(fd);
return ret;
}
#endif
/****************************************************************************
* Name: ipcfg_write_binary_ipv4
*
* Description:
* Write the IPv4 configuration to a binary IP Configuration file.
*
* Input Parameters:
* path - The full path to the IP configuration file
* ipv4cfg - The IPv4 configration to write
*
* Returned Value:
* Zero is returned on success; a negated errno value is returned on any
* failure.
*
****************************************************************************/
#if defined(CONFIG_IPCFG_WRITABLE) && defined(CONFIG_NET_IPv4)
int ipcfg_write_binary_ipv4(FAR const char *path,
FAR const struct ipv4cfg_s *ipv4cfg)
{
#ifdef CONFIG_NET_IPv6
struct ipv6cfg_s ipv6cfg;
#endif
struct ipcfg_header_s hdr;
bool ipv6 = false;
int fd;
int ret;
DEBUGASSERT(ipv4cfg != NULL);
#ifdef CONFIG_NET_IPv6
/* Read any IPv6 data in the file */
ret = ipcfg_read_binary_ipv6(path, &ipv6cfg);
if (ret < 0)
{
/* -ENOENT is not an error. It simply means that there is no IPv6
* configuration in the file.
*/
if (ret != -ENOENT)
{
return ret;
}
}
else
{
ipv6 = true;
}
#endif
/* Open the file for writing (truncates) */
fd = ipcfg_open(path, O_WRONLY | O_TRUNC | O_CREAT, 0666);
DEBUGASSERT(fd >= 0);
if (fd < 0)
{
return fd;
}
/* Write the IPv4 file header */
hdr.next = ipv6 ? sizeof(struct ipv4cfg_s) : 0;
hdr.type = AF_INET;
hdr.version = IPCFG_VERSION;
ret = ipcfg_write_binary(fd, &hdr, sizeof(struct ipcfg_header_s));
if (ret < 0)
{
goto errout_with_fd;
}
/* Write the IPv4 configuration */
ret = ipcfg_write_binary(fd, ipv4cfg, sizeof(struct ipv4cfg_s));
if (ret < 0)
{
goto errout_with_fd;
}
#ifdef CONFIG_NET_IPv6
/* Followed by any IPv6 data in the file */
if (ipv6)
{
/* Write the IPv6 header */
hdr.next = 0;
hdr.type = AF_INET6;
hdr.version = IPCFG_VERSION;
ret = ipcfg_write_binary(fd, &hdr, sizeof(struct ipcfg_header_s));
if (ret >= 0)
{
/* Write the IPv6 configuration */
ret = ipcfg_write_binary(fd, &ipv6cfg, sizeof(struct ipv6cfg_s));
}
}
#endif
errout_with_fd:
close(fd);
return ret;
}
#endif
/****************************************************************************
* Name: ipcfg_write_binary_ipv6
*
* Description:
* Write the IPv6 configuration to a binary IP Configuration file.
*
* Input Parameters:
* path - The full path to the IP configuration file
* ipv6cfg - The IPv6 configration to write
*
* Returned Value:
* Zero is returned on success; a negated errno value is returned on any
* failure.
*
****************************************************************************/
#if defined(CONFIG_IPCFG_WRITABLE) && defined(CONFIG_NET_IPv6)
int ipcfg_write_binary_ipv6(FAR const char *path,
FAR const struct ipv6cfg_s *ipv6cfg)
{
#ifdef CONFIG_NET_IPv4
struct ipv4cfg_s ipv4cfg;
bool ipv4 = false;
#endif
struct ipcfg_header_s hdr;
int fd;
int ret;
DEBUGASSERT(path != NULL && ipv6cfg != NULL);
#ifdef CONFIG_NET_IPv4
/* Read any IPv4 data in the file */
ret = ipcfg_read_binary_ipv4(path, &ipv4cfg);
if (ret < 0)
{
/* -ENOENT is not an error. It simply means that there is no IPv4
* configuration in the file.
*/
if (ret != -ENOENT)
{
return ret;
}
}
else
{
ipv4 = true;
}
#endif
/* Open the file for writing (truncates) */
fd = ipcfg_open(path, O_WRONLY | O_TRUNC | O_CREAT, 0666);
if (fd < 0)
{
return fd;
}
#ifdef CONFIG_NET_IPv4
if (ipv4)
{
/* Write the IPv4 header */
hdr.next = sizeof(struct ipv4cfg_s);
hdr.type = AF_INET;
hdr.version = IPCFG_VERSION;
ret = ipcfg_write_binary(fd, &hdr, sizeof(struct ipcfg_header_s));
if (ret < 0)
{
goto errout_with_fd;
}
/* Write the IPv4 configuration. This is really unnecessary in most
* cases since the IPv4 data should already be in place.
*/
ret = ipcfg_write_binary(fd, &ipv4cfg, sizeof(struct ipv4cfg_s));
if (ret < 0)
{
goto errout_with_fd;
}
}
#endif
/* Write the IPv6 file header */
hdr.next = 0;
hdr.type = AF_INET6;
hdr.version = IPCFG_VERSION;
ret = ipcfg_write_binary(fd, &hdr, sizeof(struct ipcfg_header_s));
if (ret >= 0)
{
/* Write the IPv6 configuration */
ret = ipcfg_write_binary(fd, ipv6cfg, sizeof(struct ipv6cfg_s));
}
#ifdef CONFIG_NET_IPv4
errout_with_fd:
#endif
close(fd);
return ret;
}
#endif
#endif /* CONFIG_IPCFG_BINARY */