(lookup): Preserve errno value.
[kopensolaris-gnu/glibc.git] / hesiod / nss_hesiod / hesiod-proto.c
1 /* Copyright (C) 1997, 2000, 2002 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <errno.h>
21 #include <hesiod.h>
22 #include <netdb.h>
23 #include <netinet/in.h>
24 #include <nss.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "nss_hesiod.h"
30
31 /* Declare a parser for Hesiod protocol entries.  Although the format
32    of the entries is identical to those in /etc/protocols, here is no
33    predefined parser for us to use.  */
34
35 #define ENTNAME protoent
36
37 struct protoent_data {};
38
39 #define TRAILING_LIST_MEMBER            p_aliases
40 #define TRAILING_LIST_SEPARATOR_P       isspace
41 #include <nss/nss_files/files-parse.c>
42 LINE_PARSER
43 ("#",
44  STRING_FIELD (result->p_name, isspace, 1);
45  INT_FIELD (result->p_proto, isspace, 1, 10,);
46  )
47
48 enum nss_status
49 _nss_hesiod_setprotoent (int stayopen)
50 {
51   return NSS_STATUS_SUCCESS;
52 }
53
54 enum nss_status
55 _nss_hesiod_endprotoent (void)
56 {
57   return NSS_STATUS_SUCCESS;
58 }
59
60 static enum nss_status
61 lookup (const char *name, const char *type, struct protoent *proto,
62         char *buffer, size_t buflen, int *errnop)
63 {
64   struct parser_data *data = (void *) buffer;
65   size_t linebuflen;
66   void *context;
67   char **list, **item;
68   int parse_res;
69   int found;
70   int olderr = errno;
71
72   context = _nss_hesiod_init ();
73   if (context == NULL)
74     return NSS_STATUS_UNAVAIL;
75
76   list = hesiod_resolve (context, name, type);
77   if (list == NULL)
78     {
79       int err = errno;
80       hesiod_end (context);
81       __set_errno (olderr);
82       return err == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
83     }
84
85   linebuflen = buffer + buflen - data->linebuffer;
86
87   item = list;
88   found = 0;
89   do
90     {
91       size_t len = strlen (*item) + 1;
92
93       if (linebuflen < len)
94         {
95           hesiod_free_list (context, list);
96           hesiod_end (context);
97           *errnop = ERANGE;
98           return NSS_STATUS_TRYAGAIN;
99         }
100
101       memcpy (data->linebuffer, *item, len);
102
103       parse_res = parse_line (buffer, proto, data, buflen, errnop);
104       if (parse_res == -1)
105         {
106           hesiod_free_list (context, list);
107           hesiod_end (context);
108           return NSS_STATUS_TRYAGAIN;
109         }
110
111       if (parse_res > 0)
112         found = 1;
113
114       ++item;
115     }
116   while (*item != NULL && !found);
117
118   hesiod_free_list (context, list);
119   hesiod_end (context);
120
121   if (found == 0)
122     {
123       __set_errno (olderr);
124       return NSS_STATUS_NOTFOUND;
125     }
126
127   return NSS_STATUS_SUCCESS;
128 }
129
130 enum nss_status
131 _nss_hesiod_getprotobyname_r (const char *name, struct protoent *proto,
132                               char *buffer, size_t buflen, int *errnop)
133 {
134   return lookup (name, "protocol", proto, buffer, buflen, errnop);
135 }
136
137 enum nss_status
138 _nss_hesiod_getprotobynumber_r (const int protocol, struct protoent *proto,
139                                 char *buffer, size_t buflen, int *errnop)
140 {
141   char protostr[21];
142
143   snprintf (protostr, sizeof protostr, "%d", protocol);
144
145   return lookup (protostr, "protonum", proto, buffer, buflen, errnop);
146 }