blob: 183099f5c6d4a1ead4adb9df6ee424b5038957d7 [file] [log] [blame]
/* vi: set sw=4 ts=4: */
/*
* Copyright (C) 2010 Bernhard Reutner-Fischer <uclibc@uclibc.org>
*
* Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
*/
/* /etc/services
# service-name port/protocol [aliases ...]
discard 9/udp sink null
service-name: case sensitive friendly name of the service
port: decimal port number
protocol: protocols(5) compatible entry
aliases: case sensitive optional space or tab separated list of other names
*/
#include <features.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
#include "internal/parse_config.h"
#include <bits/uClibc_mutex.h>
__UCLIBC_MUTEX_STATIC(mylock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
#define MINTOKENS 3
#define MAXALIASES 8 /* we seldomly need more than 1 alias */
#define MAXTOKENS (MINTOKENS + MAXALIASES + 1)
#define BUFSZ (255) /* one line */
#define SBUFSIZE (BUFSZ + 1 + (sizeof(char *) * MAXTOKENS))
static parser_t *servp = NULL;
static struct servent serve;
static char *servbuf = NULL;
static size_t servbuf_sz = SBUFSIZE;
static smallint serv_stayopen;
void setservent(int stayopen)
{
__UCLIBC_MUTEX_LOCK(mylock);
if (servp)
config_close(servp);
servp = config_open(_PATH_SERVICES);
if (stayopen)
serv_stayopen = 1;
__UCLIBC_MUTEX_UNLOCK(mylock);
}
libc_hidden_def(setservent)
void endservent(void)
{
__UCLIBC_MUTEX_LOCK(mylock);
if (servp) {
config_close(servp);
servp = NULL;
}
serv_stayopen = 0;
__UCLIBC_MUTEX_UNLOCK(mylock);
}
libc_hidden_def(endservent)
int getservent_r(struct servent *result_buf,
char *buf, size_t buflen, struct servent **result)
{
char **tok = NULL;
const size_t aliaslen = sizeof(char *) * MAXTOKENS;
int ret = ERANGE;
*result = NULL;
if (buflen < aliaslen
|| (buflen - aliaslen) < BUFSZ + 1)
goto DONE_NOUNLOCK;
__UCLIBC_MUTEX_LOCK(mylock);
ret = ENOENT;
if (servp == NULL)
setservent(serv_stayopen);
if (servp == NULL)
goto DONE;
servp->data = buf;
servp->data_len = aliaslen;
servp->line_len = buflen - aliaslen;
/* <name>[[:space:]]<port>/<proto>[[:space:]][<aliases>] */
if (!config_read(servp, &tok, MAXTOKENS - 1, MINTOKENS, "# \t/", PARSE_NORMAL)) {
goto DONE;
}
result_buf->s_name = *(tok++);
result_buf->s_port = htons((u_short) atoi(*(tok++)));
result_buf->s_proto = *(tok++);
result_buf->s_aliases = tok;
*result = result_buf;
ret = 0;
DONE:
__UCLIBC_MUTEX_UNLOCK(mylock);
DONE_NOUNLOCK:
errno = ret;
return errno;
}
libc_hidden_def(getservent_r)
static void __initbuf(void)
{
if (!servbuf)
servbuf = malloc(SBUFSIZE);
if (!servbuf)
abort();
}
struct servent *getservent(void)
{
struct servent *result;
__initbuf();
getservent_r(&serve, servbuf, servbuf_sz, &result);
return result;
}
int getservbyname_r(const char *name, const char *proto,
struct servent *result_buf, char *buf, size_t buflen,
struct servent **result)
{
register char **cp;
int ret;
__UCLIBC_MUTEX_LOCK(mylock);
setservent(serv_stayopen);
while (!(ret = getservent_r(result_buf, buf, buflen, result))) {
if (strcmp(name, result_buf->s_name) == 0)
goto gotname;
for (cp = result_buf->s_aliases; *cp; cp++)
if (strcmp(name, *cp) == 0)
goto gotname;
continue;
gotname:
if (proto == 0 || strcmp(result_buf->s_proto, proto) == 0)
break;
}
if (!serv_stayopen)
endservent();
__UCLIBC_MUTEX_UNLOCK(mylock);
return *result ? 0 : ret;
}
libc_hidden_def(getservbyname_r)
struct servent *getservbyname(const char *name, const char *proto)
{
struct servent *result;
__initbuf();
getservbyname_r(name, proto, &serve, servbuf, servbuf_sz, &result);
return result;
}
int getservbyport_r(int port, const char *proto,
struct servent *result_buf, char *buf,
size_t buflen, struct servent **result)
{
int ret;
__UCLIBC_MUTEX_LOCK(mylock);
setservent(serv_stayopen);
while (!(ret = getservent_r(result_buf, buf, buflen, result))) {
if (result_buf->s_port != port)
continue;
if (proto == 0 || strcmp(result_buf->s_proto, proto) == 0)
break;
}
if (!serv_stayopen)
endservent();
__UCLIBC_MUTEX_UNLOCK(mylock);
return *result ? 0 : ret;
}
libc_hidden_def(getservbyport_r)
struct servent *getservbyport(int port, const char *proto)
{
struct servent *result;
__initbuf();
getservbyport_r(port, proto, &serve, servbuf, servbuf_sz, &result);
return result;
}
libc_hidden_def(getservbyport)