kernel - Finish implementing PG_RAM / pipelined mmap operation
[dragonfly.git] / lib / libc / net / getservent.c
blob54557c786d4ac6b13eeba280becd3815ce61218b
1 /*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
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.
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.
29 * @(#)getservent.c 8.1 (Berkeley) 6/4/93
30 * $FreeBSD: src/lib/libc/net/getservent.c,v 1.23 2007/01/09 00:28:02 imp Exp $
31 * $DragonFly: src/lib/libc/net/getservent.c,v 1.7 2005/11/13 02:04:47 swildner Exp $
34 #include <sys/param.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <arpa/inet.h>
38 #include <errno.h>
39 #include <limits.h>
40 #include <netdb.h>
41 #include <nsswitch.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <stdlib.h>
45 #include <unistd.h>
46 #ifdef YP
47 #include <rpc/rpc.h>
48 #include <rpcsvc/yp_prot.h>
49 #include <rpcsvc/ypclnt.h>
50 #endif
51 #include "namespace.h"
52 #include "reentrant.h"
53 #include "un-namespace.h"
54 #include "netdb_private.h"
55 #ifdef NS_CACHING
56 #include "nscache.h"
57 #endif
58 #include "nss_tls.h"
60 enum constants
62 SETSERVENT = 1,
63 ENDSERVENT = 2,
64 SERVENT_STORAGE_INITIAL = 1 << 10, /* 1 KByte */
65 SERVENT_STORAGE_MAX = 1 << 20, /* 1 MByte */
68 struct servent_mdata
70 enum nss_lookup_type how;
71 int compat_mode;
74 static const ns_src defaultsrc[] = {
75 { NSSRC_COMPAT, NS_SUCCESS },
76 { NULL, 0 }
79 static int servent_unpack(char *, struct servent *, char **, size_t, int *);
81 /* files backend declarations */
82 struct files_state
84 FILE *fp;
85 int stayopen;
87 int compat_mode_active;
89 static void files_endstate(void *);
90 NSS_TLS_HANDLING(files);
92 static int files_servent(void *, void *, va_list);
93 static int files_setservent(void *, void *, va_list);
95 #ifdef YP
96 /* nis backend declarations */
97 static int nis_servent(void *, void *, va_list);
98 static int nis_setservent(void *, void *, va_list);
100 struct nis_state
102 int yp_stepping;
103 char yp_domain[MAXHOSTNAMELEN];
104 char *yp_key;
105 int yp_keylen;
107 static void nis_endstate(void *);
108 NSS_TLS_HANDLING(nis);
110 static int nis_servent(void *, void *, va_list);
111 static int nis_setservent(void *, void *, va_list);
112 #endif
114 /* compat backend declarations */
115 static int compat_setservent(void *, void *, va_list);
117 /* get** wrappers for get**_r functions declarations */
118 struct servent_state {
119 struct servent serv;
120 char *buffer;
121 size_t bufsize;
123 static void servent_endstate(void *);
124 NSS_TLS_HANDLING(servent);
126 struct key {
127 const char *proto;
128 union {
129 const char *name;
130 int port;
134 static int wrap_getservbyname_r(struct key, struct servent *, char *, size_t,
135 struct servent **);
136 static int wrap_getservbyport_r(struct key, struct servent *, char *, size_t,
137 struct servent **);
138 static int wrap_getservent_r(struct key, struct servent *, char *, size_t,
139 struct servent **);
140 static struct servent *getserv(int (*fn)(struct key, struct servent *, char *,
141 size_t, struct servent **), struct key);
143 #ifdef NS_CACHING
144 static int serv_id_func(char *, size_t *, va_list, void *);
145 static int serv_marshal_func(char *, size_t *, void *, va_list, void *);
146 static int serv_unmarshal_func(char *, size_t, void *, va_list, void *);
147 #endif
149 static int
150 servent_unpack(char *p, struct servent *serv, char **aliases,
151 size_t aliases_size, int *errnop)
153 char *cp, **q, *endp;
154 long l;
156 if (*p == '#')
157 return -1;
159 memset(serv, 0, sizeof(struct servent));
161 cp = strpbrk(p, "#\n");
162 if (cp != NULL)
163 *cp = '\0';
164 serv->s_name = p;
166 p = strpbrk(p, " \t");
167 if (p == NULL)
168 return -1;
169 *p++ = '\0';
170 while (*p == ' ' || *p == '\t')
171 p++;
172 cp = strpbrk(p, ",/");
173 if (cp == NULL)
174 return -1;
176 *cp++ = '\0';
177 l = strtol(p, &endp, 10);
178 if (endp == p || *endp != '\0' || l < 0 || l > USHRT_MAX)
179 return -1;
180 serv->s_port = htons((in_port_t)l);
181 serv->s_proto = cp;
183 q = serv->s_aliases = aliases;
184 cp = strpbrk(cp, " \t");
185 if (cp != NULL)
186 *cp++ = '\0';
187 while (cp && *cp) {
188 if (*cp == ' ' || *cp == '\t') {
189 cp++;
190 continue;
192 if (q < &aliases[aliases_size - 1]) {
193 *q++ = cp;
194 } else {
195 *q = NULL;
196 *errnop = ERANGE;
197 return -1;
199 cp = strpbrk(cp, " \t");
200 if (cp != NULL)
201 *cp++ = '\0';
203 *q = NULL;
205 return 0;
208 /* files backend implementation */
209 static void
210 files_endstate(void *p)
212 FILE * f;
214 if (p == NULL)
215 return;
217 f = ((struct files_state *)p)->fp;
218 if (f != NULL)
219 fclose(f);
221 free(p);
225 * compat structures. compat and files sources functionalities are almost
226 * equal, so they all are managed by files_servent function
228 static int
229 files_servent(void *retval, void *mdata, va_list ap)
231 static const ns_src compat_src[] = {
232 #ifdef YP
233 { NSSRC_NIS, NS_SUCCESS },
234 #endif
235 { NULL, 0 }
237 ns_dtab compat_dtab[] = {
238 #ifdef YP
239 { NSSRC_NIS, nis_servent,
240 (void *)((struct servent_mdata *)mdata)->how },
241 #endif
242 { NULL, NULL, NULL }
245 struct files_state *st;
246 int rv;
247 int stayopen;
249 struct servent_mdata *serv_mdata;
250 char *name;
251 char *proto;
252 int port;
254 struct servent *serv;
255 char *buffer;
256 size_t bufsize;
257 int *errnop;
259 char **aliases;
260 int aliases_size;
261 size_t linesize;
262 char *line;
263 char **cp;
265 name = NULL;
266 proto = NULL;
267 serv_mdata = (struct servent_mdata *)mdata;
268 switch (serv_mdata->how) {
269 case nss_lt_name:
270 name = va_arg(ap, char *);
271 proto = va_arg(ap, char *);
272 break;
273 case nss_lt_id:
274 port = va_arg(ap, int);
275 proto = va_arg(ap, char *);
276 break;
277 case nss_lt_all:
278 break;
279 default:
280 return NS_NOTFOUND;
283 serv = va_arg(ap, struct servent *);
284 buffer = va_arg(ap, char *);
285 bufsize = va_arg(ap, size_t);
286 errnop = va_arg(ap,int *);
288 *errnop = files_getstate(&st);
289 if (*errnop != 0)
290 return (NS_UNAVAIL);
292 if (st->fp == NULL)
293 st->compat_mode_active = 0;
295 if (st->fp == NULL && (st->fp = fopen(_PATH_SERVICES, "r")) == NULL) {
296 *errnop = errno;
297 return (NS_UNAVAIL);
300 if (serv_mdata->how == nss_lt_all)
301 stayopen = 1;
302 else {
303 rewind(st->fp);
304 stayopen = st->stayopen;
307 rv = NS_NOTFOUND;
308 do {
309 if (!st->compat_mode_active) {
310 if ((line = fgetln(st->fp, &linesize)) == NULL) {
311 *errnop = errno;
312 rv = NS_RETURN;
313 break;
316 if (*line=='+') {
317 if (serv_mdata->compat_mode != 0)
318 st->compat_mode_active = 1;
319 } else {
320 if (bufsize <= linesize + _ALIGNBYTES +
321 sizeof(char *)) {
322 *errnop = ERANGE;
323 rv = NS_RETURN;
324 break;
326 aliases = (char **)_ALIGN(&buffer[linesize+1]);
327 aliases_size = (buffer + bufsize -
328 (char *)aliases) / sizeof(char *);
329 if (aliases_size < 1) {
330 *errnop = ERANGE;
331 rv = NS_RETURN;
332 break;
335 memcpy(buffer, line, linesize);
336 buffer[linesize] = '\0';
340 if (st->compat_mode_active != 0) {
341 switch (serv_mdata->how) {
342 case nss_lt_name:
343 rv = nsdispatch(retval, compat_dtab,
344 NSDB_SERVICES_COMPAT, "getservbyname_r",
345 compat_src, name, proto, serv, buffer,
346 bufsize, errnop);
347 break;
348 case nss_lt_id:
349 rv = nsdispatch(retval, compat_dtab,
350 NSDB_SERVICES_COMPAT, "getservbyport_r",
351 compat_src, port, proto, serv, buffer,
352 bufsize, errnop);
353 break;
354 case nss_lt_all:
355 rv = nsdispatch(retval, compat_dtab,
356 NSDB_SERVICES_COMPAT, "getservent_r",
357 compat_src, serv, buffer, bufsize, errnop);
358 break;
361 if (!(rv & NS_TERMINATE) ||
362 serv_mdata->how != nss_lt_all)
363 st->compat_mode_active = 0;
365 continue;
368 rv = servent_unpack(buffer, serv, aliases, aliases_size,
369 errnop);
370 if (rv !=0 ) {
371 if (*errnop == 0) {
372 rv = NS_NOTFOUND;
373 continue;
375 else {
376 rv = NS_RETURN;
377 break;
381 rv = NS_NOTFOUND;
382 switch (serv_mdata->how) {
383 case nss_lt_name:
384 if (strcmp(name, serv->s_name) == 0)
385 goto gotname;
386 for (cp = serv->s_aliases; *cp; cp++)
387 if (strcmp(name, *cp) == 0)
388 goto gotname;
390 continue;
391 gotname:
392 if (proto == 0 || strcmp(serv->s_proto, proto) == 0)
393 rv = NS_SUCCESS;
394 break;
395 case nss_lt_id:
396 if (port != serv->s_port)
397 continue;
399 if (proto == 0 || strcmp(serv->s_proto, proto) == 0)
400 rv = NS_SUCCESS;
401 break;
402 case nss_lt_all:
403 rv = NS_SUCCESS;
404 break;
407 } while (!(rv & NS_TERMINATE));
409 if (!stayopen && st->fp != NULL) {
410 fclose(st->fp);
411 st->fp = NULL;
414 if ((rv == NS_SUCCESS) && (retval != NULL))
415 *(struct servent **)retval=serv;
417 return (rv);
420 static int
421 files_setservent(void *retval, void *mdata, va_list ap)
423 struct files_state *st;
424 int rv;
425 int f;
427 rv = files_getstate(&st);
428 if (rv != 0)
429 return (NS_UNAVAIL);
431 switch ((enum constants)mdata) {
432 case SETSERVENT:
433 f = va_arg(ap,int);
434 if (st->fp == NULL)
435 st->fp = fopen(_PATH_SERVICES, "r");
436 else
437 rewind(st->fp);
438 st->stayopen |= f;
439 break;
440 case ENDSERVENT:
441 if (st->fp != NULL) {
442 fclose(st->fp);
443 st->fp = NULL;
445 st->stayopen = 0;
446 break;
447 default:
448 break;
451 st->compat_mode_active = 0;
452 return (NS_UNAVAIL);
455 /* nis backend implementation */
456 #ifdef YP
457 static void
458 nis_endstate(void *p)
460 if (p == NULL)
461 return;
463 free(((struct nis_state *)p)->yp_key);
464 free(p);
467 static int
468 nis_servent(void *retval, void *mdata, va_list ap)
470 char *resultbuf, *lastkey;
471 int resultbuflen;
472 char buf[YPMAXRECORD + 2];
474 struct nis_state *st;
475 int rv;
477 enum nss_lookup_type how;
478 char *name;
479 char *proto;
480 int port;
482 struct servent *serv;
483 char *buffer;
484 size_t bufsize;
485 int *errnop;
487 char **aliases;
488 int aliases_size;
490 name = NULL;
491 proto = NULL;
492 how = (enum nss_lookup_type)mdata;
493 switch (how) {
494 case nss_lt_name:
495 name = va_arg(ap, char *);
496 proto = va_arg(ap, char *);
497 break;
498 case nss_lt_id:
499 port = va_arg(ap, int);
500 proto = va_arg(ap, char *);
501 break;
502 case nss_lt_all:
503 break;
504 default:
505 return NS_NOTFOUND;
508 serv = va_arg(ap, struct servent *);
509 buffer = va_arg(ap, char *);
510 bufsize = va_arg(ap, size_t);
511 errnop = va_arg(ap, int *);
513 *errnop = nis_getstate(&st);
514 if (*errnop != 0)
515 return (NS_UNAVAIL);
517 if (st->yp_domain[0] == '\0') {
518 if (getdomainname(st->yp_domain, sizeof st->yp_domain)) {
519 *errnop = errno;
520 return (NS_UNAVAIL);
524 do {
525 switch (how) {
526 case nss_lt_name:
527 snprintf(buf, sizeof(buf), "%s/%s", name, proto);
528 if (yp_match(st->yp_domain, "services.byname", buf,
529 strlen(buf), &resultbuf, &resultbuflen)) {
530 rv = NS_NOTFOUND;
531 goto fin;
533 break;
534 case nss_lt_id:
535 snprintf(buf, sizeof(buf), "%d/%s", ntohs(port),
536 proto);
539 * We have to be a little flexible
540 * here. Ideally you're supposed to have both
541 * a services.byname and a services.byport
542 * map, but some systems have only
543 * services.byname. FreeBSD cheats a little by
544 * putting the services.byport information in
545 * the same map as services.byname so that
546 * either case will work. We allow for both
547 * possibilities here: if there is no
548 * services.byport map, we try services.byname
549 * instead.
551 rv = yp_match(st->yp_domain, "services.byport", buf,
552 strlen(buf), &resultbuf, &resultbuflen);
553 if (rv) {
554 if (rv == YPERR_MAP) {
555 if (yp_match(st->yp_domain,
556 "services.byname", buf,
557 strlen(buf), &resultbuf,
558 &resultbuflen)) {
559 rv = NS_NOTFOUND;
560 goto fin;
562 } else {
563 rv = NS_NOTFOUND;
564 goto fin;
568 break;
569 case nss_lt_all:
570 if (!st->yp_stepping) {
571 free(st->yp_key);
572 rv = yp_first(st->yp_domain, "services.byname",
573 &st->yp_key, &st->yp_keylen, &resultbuf,
574 &resultbuflen);
575 if (rv) {
576 rv = NS_NOTFOUND;
577 goto fin;
579 st->yp_stepping = 1;
580 } else {
581 lastkey = st->yp_key;
582 rv = yp_next(st->yp_domain, "services.byname",
583 st->yp_key, st->yp_keylen, &st->yp_key,
584 &st->yp_keylen, &resultbuf, &resultbuflen);
585 free(lastkey);
586 if (rv) {
587 st->yp_stepping = 0;
588 rv = NS_NOTFOUND;
589 goto fin;
592 break;
595 /* we need a room for additional \n symbol */
596 if (bufsize <=
597 resultbuflen + 1 + _ALIGNBYTES + sizeof(char *)) {
598 *errnop = ERANGE;
599 rv = NS_RETURN;
600 break;
603 aliases = (char **)_ALIGN(&buffer[resultbuflen + 2]);
604 aliases_size =
605 (buffer + bufsize - (char *)aliases) / sizeof(char *);
606 if (aliases_size < 1) {
607 *errnop = ERANGE;
608 rv = NS_RETURN;
609 break;
613 * servent_unpack expects lines terminated with \n --
614 * make it happy
616 memcpy(buffer, resultbuf, resultbuflen);
617 buffer[resultbuflen] = '\n';
618 buffer[resultbuflen + 1] = '\0';
620 if (servent_unpack(buffer, serv, aliases, aliases_size,
621 errnop) != 0) {
622 if (*errnop == 0)
623 rv = NS_NOTFOUND;
624 else
625 rv = NS_RETURN;
626 } else
627 rv = NS_SUCCESS;
628 free(resultbuf);
630 } while (!(rv & NS_TERMINATE) && how == nss_lt_all);
632 fin:
633 if (rv == NS_SUCCESS && retval != NULL)
634 *(struct servent **)retval = serv;
636 return (rv);
639 static int
640 nis_setservent(void *result, void *mdata, va_list ap)
642 struct nis_state *st;
643 int rv;
645 rv = nis_getstate(&st);
646 if (rv != 0)
647 return (NS_UNAVAIL);
649 switch ((enum constants)mdata) {
650 case SETSERVENT:
651 case ENDSERVENT:
652 free(st->yp_key);
653 st->yp_key = NULL;
654 st->yp_stepping = 0;
655 break;
656 default:
657 break;
660 return (NS_UNAVAIL);
662 #endif
664 /* compat backend implementation */
665 static int
666 compat_setservent(void *retval, void *mdata, va_list ap)
668 static const ns_src compat_src[] = {
669 #ifdef YP
670 { NSSRC_NIS, NS_SUCCESS },
671 #endif
672 { NULL, 0 }
674 ns_dtab compat_dtab[] = {
675 #ifdef YP
676 { NSSRC_NIS, nis_setservent, mdata },
677 #endif
678 { NULL, NULL, NULL }
680 int f;
682 files_setservent(retval, mdata, ap);
684 switch ((enum constants)mdata) {
685 case SETSERVENT:
686 f = va_arg(ap, int);
687 nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT,
688 "setservent", compat_src, f);
689 break;
690 case ENDSERVENT:
691 nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT,
692 "endservent", compat_src);
693 break;
694 default:
695 break;
698 return (NS_UNAVAIL);
701 #ifdef NS_CACHING
702 static int
703 serv_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
705 char *name;
706 char *proto;
707 int port;
709 size_t desired_size, size, size2;
710 enum nss_lookup_type lookup_type;
711 int res = NS_UNAVAIL;
713 lookup_type = (enum nss_lookup_type)cache_mdata;
714 switch (lookup_type) {
715 case nss_lt_name:
716 name = va_arg(ap, char *);
717 proto = va_arg(ap, char *);
719 size = strlen(name);
720 desired_size = sizeof(enum nss_lookup_type) + size + 1;
721 if (proto != NULL) {
722 size2 = strlen(proto);
723 desired_size += size2 + 1;
724 } else
725 size2 = 0;
727 if (desired_size > *buffer_size) {
728 res = NS_RETURN;
729 goto fin;
732 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
733 memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
735 if (proto != NULL)
736 memcpy(buffer + sizeof(enum nss_lookup_type) + size + 1,
737 proto, size2 + 1);
739 res = NS_SUCCESS;
740 break;
741 case nss_lt_id:
742 port = va_arg(ap, int);
743 proto = va_arg(ap, char *);
745 desired_size = sizeof(enum nss_lookup_type) + sizeof(int);
746 if (proto != NULL) {
747 size = strlen(proto);
748 desired_size += size + 1;
749 } else
750 size = 0;
752 if (desired_size > *buffer_size) {
753 res = NS_RETURN;
754 goto fin;
757 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
758 memcpy(buffer + sizeof(enum nss_lookup_type), &port,
759 sizeof(int));
761 if (proto != NULL)
762 memcpy(buffer + sizeof(enum nss_lookup_type) +
763 sizeof(int), proto, size + 1);
765 res = NS_SUCCESS;
766 break;
767 default:
768 /* should be unreachable */
769 return (NS_UNAVAIL);
772 fin:
773 *buffer_size = desired_size;
774 return (res);
778 serv_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
779 void *cache_mdata)
781 char *name;
782 char *proto;
783 int port;
784 struct servent *serv;
785 char *orig_buf;
786 size_t orig_buf_size;
788 struct servent new_serv;
789 size_t desired_size;
790 char **alias;
791 char *p;
792 size_t size;
793 size_t aliases_size;
795 switch ((enum nss_lookup_type)cache_mdata) {
796 case nss_lt_name:
797 name = va_arg(ap, char *);
798 proto = va_arg(ap, char *);
799 break;
800 case nss_lt_id:
801 port = va_arg(ap, int);
802 proto = va_arg(ap, char *);
803 break;
804 case nss_lt_all:
805 break;
806 default:
807 /* should be unreachable */
808 return (NS_UNAVAIL);
811 serv = va_arg(ap, struct servent *);
812 orig_buf = va_arg(ap, char *);
813 orig_buf_size = va_arg(ap, size_t);
815 desired_size = _ALIGNBYTES + sizeof(struct servent) + sizeof(char *);
816 if (serv->s_name != NULL)
817 desired_size += strlen(serv->s_name) + 1;
818 if (serv->s_proto != NULL)
819 desired_size += strlen(serv->s_proto) + 1;
821 aliases_size = 0;
822 if (serv->s_aliases != NULL) {
823 for (alias = serv->s_aliases; *alias; ++alias) {
824 desired_size += strlen(*alias) + 1;
825 ++aliases_size;
828 desired_size += _ALIGNBYTES +
829 sizeof(char *) * (aliases_size + 1);
832 if (*buffer_size < desired_size) {
833 /* this assignment is here for future use */
834 *buffer_size = desired_size;
835 return (NS_RETURN);
838 memcpy(&new_serv, serv, sizeof(struct servent));
839 memset(buffer, 0, desired_size);
841 *buffer_size = desired_size;
842 p = buffer + sizeof(struct servent) + sizeof(char *);
843 memcpy(buffer + sizeof(struct servent), &p, sizeof(char *));
844 p = (char *)_ALIGN(p);
846 if (new_serv.s_name != NULL) {
847 size = strlen(new_serv.s_name);
848 memcpy(p, new_serv.s_name, size);
849 new_serv.s_name = p;
850 p += size + 1;
853 if (new_serv.s_proto != NULL) {
854 size = strlen(new_serv.s_proto);
855 memcpy(p, new_serv.s_proto, size);
856 new_serv.s_proto = p;
857 p += size + 1;
860 if (new_serv.s_aliases != NULL) {
861 p = (char *)_ALIGN(p);
862 memcpy(p, new_serv.s_aliases, sizeof(char *) * aliases_size);
863 new_serv.s_aliases = (char **)p;
864 p += sizeof(char *) * (aliases_size + 1);
866 for (alias = new_serv.s_aliases; *alias; ++alias) {
867 size = strlen(*alias);
868 memcpy(p, *alias, size);
869 *alias = p;
870 p += size + 1;
874 memcpy(buffer, &new_serv, sizeof(struct servent));
875 return (NS_SUCCESS);
879 serv_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
880 void *cache_mdata)
882 char *name;
883 char *proto;
884 int port;
885 struct servent *serv;
886 char *orig_buf;
887 char *p;
888 char **alias;
889 size_t orig_buf_size;
890 int *ret_errno;
892 switch ((enum nss_lookup_type)cache_mdata) {
893 case nss_lt_name:
894 name = va_arg(ap, char *);
895 proto = va_arg(ap, char *);
896 break;
897 case nss_lt_id:
898 port = va_arg(ap, int);
899 proto = va_arg(ap, char *);
900 break;
901 case nss_lt_all:
902 break;
903 default:
904 /* should be unreachable */
905 return (NS_UNAVAIL);
908 serv = va_arg(ap, struct servent *);
909 orig_buf = va_arg(ap, char *);
910 orig_buf_size = va_arg(ap, size_t);
911 ret_errno = va_arg(ap, int *);
913 if (orig_buf_size <
914 buffer_size - sizeof(struct servent) - sizeof(char *)) {
915 *ret_errno = ERANGE;
916 return (NS_RETURN);
919 memcpy(serv, buffer, sizeof(struct servent));
920 memcpy(&p, buffer + sizeof(struct servent), sizeof(char *));
922 orig_buf = (char *)_ALIGN(orig_buf);
923 memcpy(orig_buf, buffer + sizeof(struct servent) + sizeof(char *) +
924 (_ALIGN(p) - (size_t)p),
925 buffer_size - sizeof(struct servent) - sizeof(char *) -
926 (_ALIGN(p) - (size_t)p));
927 p = (char *)_ALIGN(p);
929 NS_APPLY_OFFSET(serv->s_name, orig_buf, p, char *);
930 NS_APPLY_OFFSET(serv->s_proto, orig_buf, p, char *);
931 if (serv->s_aliases != NULL) {
932 NS_APPLY_OFFSET(serv->s_aliases, orig_buf, p, char **);
934 for (alias = serv->s_aliases; *alias; ++alias)
935 NS_APPLY_OFFSET(*alias, orig_buf, p, char *);
938 if (retval != NULL)
939 *((struct servent **)retval) = serv;
940 return (NS_SUCCESS);
943 NSS_MP_CACHE_HANDLING(services);
944 #endif /* NS_CACHING */
946 /* get**_r functions implementation */
948 getservbyname_r(const char *name, const char *proto, struct servent *serv,
949 char *buffer, size_t bufsize, struct servent **result)
951 static const struct servent_mdata mdata = { nss_lt_name, 0 };
952 static const struct servent_mdata compat_mdata = { nss_lt_name, 1 };
953 #ifdef NS_CACHING
954 static const nss_cache_info cache_info =
955 NS_COMMON_CACHE_INFO_INITIALIZER(
956 services, (void *)nss_lt_name,
957 serv_id_func, serv_marshal_func, serv_unmarshal_func);
958 #endif /* NS_CACHING */
959 static const ns_dtab dtab[] = {
960 { NSSRC_FILES, files_servent, (void *)&mdata },
961 #ifdef YP
962 { NSSRC_NIS, nis_servent, (void *)nss_lt_name },
963 #endif
964 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
965 #ifdef NS_CACHING
966 NS_CACHE_CB(&cache_info)
967 #endif
968 { NULL, NULL, NULL }
970 int rv, ret_errno;
972 ret_errno = 0;
973 *result = NULL;
974 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyname_r",
975 defaultsrc, name, proto, serv, buffer, bufsize, &ret_errno);
977 if (rv == NS_SUCCESS)
978 return (0);
979 else
980 return (ret_errno);
984 getservbyport_r(int port, const char *proto, struct servent *serv,
985 char *buffer, size_t bufsize, struct servent **result)
987 static const struct servent_mdata mdata = { nss_lt_id, 0 };
988 static const struct servent_mdata compat_mdata = { nss_lt_id, 1 };
989 #ifdef NS_CACHING
990 static const nss_cache_info cache_info =
991 NS_COMMON_CACHE_INFO_INITIALIZER(
992 services, (void *)nss_lt_id,
993 serv_id_func, serv_marshal_func, serv_unmarshal_func);
994 #endif
995 static const ns_dtab dtab[] = {
996 { NSSRC_FILES, files_servent, (void *)&mdata },
997 #ifdef YP
998 { NSSRC_NIS, nis_servent, (void *)nss_lt_id },
999 #endif
1000 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
1001 #ifdef NS_CACHING
1002 NS_CACHE_CB(&cache_info)
1003 #endif
1004 { NULL, NULL, NULL }
1006 int rv, ret_errno;
1008 ret_errno = 0;
1009 *result = NULL;
1010 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyport_r",
1011 defaultsrc, port, proto, serv, buffer, bufsize, &ret_errno);
1013 if (rv == NS_SUCCESS)
1014 return (0);
1015 else
1016 return (ret_errno);
1020 getservent_r(struct servent *serv, char *buffer, size_t bufsize,
1021 struct servent **result)
1023 static const struct servent_mdata mdata = { nss_lt_all, 0 };
1024 static const struct servent_mdata compat_mdata = { nss_lt_all, 1 };
1025 #ifdef NS_CACHING
1026 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1027 services, (void *)nss_lt_all,
1028 serv_marshal_func, serv_unmarshal_func);
1029 #endif
1030 static const ns_dtab dtab[] = {
1031 { NSSRC_FILES, files_servent, (void *)&mdata },
1032 #ifdef YP
1033 { NSSRC_NIS, nis_servent, (void *)nss_lt_all },
1034 #endif
1035 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
1036 #ifdef NS_CACHING
1037 NS_CACHE_CB(&cache_info)
1038 #endif
1039 { NULL, NULL, NULL }
1041 int rv, ret_errno;
1043 ret_errno = 0;
1044 *result = NULL;
1045 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservent_r",
1046 defaultsrc, serv, buffer, bufsize, &ret_errno);
1048 if (rv == NS_SUCCESS)
1049 return (0);
1050 else
1051 return (ret_errno);
1054 void
1055 setservent(int stayopen)
1057 #ifdef NS_CACHING
1058 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1059 services, (void *)nss_lt_all,
1060 NULL, NULL);
1061 #endif
1062 static const ns_dtab dtab[] = {
1063 { NSSRC_FILES, files_setservent, (void *)SETSERVENT },
1064 #ifdef YP
1065 { NSSRC_NIS, nis_setservent, (void *)SETSERVENT },
1066 #endif
1067 { NSSRC_COMPAT, compat_setservent, (void *)SETSERVENT },
1068 #ifdef NS_CACHING
1069 NS_CACHE_CB(&cache_info)
1070 #endif
1071 { NULL, NULL, NULL }
1074 nsdispatch(NULL, dtab, NSDB_SERVICES, "setservent", defaultsrc,
1075 stayopen);
1078 void
1079 endservent(void)
1081 #ifdef NS_CACHING
1082 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1083 services, (void *)nss_lt_all,
1084 NULL, NULL);
1085 #endif
1086 static const ns_dtab dtab[] = {
1087 { NSSRC_FILES, files_setservent, (void *)ENDSERVENT },
1088 #ifdef YP
1089 { NSSRC_NIS, nis_setservent, (void *)ENDSERVENT },
1090 #endif
1091 { NSSRC_COMPAT, compat_setservent, (void *)ENDSERVENT },
1092 #ifdef NS_CACHING
1093 NS_CACHE_CB(&cache_info)
1094 #endif
1095 { NULL, NULL, NULL }
1098 nsdispatch(NULL, dtab, NSDB_SERVICES, "endservent", defaultsrc);
1101 /* get** wrappers for get**_r functions implementation */
1102 static void
1103 servent_endstate(void *p)
1105 if (p == NULL)
1106 return;
1108 free(((struct servent_state *)p)->buffer);
1109 free(p);
1112 static int
1113 wrap_getservbyname_r(struct key key, struct servent *serv, char *buffer,
1114 size_t bufsize, struct servent **res)
1116 return (getservbyname_r(key.name, key.proto, serv, buffer, bufsize,
1117 res));
1120 static int
1121 wrap_getservbyport_r(struct key key, struct servent *serv, char *buffer,
1122 size_t bufsize, struct servent **res)
1124 return (getservbyport_r(key.port, key.proto, serv, buffer, bufsize,
1125 res));
1128 static int
1129 wrap_getservent_r(struct key key, struct servent *serv, char *buffer,
1130 size_t bufsize, struct servent **res)
1132 return (getservent_r(serv, buffer, bufsize, res));
1135 static struct servent *
1136 getserv(int (*fn)(struct key, struct servent *, char *, size_t,
1137 struct servent **), struct key key)
1139 int rv;
1140 struct servent *res;
1141 struct servent_state * st;
1143 rv = servent_getstate(&st);
1144 if (rv != 0) {
1145 errno = rv;
1146 return NULL;
1149 if (st->buffer == NULL) {
1150 st->buffer = malloc(SERVENT_STORAGE_INITIAL);
1151 if (st->buffer == NULL)
1152 return (NULL);
1153 st->bufsize = SERVENT_STORAGE_INITIAL;
1155 do {
1156 rv = fn(key, &st->serv, st->buffer, st->bufsize, &res);
1157 if (res == NULL && rv == ERANGE) {
1158 free(st->buffer);
1159 if ((st->bufsize << 1) > SERVENT_STORAGE_MAX) {
1160 st->buffer = NULL;
1161 errno = ERANGE;
1162 return (NULL);
1164 st->bufsize <<= 1;
1165 st->buffer = malloc(st->bufsize);
1166 if (st->buffer == NULL)
1167 return (NULL);
1169 } while (res == NULL && rv == ERANGE);
1170 if (rv != 0)
1171 errno = rv;
1173 return (res);
1176 struct servent *
1177 getservbyname(const char *name, const char *proto)
1179 struct key key;
1181 key.name = name;
1182 key.proto = proto;
1184 return (getserv(wrap_getservbyname_r, key));
1187 struct servent *
1188 getservbyport(int port, const char *proto)
1190 struct key key;
1192 key.port = port;
1193 key.proto = proto;
1195 return (getserv(wrap_getservbyport_r, key));
1198 struct servent *
1199 getservent(void)
1201 struct key key;
1203 key.proto = NULL;
1204 key.port = 0;
1206 return (getserv(wrap_getservent_r, key));