OSDN Git Service

ldso: Add remaining relocation types to the table
[uclinux-h8/uClibc.git] / libc / inet / getnet.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Copyright (C) 2010 Bernhard Reutner-Fischer <uclibc@uclibc.org>
4  *
5  * Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
6  */
7
8 /* /etc/networks
9 #   network-name  number     [aliases ...]
10 loopback          127.0.0.0  # optional aliases
11
12 network-name: symbolic name of the netwkork
13 number: official number of the network in dotted quad
14 aliases: case sensitive optional space or tab separated list of other names
15 */
16
17 #include <features.h>
18 #include <netdb.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <errno.h>
24 #include <unistd.h>
25 #include "internal/parse_config.h"
26
27 #include <bits/uClibc_mutex.h>
28 __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
29
30 #define MINTOKENS       2
31 #define MAXALIASES      8
32 #define MAXTOKENS       (MINTOKENS + MAXALIASES + 1)
33 #define BUFSZ           (255) /* one line */
34 #define SBUFSIZE        (BUFSZ + 1 + (sizeof(char *) * MAXTOKENS))
35
36 static parser_t *netp = NULL;
37 static struct netent nete;
38 static char *netbuf = NULL;
39 static smallint net_stayopen;
40
41 void setnetent(int stayopen)
42 {
43         __UCLIBC_MUTEX_LOCK(mylock);
44         if (netp)
45                 config_close(netp);
46         netp = config_open(_PATH_NETWORKS);
47         if (stayopen)
48                 net_stayopen = 1;
49         __UCLIBC_MUTEX_UNLOCK(mylock);
50 }
51 libc_hidden_def(setnetent)
52
53 void endnetent(void)
54 {
55         __UCLIBC_MUTEX_LOCK(mylock);
56         if (netp) {
57                 config_close(netp);
58                 netp = NULL;
59         }
60         net_stayopen = 0;
61         __UCLIBC_MUTEX_UNLOCK(mylock);
62 }
63 libc_hidden_def(endnetent)
64
65 int getnetent_r(struct netent *result_buf,
66                                 char *buf, size_t buflen, struct netent **result,
67                                 int *h_errnop
68                                  )
69 {
70         char **tok = NULL;
71         const size_t aliaslen = sizeof(char *) * MAXTOKENS;
72         int ret = ERANGE;
73
74         *result = NULL;
75         if (buflen < aliaslen
76                 || (buflen - aliaslen) < BUFSZ + 1)
77                 goto DONE_NOUNLOCK;
78
79         __UCLIBC_MUTEX_LOCK(mylock);
80         ret = ENOENT;
81         if (netp == NULL)
82                 setnetent(net_stayopen);
83         if (netp == NULL)
84                 goto DONE;
85         netp->data = buf;
86         netp->data_len = aliaslen;
87         netp->line_len = buflen - aliaslen;
88         /* <name>[[:space:]]<netnumber>[[:space:]][<aliases>] */
89         if (!config_read(netp, &tok, MAXTOKENS-1, MINTOKENS, "# \t/", PARSE_NORMAL)) {
90                 goto DONE;
91         }
92         result_buf->n_name = *(tok++);
93         {
94                 struct addrinfo hints, *addri;
95 # define sa4_to_uint32(sa) \
96         (ntohl(((struct sockaddr_in*)sa)->sin_addr.s_addr))
97 #ifdef __UCLIBC_HAS_IPV6__
98 # define sa6_to_uint8(sa) \
99         (ntohl(((struct sockaddr_in6*)sa)->sin6_addr.s6_addr))
100 #endif
101                 memset(&hints, 0, sizeof(struct addrinfo));
102                 hints.ai_family = AF_UNSPEC;
103                 hints.ai_flags = AI_NUMERICHOST;
104                 getaddrinfo(*(tok++), NULL, &hints, &addri);
105                 result_buf->n_addrtype = addri->ai_family;
106                 result_buf->n_net =
107 #if 0 /*FIXME: implement me! def __UCLIBC_HAS_IPV6__ */
108                         addri->ai_family == AF_INET6 ? sa6_to_uint8(addri->ai_addr) :
109 #endif
110                         sa4_to_uint32(addri->ai_addr);
111                 freeaddrinfo(addri);
112         }
113         result_buf->n_aliases = tok;
114         *result = result_buf;
115         ret = 0;
116  DONE:
117         __UCLIBC_MUTEX_UNLOCK(mylock);
118  DONE_NOUNLOCK:
119         errno = ret;
120         return errno;
121 }
122 libc_hidden_def(getnetent_r)
123
124 static void __initbuf(void)
125 {
126         if (!netbuf) {
127                 netbuf = malloc(SBUFSIZE);
128                 if (!netbuf)
129                         abort();
130         }
131 }
132
133 struct netent *getnetent(void)
134 {
135         struct netent *result;
136         int herrnop;
137
138         __initbuf();
139         getnetent_r(&nete, netbuf, SBUFSIZE, &result, &herrnop);
140         return result;
141 }
142
143 int getnetbyname_r(const char *name,
144                                         struct netent *result_buf, char *buf, size_t buflen,
145                                         struct netent **result,
146                                         int *h_errnop
147                                         )
148 {
149         register char **cp;
150         int ret, herrnop;
151
152         __UCLIBC_MUTEX_LOCK(mylock);
153         setnetent(net_stayopen);
154         while (!(ret = getnetent_r(result_buf, buf, buflen, result, &herrnop))) {
155                 if (strcmp(name, result_buf->n_name) == 0)
156                         break;
157                 for (cp = result_buf->n_aliases; *cp; cp++)
158                         if (strcmp(name, *cp) == 0)
159                                 goto gotname;
160         }
161  gotname:
162         if (!net_stayopen)
163                 endnetent();
164         __UCLIBC_MUTEX_UNLOCK(mylock);
165         return *result ? 0 : ret;
166 }
167 libc_hidden_def(getnetbyname_r)
168
169 struct netent *getnetbyname(const char *name)
170 {
171         struct netent *result;
172         int herrnop;
173
174         __initbuf();
175         getnetbyname_r(name, &nete, netbuf, SBUFSIZE, &result, &herrnop);
176         return result;
177 }
178
179 int getnetbyaddr_r(uint32_t net, int type,
180                                         struct netent *result_buf, char *buf,
181                                         size_t buflen, struct netent **result,
182                                         int *h_errnop)
183 {
184         int ret, herrnop;
185
186         __UCLIBC_MUTEX_LOCK(mylock);
187         setnetent(net_stayopen);
188         while (!(ret = getnetent_r(result_buf, buf, buflen, result, &herrnop))) {
189                 if (net == result_buf->n_net && type == result_buf->n_addrtype)
190                         break;
191         }
192         if (!net_stayopen)
193                 endnetent();
194         __UCLIBC_MUTEX_UNLOCK(mylock);
195         return *result ? 0 : ret;
196 }
197 libc_hidden_def(getnetbyaddr_r)
198
199 struct netent *getnetbyaddr(uint32_t net, int type)
200 {
201         struct netent *result;
202         int herrnop;
203
204         __initbuf();
205         getnetbyaddr_r(net, type, &nete, netbuf, SBUFSIZE, &result, &herrnop);
206         return result;
207 }
208