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