Let tst-swscanf find its locale
[platform/upstream/glibc.git] / resolv / res_query.c
1 /*
2  * Copyright (c) 1988, 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  * 4. 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
30 /*
31  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
32  *
33  * Permission to use, copy, modify, and distribute this software for any
34  * purpose with or without fee is hereby granted, provided that the above
35  * copyright notice and this permission notice appear in all copies, and that
36  * the name of Digital Equipment Corporation not be used in advertising or
37  * publicity pertaining to distribution of the document or software without
38  * specific, written prior permission.
39  *
40  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
41  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
42  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
43  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
44  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
45  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
46  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47  * SOFTWARE.
48  */
49
50 /*
51  * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
52  *
53  * Permission to use, copy, modify, and distribute this software for any
54  * purpose with or without fee is hereby granted, provided that the above
55  * copyright notice and this permission notice appear in all copies.
56  *
57  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
58  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
59  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
60  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
61  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
62  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
63  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
64  * SOFTWARE.
65  */
66
67 #if defined(LIBC_SCCS) && !defined(lint)
68 static const char sccsid[] = "@(#)res_query.c   8.1 (Berkeley) 6/4/93";
69 static const char rcsid[] = "$BINDId: res_query.c,v 8.20 2000/02/29 05:39:12 vixie Exp $";
70 #endif /* LIBC_SCCS and not lint */
71
72 #include <assert.h>
73 #include <sys/types.h>
74 #include <sys/param.h>
75 #include <netinet/in.h>
76 #include <arpa/inet.h>
77 #include <arpa/nameser.h>
78 #include <ctype.h>
79 #include <errno.h>
80 #include <netdb.h>
81 #include <resolv.h>
82 #include <stdio.h>
83 #include <stdlib.h>
84 #include <string.h>
85
86 /* Options.  Leave them on. */
87 /* #undef DEBUG */
88
89 #if PACKETSZ > 65536
90 #define MAXPACKET       PACKETSZ
91 #else
92 #define MAXPACKET       65536
93 #endif
94
95 #define QUERYSIZE       (HFIXEDSZ + QFIXEDSZ + MAXCDNAME + 1)
96
97 static int
98 __libc_res_nquerydomain(res_state statp, const char *name, const char *domain,
99                         int class, int type, u_char *answer, int anslen,
100                         u_char **answerp, u_char **answerp2, int *nanswerp2,
101                         int *resplen2);
102
103 /*
104  * Formulate a normal query, send, and await answer.
105  * Returned answer is placed in supplied buffer "answer".
106  * Perform preliminary check of answer, returning success only
107  * if no error is indicated and the answer count is nonzero.
108  * Return the size of the response on success, -1 on error.
109  * Error number is left in H_ERRNO.
110  *
111  * Caller must parse answer and determine whether it answers the question.
112  */
113 int
114 __libc_res_nquery(res_state statp,
115                   const char *name,     /* domain name */
116                   int class, int type,  /* class and type of query */
117                   u_char *answer,       /* buffer to put answer */
118                   int anslen,           /* size of answer buffer */
119                   u_char **answerp,     /* if buffer needs to be enlarged */
120                   u_char **answerp2,
121                   int *nanswerp2,
122                   int *resplen2)
123 {
124         HEADER *hp = (HEADER *) answer;
125         HEADER *hp2;
126         int n, use_malloc = 0;
127         u_int oflags = statp->_flags;
128
129         size_t bufsize = (type == T_UNSPEC ? 2 : 1) * QUERYSIZE;
130         u_char *buf = alloca (bufsize);
131         u_char *query1 = buf;
132         int nquery1 = -1;
133         u_char *query2 = NULL;
134         int nquery2 = 0;
135
136  again:
137         hp->rcode = NOERROR;    /* default */
138
139 #ifdef DEBUG
140         if (statp->options & RES_DEBUG)
141                 printf(";; res_query(%s, %d, %d)\n", name, class, type);
142 #endif
143
144         if (type == T_UNSPEC)
145           {
146             n = res_nmkquery(statp, QUERY, name, class, T_A, NULL, 0, NULL,
147                              query1, bufsize);
148             if (n > 0)
149               {
150                 if ((oflags & RES_F_EDNS0ERR) == 0
151                     && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
152                   {
153                     n = __res_nopt(statp, n, query1, bufsize, anslen / 2);
154                     if (n < 0)
155                       goto unspec_nomem;
156                   }
157
158                 nquery1 = n;
159                 /* Align the buffer.  */
160                 int npad = ((nquery1 + __alignof__ (HEADER) - 1)
161                             & ~(__alignof__ (HEADER) - 1)) - nquery1;
162                 if (n > bufsize - npad)
163                   {
164                     n = -1;
165                     goto unspec_nomem;
166                   }
167                 int nused = n + npad;
168                 query2 = buf + nused;
169                 n = res_nmkquery(statp, QUERY, name, class, T_AAAA, NULL, 0,
170                                  NULL, query2, bufsize - nused);
171                 if (n > 0
172                     && (oflags & RES_F_EDNS0ERR) == 0
173                     && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
174                   n = __res_nopt(statp, n, query2, bufsize - nused - n,
175                                  anslen / 2);
176                 nquery2 = n;
177               }
178
179           unspec_nomem:;
180           }
181         else
182           {
183             n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
184                              query1, bufsize);
185
186             if (n > 0
187                 && (oflags & RES_F_EDNS0ERR) == 0
188                 && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
189               n = __res_nopt(statp, n, query1, bufsize, anslen);
190
191             nquery1 = n;
192           }
193
194         if (__builtin_expect (n <= 0, 0) && !use_malloc) {
195                 /* Retry just in case res_nmkquery failed because of too
196                    short buffer.  Shouldn't happen.  */
197                 bufsize = (type == T_UNSPEC ? 2 : 1) * MAXPACKET;
198                 buf = malloc (bufsize);
199                 if (buf != NULL) {
200                         query1 = buf;
201                         use_malloc = 1;
202                         goto again;
203                 }
204         }
205         if (__builtin_expect (n <= 0, 0)) {
206                 /* If the query choked with EDNS0, retry without EDNS0.  */
207                 if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0
208                     && ((oflags ^ statp->_flags) & RES_F_EDNS0ERR) != 0) {
209                         statp->_flags |= RES_F_EDNS0ERR;
210 #ifdef DEBUG
211                         if (statp->options & RES_DEBUG)
212                                 printf(";; res_nquery: retry without EDNS0\n");
213 #endif
214                         goto again;
215                 }
216 #ifdef DEBUG
217                 if (statp->options & RES_DEBUG)
218                         printf(";; res_query: mkquery failed\n");
219 #endif
220                 RES_SET_H_ERRNO(statp, NO_RECOVERY);
221                 if (use_malloc)
222                         free (buf);
223                 return (n);
224         }
225         assert (answerp == NULL || (void *) *answerp == (void *) answer);
226         n = __libc_res_nsend(statp, query1, nquery1, query2, nquery2, answer,
227                              anslen, answerp, answerp2, nanswerp2, resplen2);
228         if (use_malloc)
229                 free (buf);
230         if (n < 0) {
231 #ifdef DEBUG
232                 if (statp->options & RES_DEBUG)
233                         printf(";; res_query: send error\n");
234 #endif
235                 RES_SET_H_ERRNO(statp, TRY_AGAIN);
236                 return (n);
237         }
238
239         if (answerp != NULL)
240           /* __libc_res_nsend might have reallocated the buffer.  */
241           hp = (HEADER *) *answerp;
242
243         /* We simplify the following tests by assigning HP to HP2 or
244            vice versa.  It is easy to verify that this is the same as
245            ignoring all tests of HP or HP2.  */
246         if (answerp2 == NULL || *resplen2 < (int) sizeof (HEADER))
247           {
248             hp2 = hp;
249           }
250         else
251           {
252             hp2 = (HEADER *) *answerp2;
253             if (n < (int) sizeof (HEADER))
254               {
255                 hp = hp2;
256               }
257           }
258
259         /* Make sure both hp and hp2 are defined */
260         assert((hp != NULL) && (hp2 != NULL));
261
262         if ((hp->rcode != NOERROR || ntohs(hp->ancount) == 0)
263             && (hp2->rcode != NOERROR || ntohs(hp2->ancount) == 0)) {
264 #ifdef DEBUG
265                 if (statp->options & RES_DEBUG) {
266                         printf(";; rcode = %d, ancount=%d\n", hp->rcode,
267                             ntohs(hp->ancount));
268                         if (hp != hp2)
269                           printf(";; rcode2 = %d, ancount2=%d\n", hp2->rcode,
270                                  ntohs(hp2->ancount));
271                 }
272 #endif
273                 switch (hp->rcode == NOERROR ? hp2->rcode : hp->rcode) {
274                 case NXDOMAIN:
275                         if ((hp->rcode == NOERROR && ntohs (hp->ancount) != 0)
276                             || (hp2->rcode == NOERROR
277                                 && ntohs (hp2->ancount) != 0))
278                                 goto success;
279                         RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
280                         break;
281                 case SERVFAIL:
282                         RES_SET_H_ERRNO(statp, TRY_AGAIN);
283                         break;
284                 case NOERROR:
285                         if (ntohs (hp->ancount) != 0
286                             || ntohs (hp2->ancount) != 0)
287                                 goto success;
288                         RES_SET_H_ERRNO(statp, NO_DATA);
289                         break;
290                 case FORMERR:
291                 case NOTIMP:
292                         /* Servers must not reply to AAAA queries with
293                            NOTIMP etc but some of them do.  */
294                         if ((hp->rcode == NOERROR && ntohs (hp->ancount) != 0)
295                             || (hp2->rcode == NOERROR
296                                 && ntohs (hp2->ancount) != 0))
297                                 goto success;
298                         /* FALLTHROUGH */
299                 case REFUSED:
300                 default:
301                         RES_SET_H_ERRNO(statp, NO_RECOVERY);
302                         break;
303                 }
304                 return (-1);
305         }
306  success:
307         return (n);
308 }
309 libresolv_hidden_def (__libc_res_nquery)
310
311 int
312 res_nquery(res_state statp,
313            const char *name,    /* domain name */
314            int class, int type, /* class and type of query */
315            u_char *answer,      /* buffer to put answer */
316            int anslen)          /* size of answer buffer */
317 {
318         return __libc_res_nquery(statp, name, class, type, answer, anslen,
319                                  NULL, NULL, NULL, NULL);
320 }
321 libresolv_hidden_def (res_nquery)
322
323 /*
324  * Formulate a normal query, send, and retrieve answer in supplied buffer.
325  * Return the size of the response on success, -1 on error.
326  * If enabled, implement search rules until answer or unrecoverable failure
327  * is detected.  Error code, if any, is left in H_ERRNO.
328  */
329 int
330 __libc_res_nsearch(res_state statp,
331                    const char *name,    /* domain name */
332                    int class, int type, /* class and type of query */
333                    u_char *answer,      /* buffer to put answer */
334                    int anslen,          /* size of answer */
335                    u_char **answerp,
336                    u_char **answerp2,
337                    int *nanswerp2,
338                    int *resplen2)
339 {
340         const char *cp, * const *domain;
341         HEADER *hp = (HEADER *) answer;
342         char tmp[NS_MAXDNAME];
343         u_int dots;
344         int trailing_dot, ret, saved_herrno;
345         int got_nodata = 0, got_servfail = 0, root_on_list = 0;
346         int tried_as_is = 0;
347         int searched = 0;
348
349         __set_errno (0);
350         RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);  /* True if we never query. */
351
352         dots = 0;
353         for (cp = name; *cp != '\0'; cp++)
354                 dots += (*cp == '.');
355         trailing_dot = 0;
356         if (cp > name && *--cp == '.')
357                 trailing_dot++;
358
359         /* If there aren't any dots, it could be a user-level alias. */
360         if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
361                 return (__libc_res_nquery(statp, cp, class, type, answer,
362                                           anslen, answerp, answerp2,
363                                           nanswerp2, resplen2));
364
365 #ifdef DEBUG
366         if (statp->options & RES_DEBUG)
367                 printf("dots=%d, statp->ndots=%d, trailing_dot=%d, name=%s\n",
368                        (int)dots,(int)statp->ndots,(int)trailing_dot,name);
369 #endif
370
371         /*
372          * If there are enough dots in the name, let's just give it a
373          * try 'as is'. The threshold can be set with the "ndots" option.
374          * Also, query 'as is', if there is a trailing dot in the name.
375          */
376         saved_herrno = -1;
377         if (dots >= statp->ndots || trailing_dot) {
378                 ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
379                                               answer, anslen, answerp,
380                                               answerp2, nanswerp2, resplen2);
381                 if (ret > 0 || trailing_dot)
382                         return (ret);
383                 saved_herrno = h_errno;
384                 tried_as_is++;
385                 if (answerp && *answerp != answer) {
386                         answer = *answerp;
387                         anslen = MAXPACKET;
388                 }
389                 if (answerp2
390                     && (*answerp2 < answer || *answerp2 >= answer + anslen))
391                   {
392                     free (*answerp2);
393                     *answerp2 = NULL;
394                   }
395         }
396
397         /*
398          * We do at least one level of search if
399          *      - there is no dot and RES_DEFNAME is set, or
400          *      - there is at least one dot, there is no trailing dot,
401          *        and RES_DNSRCH is set.
402          */
403         if ((!dots && (statp->options & RES_DEFNAMES) != 0) ||
404             (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0)) {
405                 int done = 0;
406
407                 for (domain = (const char * const *)statp->dnsrch;
408                      *domain && !done;
409                      domain++) {
410                         searched = 1;
411
412                         if (domain[0][0] == '\0' ||
413                             (domain[0][0] == '.' && domain[0][1] == '\0'))
414                                 root_on_list++;
415
416                         ret = __libc_res_nquerydomain(statp, name, *domain,
417                                                       class, type,
418                                                       answer, anslen, answerp,
419                                                       answerp2, nanswerp2,
420                                                       resplen2);
421                         if (ret > 0)
422                                 return (ret);
423
424                         if (answerp && *answerp != answer) {
425                                 answer = *answerp;
426                                 anslen = MAXPACKET;
427                         }
428                         if (answerp2
429                             && (*answerp2 < answer
430                                 || *answerp2 >= answer + anslen))
431                           {
432                             free (*answerp2);
433                             *answerp2 = NULL;
434                           }
435
436                         /*
437                          * If no server present, give up.
438                          * If name isn't found in this domain,
439                          * keep trying higher domains in the search list
440                          * (if that's enabled).
441                          * On a NO_DATA error, keep trying, otherwise
442                          * a wildcard entry of another type could keep us
443                          * from finding this entry higher in the domain.
444                          * If we get some other error (negative answer or
445                          * server failure), then stop searching up,
446                          * but try the input name below in case it's
447                          * fully-qualified.
448                          */
449                         if (errno == ECONNREFUSED) {
450                                 RES_SET_H_ERRNO(statp, TRY_AGAIN);
451                                 return (-1);
452                         }
453
454                         switch (statp->res_h_errno) {
455                         case NO_DATA:
456                                 got_nodata++;
457                                 /* FALLTHROUGH */
458                         case HOST_NOT_FOUND:
459                                 /* keep trying */
460                                 break;
461                         case TRY_AGAIN:
462                                 if (hp->rcode == SERVFAIL) {
463                                         /* try next search element, if any */
464                                         got_servfail++;
465                                         break;
466                                 }
467                                 /* FALLTHROUGH */
468                         default:
469                                 /* anything else implies that we're done */
470                                 done++;
471                         }
472
473                         /* if we got here for some reason other than DNSRCH,
474                          * we only wanted one iteration of the loop, so stop.
475                          */
476                         if ((statp->options & RES_DNSRCH) == 0)
477                                 done++;
478                 }
479         }
480
481         /*
482          * f the query has not already been tried as is then try it
483          * unless RES_NOTLDQUERY is set and there were no dots.
484          */
485         if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0)
486             && !(tried_as_is || root_on_list)) {
487                 ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
488                                               answer, anslen, answerp,
489                                               answerp2, nanswerp2, resplen2);
490                 if (ret > 0)
491                         return (ret);
492         }
493
494         /* if we got here, we didn't satisfy the search.
495          * if we did an initial full query, return that query's H_ERRNO
496          * (note that we wouldn't be here if that query had succeeded).
497          * else if we ever got a nodata, send that back as the reason.
498          * else send back meaningless H_ERRNO, that being the one from
499          * the last DNSRCH we did.
500          */
501         if (answerp2 && (*answerp2 < answer || *answerp2 >= answer + anslen))
502           {
503             free (*answerp2);
504             *answerp2 = NULL;
505           }
506         if (saved_herrno != -1)
507                 RES_SET_H_ERRNO(statp, saved_herrno);
508         else if (got_nodata)
509                 RES_SET_H_ERRNO(statp, NO_DATA);
510         else if (got_servfail)
511                 RES_SET_H_ERRNO(statp, TRY_AGAIN);
512         return (-1);
513 }
514 libresolv_hidden_def (__libc_res_nsearch)
515
516 int
517 res_nsearch(res_state statp,
518             const char *name,   /* domain name */
519             int class, int type,        /* class and type of query */
520             u_char *answer,     /* buffer to put answer */
521             int anslen)         /* size of answer */
522 {
523         return __libc_res_nsearch(statp, name, class, type, answer,
524                                   anslen, NULL, NULL, NULL, NULL);
525 }
526 libresolv_hidden_def (res_nsearch)
527
528 /*
529  * Perform a call on res_query on the concatenation of name and domain,
530  * removing a trailing dot from name if domain is NULL.
531  */
532 static int
533 __libc_res_nquerydomain(res_state statp,
534                         const char *name,
535                         const char *domain,
536                         int class, int type,    /* class and type of query */
537                         u_char *answer,         /* buffer to put answer */
538                         int anslen,                     /* size of answer */
539                         u_char **answerp,
540                         u_char **answerp2,
541                         int *nanswerp2,
542                         int *resplen2)
543 {
544         char nbuf[MAXDNAME];
545         const char *longname = nbuf;
546         size_t n, d;
547
548 #ifdef DEBUG
549         if (statp->options & RES_DEBUG)
550                 printf(";; res_nquerydomain(%s, %s, %d, %d)\n",
551                        name, domain?domain:"<Nil>", class, type);
552 #endif
553         if (domain == NULL) {
554                 /*
555                  * Check for trailing '.';
556                  * copy without '.' if present.
557                  */
558                 n = strlen(name);
559
560                 /* Decrement N prior to checking it against MAXDNAME
561                    so that we detect a wrap to SIZE_MAX and return
562                    a reasonable error.  */
563                 n--;
564                 if (n >= MAXDNAME - 1) {
565                         RES_SET_H_ERRNO(statp, NO_RECOVERY);
566                         return (-1);
567                 }
568                 if (name[n] == '.') {
569                         strncpy(nbuf, name, n);
570                         nbuf[n] = '\0';
571                 } else
572                         longname = name;
573         } else {
574                 n = strlen(name);
575                 d = strlen(domain);
576                 if (n + d + 1 >= MAXDNAME) {
577                         RES_SET_H_ERRNO(statp, NO_RECOVERY);
578                         return (-1);
579                 }
580                 sprintf(nbuf, "%s.%s", name, domain);
581         }
582         return (__libc_res_nquery(statp, longname, class, type, answer,
583                                   anslen, answerp, answerp2, nanswerp2,
584                                   resplen2));
585 }
586
587 int
588 res_nquerydomain(res_state statp,
589             const char *name,
590             const char *domain,
591             int class, int type,        /* class and type of query */
592             u_char *answer,             /* buffer to put answer */
593             int anslen)         /* size of answer */
594 {
595         return __libc_res_nquerydomain(statp, name, domain, class, type,
596                                        answer, anslen, NULL, NULL, NULL, NULL);
597 }
598 libresolv_hidden_def (res_nquerydomain)
599
600 const char *
601 res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
602         char *file, *cp1, *cp2;
603         char buf[BUFSIZ];
604         FILE *fp;
605
606         if (statp->options & RES_NOALIASES)
607                 return (NULL);
608         file = getenv("HOSTALIASES");
609         if (file == NULL || (fp = fopen(file, "rce")) == NULL)
610                 return (NULL);
611         setbuf(fp, NULL);
612         buf[sizeof(buf) - 1] = '\0';
613         while (fgets(buf, sizeof(buf), fp)) {
614                 for (cp1 = buf; *cp1 && !isspace(*cp1); ++cp1)
615                         ;
616                 if (!*cp1)
617                         break;
618                 *cp1 = '\0';
619                 if (ns_samename(buf, name) == 1) {
620                         while (isspace(*++cp1))
621                                 ;
622                         if (!*cp1)
623                                 break;
624                         for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2)
625                                 ;
626                         *cp2 = '\0';
627                         strncpy(dst, cp1, siz - 1);
628                         dst[siz - 1] = '\0';
629                         fclose(fp);
630                         return (dst);
631                 }
632         }
633         fclose(fp);
634         return (NULL);
635 }
636 libresolv_hidden_def (res_hostalias)