* libs/libc/netdb/lib_parsehostfile.c
*
* SPDX-License-Identifier: Apache-2.0
*
* 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 <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <arpa/inet.h>
#include "lib_netdb.h"
#ifdef CONFIG_NETDB_HOSTFILE
* Pre-processor Definitions
****************************************************************************/
#define lib_isspace(c) \
((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\f' || c == '\v')
* Private Type Definitions
****************************************************************************/
struct hostent_info_s
{
FAR char *hi_aliases[CONFIG_NETDB_MAX_ALTNAMES + 1];
int hi_addrtypes[1];
int hi_lengths[1];
FAR char *hi_addrlist[2];
char hi_data[1];
};
* Private functions
****************************************************************************/
* Name: lib_skipspaces
*
* Description:
* Read from the 'stream' until a non-whitespace character is read or the
* end-of-line or end-of-file is encountered.
*
* Input Parameters:
* stream - The stream to read from
* nread - A count to the pointer of characters read. Will be
* incremented after each successful character read.
*
* Returned Value:
* The first non-whitespace character read. This will be the newline
* character of EROF if the end-of-line or end-of-file is encountered.
*
****************************************************************************/
static int lib_skipspaces(FAR FILE *stream, FAR size_t *nread)
{
int ch;
do
{
ch = fgetc(stream);
if (ch != EOF)
{
(*nread)++;
}
}
while (lib_isspace(ch));
return ch;
}
* Name: lib_skipline
*
* Description:
* Read from the 'stream' until the end-of-line or end-of-file is
* encountered.
*
* Input Parameters:
* stream - The stream to read from
* nread - A count to the pointer of characters read. Will be
* incremented after each successful character read.
*
* Returned Value:
* The character that terminated the line. This may be either the newline
* character or EOF.
*
****************************************************************************/
static int lib_skipline(FAR FILE *stream, FAR size_t *nread)
{
int ch;
do
{
ch = fgetc(stream);
if (ch != EOF)
{
(*nread)++;
}
}
while (ch != EOF && ch != '\n');
return ch;
}
* Name: lib_copystring
*
* Description:
* Read from the 'stream' And copy each byte to the buffer at 'ptr' until
* either a whitespace delimiter, the end-of-line, or the end-of-file is
* encountered.
*
* Input Parameters:
* stream - The stream to read from
* ptr - The pointer to the buffer to receive the string
* nread - A count to the pointer of characters read. Will be
* incremented after each successful character read.
* buflen - The size of the buffer in bytes
* terminator - The actual character the terminated the copy is returned
* to this location.
*
* Returned Value:
* Number of bytes written to the buffer on success. 0 if the end of
* file is encountered (or a read error occurs). A negated errno value on
* any failure:
*
* -ERANGE - Insufficient buffer space to hold the string.
*
****************************************************************************/
static ssize_t lib_copystring(FAR FILE *stream, FAR char *ptr,
FAR size_t *nread, size_t buflen,
FAR int *terminator)
{
size_t nwritten = 0;
int ch;
* encountered
*/
for (; ; )
{
if (nwritten >= buflen)
{
return -ERANGE;
}
ch = fgetc(stream);
if (ch != EOF)
{
(*nread)++;
}
if (isspace(ch) || ch == EOF)
{
*terminator = ch;
*ptr++ = '\0';
return nwritten + 1;
}
*ptr++ = ch;
nwritten++;
}
}
* Public Functions
****************************************************************************/
* Name: parse_hostfile
*
* Description:
* Parse the next line from the hosts file.
*
* Input Parameters:
* stream - File stream of the opened hosts file with the file pointer
* positioned at the beginning of the next host entry.
* host - Caller provided location to return the host data.
* buf - Caller provided buffer to hold string data associated with the
* host data.
* buflen - The size of the caller-provided buffer
*
* Returned Value:
* The non-zero number of bytes read from the hosts file is returned if
* the host entry was successfully read. Zero is returned if the end
* of the host file has been reached. A negated errno value is return
* in the event a failure:
*
* ERANGE - Buffer not big enough
* ESPIPE - End of file (or possibly a read error).
* EAGAIN - Error parsing the line (E.g., missing hostname)
*
****************************************************************************/
ssize_t parse_hostfile(FAR FILE *stream, FAR struct hostent_s *host,
FAR char *buf, size_t buflen)
{
FAR struct hostent_info_s *info;
FAR char addrstring[48];
FAR char *ptr;
FAR char *start;
socklen_t addrlen;
size_t nread = 0;
ssize_t nwritten;
int ret;
int ch;
int i;
* be big enough).
*/
if (buflen <= sizeof(struct hostent_info_s))
{
return -ERANGE;
}
info = (FAR struct hostent_info_s *)buf;
ptr = info->hi_data;
buflen -= (sizeof(struct hostent_info_s) - 1);
memset(host, 0, sizeof(struct hostent_s));
memset(info, 0, sizeof(struct hostent_info_s));
host->h_addrtypes = info->hi_addrtypes;
host->h_lengths = info->hi_lengths;
host->h_addr_list = info->hi_addrlist;
do
{
ch = lib_skipspaces(stream, &nread);
if (ch == EOF)
{
return -EPIPE;
}
if (ch == '#')
{
ch = lib_skipline(stream, &nread);
if (ch == EOF)
{
return -EPIPE;
}
}
}
while (ch == '\n');
addrstring[0] = ch;
nwritten = lib_copystring(stream, &addrstring[1], &nread, 47, &ch);
if (nwritten < 0)
{
return nwritten;
}
if (!lib_isspace(ch))
{
return ch == EOF ? -EPIPE : -EAGAIN;
}
if (strchr(addrstring, ':') != NULL)
{
addrlen = sizeof(struct in6_addr);
if (buflen < addrlen)
{
return -ERANGE;
}
ret = inet_pton(AF_INET6, addrstring, ptr);
if (ret <= 0)
{
lib_skipline(stream, &nread);
return -EAGAIN;
}
host->h_addrtypes[0] = AF_INET6;
}
else
{
addrlen = sizeof(struct in_addr);
if (buflen < addrlen)
{
return -ERANGE;
}
ret = inet_pton(AF_INET, addrstring, ptr);
if (ret <= 0)
{
lib_skipline(stream, &nread);
return -EAGAIN;
}
host->h_addrtypes[0] = AF_INET;
}
host->h_addr_list[0] = ptr;
host->h_lengths[0] = addrlen;
ptr += addrlen;
buflen -= addrlen;
ch = lib_skipspaces(stream, &nread);
if (ch == EOF)
{
return -EPIPE;
}
else if (ch == '\n')
{
return -EAGAIN;
}
else if (buflen == 0)
{
return -ERANGE;
}
start = ptr;
*ptr++ = ch;
buflen--;
nwritten = lib_copystring(stream, ptr, &nread, buflen, &ch);
if (nwritten < 0)
{
return nwritten;
}
host->h_name = start;
if (!lib_isspace(ch))
{
return nread;
}
ptr += nwritten;
buflen -= nwritten;
for (i = 0; ; i++)
{
ch = lib_skipspaces(stream, &nread);
if (ch == EOF || ch == '\n')
{
return nread;
}
else if (buflen == 0 || i >= CONFIG_NETDB_MAX_ALTNAMES)
{
return -ERANGE;
}
start = ptr;
*ptr++ = ch;
buflen--;
nwritten = lib_copystring(stream, ptr, &nread, buflen, &ch);
if (nwritten < 0)
{
return nwritten;
}
info->hi_aliases[i] = start;
if (host->h_aliases == NULL)
{
host->h_aliases = info->hi_aliases;
}
if (!lib_isspace(ch))
{
return nread;
}
ptr += nwritten;
buflen -= nwritten;
}
}
#endif