1/*
2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (c) 1998-1999 by Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#if defined(LIBC_SCCS) && !defined(lint)
19static const char rcsid[] = "$Id: getservent_r.c,v 1.6 2006/08/01 01:14:16 marka Exp $";
20#endif /* LIBC_SCCS and not lint */
21
22#include <port_before.h>
23#if !defined(_REENTRANT) || !defined(DO_PTHREADS)
24	static int getservent_r_not_required = 0;
25#else
26#include <errno.h>
27#include <string.h>
28#include <stdio.h>
29#include <sys/types.h>
30#include <netinet/in.h>
31#include <netdb.h>
32#include <sys/param.h>
33#include <port_after.h>
34
35#ifdef SERV_R_RETURN
36
37static SERV_R_RETURN
38copy_servent(struct servent *, struct servent *, SERV_R_COPY_ARGS);
39
40SERV_R_RETURN
41getservbyname_r(const char *name, const char *proto,
42		struct servent *sptr, SERV_R_ARGS) {
43	struct servent *se = getservbyname(name, proto);
44#ifdef SERV_R_SETANSWER
45	int n = 0;
46
47	if (se == NULL || (n = copy_servent(se, sptr, SERV_R_COPY)) != 0)
48		*answerp = NULL;
49	else
50		*answerp = sptr;
51
52	return (n);
53#else
54	if (se == NULL)
55		return (SERV_R_BAD);
56
57	return (copy_servent(se, sptr, SERV_R_COPY));
58#endif
59}
60
61SERV_R_RETURN
62getservbyport_r(int port, const char *proto,
63		struct servent *sptr, SERV_R_ARGS) {
64	struct servent *se = getservbyport(port, proto);
65#ifdef SERV_R_SETANSWER
66	int n = 0;
67
68	if (se == NULL || (n = copy_servent(se, sptr, SERV_R_COPY)) != 0)
69		*answerp = NULL;
70	else
71		*answerp = sptr;
72
73	return (n);
74#else
75	if (se == NULL)
76		return (SERV_R_BAD);
77
78	return (copy_servent(se, sptr, SERV_R_COPY));
79#endif
80}
81
82/*%
83 *	These assume a single context is in operation per thread.
84 *	If this is not the case we will need to call irs directly
85 *	rather than through the base functions.
86 */
87
88SERV_R_RETURN
89getservent_r(struct servent *sptr, SERV_R_ARGS) {
90	struct servent *se = getservent();
91#ifdef SERV_R_SETANSWER
92	int n = 0;
93
94	if (se == NULL || (n = copy_servent(se, sptr, SERV_R_COPY)) != 0)
95		*answerp = NULL;
96	else
97		*answerp = sptr;
98
99	return (n);
100#else
101	if (se == NULL)
102		return (SERV_R_BAD);
103
104	return (copy_servent(se, sptr, SERV_R_COPY));
105#endif
106}
107
108SERV_R_SET_RETURN
109#ifdef SERV_R_ENT_ARGS
110setservent_r(int stay_open, SERV_R_ENT_ARGS)
111#else
112setservent_r(int stay_open)
113#endif
114{
115#ifdef SERV_R_ENT_UNUSED
116	SERV_R_ENT_UNUSED;
117#endif
118	setservent(stay_open);
119#ifdef SERV_R_SET_RESULT
120	return (SERV_R_SET_RESULT);
121#endif
122}
123
124SERV_R_END_RETURN
125#ifdef SERV_R_ENT_ARGS
126endservent_r(SERV_R_ENT_ARGS)
127#else
128endservent_r()
129#endif
130{
131#ifdef SERV_R_ENT_UNUSED
132	SERV_R_ENT_UNUSED;
133#endif
134	endservent();
135	SERV_R_END_RESULT(SERV_R_OK);
136}
137
138/* Private */
139
140#ifndef SERVENT_DATA
141static SERV_R_RETURN
142copy_servent(struct servent *se, struct servent *sptr, SERV_R_COPY_ARGS) {
143	char *cp;
144	int i, n;
145	int numptr, len;
146
147	/* Find out the amount of space required to store the answer. */
148	numptr = 1; /*%< NULL ptr */
149	len = (char *)ALIGN(buf) - buf;
150	for (i = 0; se->s_aliases[i]; i++, numptr++) {
151		len += strlen(se->s_aliases[i]) + 1;
152	}
153	len += strlen(se->s_name) + 1;
154	len += strlen(se->s_proto) + 1;
155	len += numptr * sizeof(char*);
156
157	if (len > (int)buflen) {
158		errno = ERANGE;
159		return (SERV_R_BAD);
160	}
161
162	/* copy port value */
163	sptr->s_port = se->s_port;
164
165	cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
166
167	/* copy official name */
168	n = strlen(se->s_name) + 1;
169	strcpy(cp, se->s_name);
170	sptr->s_name = cp;
171	cp += n;
172
173	/* copy aliases */
174	sptr->s_aliases = (char **)ALIGN(buf);
175	for (i = 0 ; se->s_aliases[i]; i++) {
176		n = strlen(se->s_aliases[i]) + 1;
177		strcpy(cp, se->s_aliases[i]);
178		sptr->s_aliases[i] = cp;
179		cp += n;
180	}
181	sptr->s_aliases[i] = NULL;
182
183	/* copy proto */
184	n = strlen(se->s_proto) + 1;
185	strcpy(cp, se->s_proto);
186	sptr->s_proto = cp;
187	cp += n;
188
189	return (SERV_R_OK);
190}
191#else /* !SERVENT_DATA */
192static int
193copy_servent(struct servent *se, struct servent *sptr, SERV_R_COPY_ARGS) {
194	char *cp, *eob;
195	int i, n;
196
197	/* copy port value */
198	sptr->s_port = se->s_port;
199
200	/* copy official name */
201	cp = sdptr->line;
202	eob = sdptr->line + sizeof(sdptr->line);
203	if ((n = strlen(se->s_name) + 1) < (eob - cp)) {
204		strcpy(cp, se->s_name);
205		sptr->s_name = cp;
206		cp += n;
207	} else {
208		return (-1);
209	}
210
211	/* copy aliases */
212	i = 0;
213	sptr->s_aliases = sdptr->serv_aliases;
214	while (se->s_aliases[i] && i < (_MAXALIASES-1)) {
215		if ((n = strlen(se->s_aliases[i]) + 1) < (eob - cp)) {
216			strcpy(cp, se->s_aliases[i]);
217			sptr->s_aliases[i] = cp;
218			cp += n;
219		} else {
220			break;
221		}
222		i++;
223	}
224	sptr->s_aliases[i] = NULL;
225
226	/* copy proto */
227	if ((n = strlen(se->s_proto) + 1) < (eob - cp)) {
228		strcpy(cp, se->s_proto);
229		sptr->s_proto = cp;
230		cp += n;
231	} else {
232		return (-1);
233	}
234
235	return (SERV_R_OK);
236}
237#endif /* !SERVENT_DATA */
238#else /*SERV_R_RETURN */
239	static int getservent_r_unknown_system = 0;
240#endif /*SERV_R_RETURN */
241#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */
242/*! \file */
243