blob: 183099f5c6d4a1ead4adb9df6ee424b5038957d7 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* 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 ...]
10discard 9/udp sink null
11
12service-name: case sensitive friendly name of the service
13port: decimal port number
14protocol: protocols(5) compatible entry
15aliases: 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
37static parser_t *servp = NULL;
38static struct servent serve;
39static char *servbuf = NULL;
40static size_t servbuf_sz = SBUFSIZE;
41static smallint serv_stayopen;
42
43void 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}
53libc_hidden_def(setservent)
54
55void 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}
65libc_hidden_def(endservent)
66
67int 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}
105libc_hidden_def(getservent_r)
106
107static void __initbuf(void)
108{
109 if (!servbuf)
110 servbuf = malloc(SBUFSIZE);
111 if (!servbuf)
112 abort();
113}
114
115struct servent *getservent(void)
116{
117 struct servent *result;
118
119 __initbuf();
120 getservent_r(&serve, servbuf, servbuf_sz, &result);
121 return result;
122}
123
124int 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}
149libc_hidden_def(getservbyname_r)
150
151struct 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
161int 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}
180libc_hidden_def(getservbyport_r)
181
182struct 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}
190libc_hidden_def(getservbyport)