1 /* vi: set sw=4 ts=4: */
2 /*
3  * Copyright (C) 2010 Bernhard Reutner-Fischer <uclibc@uclibc.org>
4  *
5  * Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
6  */
7 
8 /* /etc/services
9 #   service-name   port/protocol   [aliases ...]
10 discard               9/udp        sink null
11 
12 service-name: case sensitive friendly name of the service
13 port: decimal port number
14 protocol: protocols(5) compatible entry
15 aliases: case sensitive optional space or tab separated list of other names
16 */
17 
18 #include <features.h>
19 #include <netdb.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include "internal/parse_config.h"
27 
28 #include <bits/uClibc_mutex.h>
29 __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
30 
31 #define MINTOKENS	3
32 #define	MAXALIASES	8	/* we seldomly need more than 1 alias */
33 #define MAXTOKENS	(MINTOKENS + MAXALIASES + 1)
34 #define BUFSZ		(255)	/* one line */
35 #define SBUFSIZE	(BUFSZ + 1 + (sizeof(char *) * MAXTOKENS))
36 
37 static parser_t *servp = NULL;
38 static struct servent serve;
39 static char *servbuf = NULL;
40 static size_t servbuf_sz = SBUFSIZE;
41 static smallint serv_stayopen;
42 
setservent(int stayopen)43 void setservent(int stayopen)
44 {
45 	__UCLIBC_MUTEX_LOCK(mylock);
46 	if (servp)
47 		config_close(servp);
48 	servp = config_open(_PATH_SERVICES);
49 	if (stayopen)
50 		serv_stayopen = 1;
51 	__UCLIBC_MUTEX_UNLOCK(mylock);
52 }
libc_hidden_def(setservent)53 libc_hidden_def(setservent)
54 
55 void endservent(void)
56 {
57 	__UCLIBC_MUTEX_LOCK(mylock);
58 	if (servp) {
59 		config_close(servp);
60 		servp = NULL;
61 	}
62 	serv_stayopen = 0;
63 	__UCLIBC_MUTEX_UNLOCK(mylock);
64 }
libc_hidden_def(endservent)65 libc_hidden_def(endservent)
66 
67 int getservent_r(struct servent *result_buf,
68 				 char *buf, size_t buflen, struct servent **result)
69 {
70 	char **tok = NULL;
71 	const size_t aliaslen = sizeof(char *) * MAXTOKENS;
72 	int ret = ERANGE;
73 
74 	*result = NULL;
75 	if (buflen < aliaslen
76 		|| (buflen - aliaslen) < BUFSZ + 1)
77 		goto DONE_NOUNLOCK;
78 
79 	__UCLIBC_MUTEX_LOCK(mylock);
80 	ret = ENOENT;
81 	if (servp == NULL)
82 		setservent(serv_stayopen);
83 	if (servp == NULL)
84 		goto DONE;
85 
86 	servp->data = buf;
87 	servp->data_len = aliaslen;
88 	servp->line_len = buflen - aliaslen;
89 	/* <name>[[:space:]]<port>/<proto>[[:space:]][<aliases>] */
90 	if (!config_read(servp, &tok, MAXTOKENS - 1, MINTOKENS, "# \t/", PARSE_NORMAL)) {
91 		goto DONE;
92 	}
93 	result_buf->s_name = *(tok++);
94 	result_buf->s_port = htons((u_short) atoi(*(tok++)));
95 	result_buf->s_proto = *(tok++);
96 	result_buf->s_aliases = tok;
97 	*result = result_buf;
98 	ret = 0;
99  DONE:
100 	__UCLIBC_MUTEX_UNLOCK(mylock);
101  DONE_NOUNLOCK:
102 	errno = ret;
103 	return errno;
104 }
libc_hidden_def(getservent_r)105 libc_hidden_def(getservent_r)
106 
107 static void __initbuf(void)
108 {
109 	if (!servbuf)
110 		servbuf = malloc(SBUFSIZE);
111 	if (!servbuf)
112 		abort();
113 }
114 
getservent(void)115 struct servent *getservent(void)
116 {
117 	struct servent *result;
118 
119 	__initbuf();
120 	getservent_r(&serve, servbuf, servbuf_sz, &result);
121 	return result;
122 }
123 
getservbyname_r(const char * name,const char * proto,struct servent * result_buf,char * buf,size_t buflen,struct servent ** result)124 int getservbyname_r(const char *name, const char *proto,
125 					struct servent *result_buf, char *buf, size_t buflen,
126 					struct servent **result)
127 {
128 	register char **cp;
129 	int ret;
130 
131 	__UCLIBC_MUTEX_LOCK(mylock);
132 	setservent(serv_stayopen);
133 	while (!(ret = getservent_r(result_buf, buf, buflen, result))) {
134 		if (strcmp(name, result_buf->s_name) == 0)
135 			goto gotname;
136 		for (cp = result_buf->s_aliases; *cp; cp++)
137 			if (strcmp(name, *cp) == 0)
138 				goto gotname;
139 		continue;
140  gotname:
141 		if (proto == 0 || strcmp(result_buf->s_proto, proto) == 0)
142 			break;
143 	}
144 	if (!serv_stayopen)
145 		endservent();
146 	__UCLIBC_MUTEX_UNLOCK(mylock);
147 	return *result ? 0 : ret;
148 }
libc_hidden_def(getservbyname_r)149 libc_hidden_def(getservbyname_r)
150 
151 struct servent *getservbyname(const char *name, const char *proto)
152 {
153 	struct servent *result;
154 
155 	__initbuf();
156 	getservbyname_r(name, proto, &serve, servbuf, servbuf_sz, &result);
157 	return result;
158 }
159 
160 
getservbyport_r(int port,const char * proto,struct servent * result_buf,char * buf,size_t buflen,struct servent ** result)161 int getservbyport_r(int port, const char *proto,
162 					struct servent *result_buf, char *buf,
163 					size_t buflen, struct servent **result)
164 {
165 	int ret;
166 
167 	__UCLIBC_MUTEX_LOCK(mylock);
168 	setservent(serv_stayopen);
169 	while (!(ret = getservent_r(result_buf, buf, buflen, result))) {
170 		if (result_buf->s_port != port)
171 			continue;
172 		if (proto == 0 || strcmp(result_buf->s_proto, proto) == 0)
173 			break;
174 	}
175 	if (!serv_stayopen)
176 		endservent();
177 	__UCLIBC_MUTEX_UNLOCK(mylock);
178 	return *result ? 0 : ret;
179 }
libc_hidden_def(getservbyport_r)180 libc_hidden_def(getservbyport_r)
181 
182 struct servent *getservbyport(int port, const char *proto)
183 {
184 	struct servent *result;
185 
186 	__initbuf();
187 	getservbyport_r(port, proto, &serve, servbuf, servbuf_sz, &result);
188 	return result;
189 }
190 libc_hidden_def(getservbyport)
191