Merge from vendor branch GDB:
[dragonfly.git] / lib / libc / net / getservent.c
1 /*
2  * Copyright (c) 1983, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * @(#)getservent.c     8.1 (Berkeley) 6/4/93
30  * $DragonFly: src/lib/libc/net/getservent.c,v 1.6 2005/09/19 09:34:53 asmodai Exp $
31  */
32
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <netdb.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #ifdef YP
40 #include <rpc/rpc.h>
41 #include <rpcsvc/yp_prot.h>
42 #include <rpcsvc/ypclnt.h>
43 static int serv_stepping_yp = 0;
44 extern int _yp_check ( char ** );
45 #endif
46
47
48 #define MAXALIASES      35
49
50 static FILE *servf = NULL;
51 static char line[BUFSIZ+1];
52 static struct servent serv;
53 static char *serv_aliases[MAXALIASES];
54 int _serv_stayopen;
55
56 #ifdef YP
57 char *___getservbyname_yp = NULL;
58 char *___getservbyproto_yp = NULL;
59 int ___getservbyport_yp = 0;
60 static char *yp_domain = NULL;
61
62 static int
63 _getservbyport_yp(line)
64         char *line;
65 {
66         char *result;
67         int resultlen;
68         char buf[YPMAXRECORD + 2];
69         int rv;
70
71         snprintf(buf, sizeof(buf), "%d/%s", ntohs(___getservbyport_yp),
72                                                 ___getservbyproto_yp);
73
74         ___getservbyport_yp = 0;
75         ___getservbyproto_yp = NULL;
76
77         if(!yp_domain) {
78                 if(yp_get_default_domain(&yp_domain))
79                         return (0);
80         }
81
82         /*
83          * We have to be a little flexible here. Ideally you're supposed
84          * to have both a services.byname and a services.byport map, but
85          * some systems have only services.byname. FreeBSD cheats a little
86          * by putting the services.byport information in the same map as
87          * services.byname so that either case will work. We allow for both
88          * possibilities here: if there is no services.byport map, we try
89          * services.byname instead.
90          */
91         if ((rv = yp_match(yp_domain, "services.byport", buf, strlen(buf),
92                                                 &result, &resultlen))) {
93                 if (rv == YPERR_MAP) {
94                         if (yp_match(yp_domain, "services.byname", buf,
95                                         strlen(buf), &result, &resultlen))
96                         return(0);
97                 } else
98                         return(0);
99         }
100                 
101         /* getservent() expects lines terminated with \n -- make it happy */
102         snprintf(line, BUFSIZ, "%.*s\n", resultlen, result);
103
104         free(result);
105         return(1);
106 }
107
108 static int
109 _getservbyname_yp(line)
110         char *line;
111 {
112         char *result;
113         int resultlen;
114         char buf[YPMAXRECORD + 2];
115
116         if(!yp_domain) {
117                 if(yp_get_default_domain(&yp_domain))
118                         return (0);
119         }
120
121         snprintf(buf, sizeof(buf), "%s/%s", ___getservbyname_yp,
122                                                 ___getservbyproto_yp);
123
124         ___getservbyname_yp = 0;
125         ___getservbyproto_yp = NULL;
126
127         if (yp_match(yp_domain, "services.byname", buf, strlen(buf),
128                                                 &result, &resultlen)) {
129                 return(0);
130         }
131                 
132         /* getservent() expects lines terminated with \n -- make it happy */
133         snprintf(line, BUFSIZ, "%.*s\n", resultlen, result);
134
135         free(result);
136         return(1);
137 }
138
139 static int
140 _getservent_yp(line)
141         char *line;
142 {
143         static char *key = NULL;
144         static int keylen;
145         char *lastkey, *result;
146         int resultlen;
147         int rv;
148
149         if(!yp_domain) {
150                 if(yp_get_default_domain(&yp_domain))
151                         return (0);
152         }
153
154         if (!serv_stepping_yp) {
155                 if (key)
156                         free(key);
157                 if ((rv = yp_first(yp_domain, "services.byname", &key, &keylen,
158                              &result, &resultlen))) {
159                         serv_stepping_yp = 0;
160                         return(0);
161                 }
162                 serv_stepping_yp = 1;
163         } else {
164                 lastkey = key;
165                 rv = yp_next(yp_domain, "services.byname", key, keylen, &key,
166                              &keylen, &result, &resultlen);
167                 free(lastkey);
168                 if (rv) {
169                         serv_stepping_yp = 0;
170                         return (0);
171                 }
172         }
173
174         /* getservent() expects lines terminated with \n -- make it happy */
175         snprintf(line, BUFSIZ, "%.*s\n", resultlen, result);
176
177         free(result);
178
179         return(1);
180 }
181 #endif
182
183 void
184 setservent(f)
185         int f;
186 {
187         if (servf == NULL)
188                 servf = fopen(_PATH_SERVICES, "r" );
189         else
190                 rewind(servf);
191         _serv_stayopen |= f;
192 }
193
194 void
195 endservent()
196 {
197         if (servf) {
198                 fclose(servf);
199                 servf = NULL;
200         }
201         _serv_stayopen = 0;
202 }
203
204 struct servent *
205 getservent()
206 {
207         char *p;
208         char *cp, **q;
209
210 #ifdef YP
211         if (serv_stepping_yp && _getservent_yp(line)) {
212                 p = (char *)&line;
213                 goto unpack;
214         }
215 tryagain:
216 #endif
217         if (servf == NULL && (servf = fopen(_PATH_SERVICES, "r" )) == NULL)
218                 return (NULL);
219 again:
220         if ((p = fgets(line, BUFSIZ, servf)) == NULL)
221                 return (NULL);
222 #ifdef YP
223         if (*p == '+' && _yp_check(NULL)) {
224                 if (___getservbyname_yp != NULL) {
225                         if (!_getservbyname_yp(line))
226                                 goto tryagain;
227                 } 
228                 else if (___getservbyport_yp != 0) {
229                         if (!_getservbyport_yp(line))
230                                 goto tryagain;
231                 }
232                 else if (!_getservent_yp(line))
233                         goto tryagain;
234         }
235 unpack:
236 #endif
237         if (*p == '#')
238                 goto again;
239         cp = strpbrk(p, "#\n");
240         if (cp == NULL)
241                 goto again;
242         *cp = '\0';
243         serv.s_name = p;
244         p = strpbrk(p, " \t");
245         if (p == NULL)
246                 goto again;
247         *p++ = '\0';
248         while (*p == ' ' || *p == '\t')
249                 p++;
250         cp = strpbrk(p, ",/");
251         if (cp == NULL)
252                 goto again;
253         *cp++ = '\0';
254         serv.s_port = htons((u_short)atoi(p));
255         serv.s_proto = cp;
256         q = serv.s_aliases = serv_aliases;
257         cp = strpbrk(cp, " \t");
258         if (cp != NULL)
259                 *cp++ = '\0';
260         while (cp && *cp) {
261                 if (*cp == ' ' || *cp == '\t') {
262                         cp++;
263                         continue;
264                 }
265                 if (q < &serv_aliases[MAXALIASES - 1])
266                         *q++ = cp;
267                 cp = strpbrk(cp, " \t");
268                 if (cp != NULL)
269                         *cp++ = '\0';
270         }
271         *q = NULL;
272         return (&serv);
273 }