]>
Commit | Line | Data |
---|---|---|
838ad582 CF |
1 | /* netdb.cc: network database related routines. |
2 | ||
bc837d22 | 3 | Copyright 2002, 2003, 2007, 2008, 2010, 2011 Red Hat, Inc. |
838ad582 CF |
4 | |
5 | This file is part of Cygwin. | |
6 | ||
7 | This software is a copyrighted work licensed under the terms of the | |
8 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
9 | details. */ | |
10 | ||
11 | #include "winsup.h" | |
838ad582 | 12 | #include <stdio.h> |
838ad582 CF |
13 | #include <stdlib.h> |
14 | #include <netdb.h> | |
8d1bda71 | 15 | #include <shared_info.h> |
838ad582 CF |
16 | |
17 | /* Locate and open a system network database file. relative_path | |
18 | should be one of the following values: | |
19 | "protocol" | |
20 | "services" | |
21 | "networks" | |
22 | "hosts" | |
23 | ||
838ad582 CF |
24 | It is the callers responsibility to close the file. */ |
25 | static FILE * | |
26 | open_system_file (const char *relative_path) | |
27 | { | |
27114d3a CV |
28 | /* system dir path is never longer. */ |
29 | char win32_name[MAX_PATH]; | |
570858c3 | 30 | |
8d1bda71 | 31 | user_shared->warned_msdos = true; |
893a8b78 CV |
32 | sys_wcstombs (win32_name, MAX_PATH, windows_system_directory); |
33 | strcat (win32_name, "drivers\\etc\\"); | |
838ad582 | 34 | strcat (win32_name, relative_path); |
27114d3a | 35 | FILE *result = fopen (win32_name, "rt"); |
893a8b78 | 36 | debug_printf ("handle to netdb file %s: %p", win32_name, result); |
838ad582 CF |
37 | return result; |
38 | } | |
39 | ||
40 | inline static FILE * | |
41 | open_protocol_file () | |
42 | { | |
43 | return open_system_file ("protocol"); | |
44 | } | |
45 | ||
46 | /* Wrapper for open_system_file(), fixing the constant name | |
47 | "services". Returns the open file. */ | |
48 | inline static FILE * | |
49 | open_services_file () | |
50 | { | |
51 | return open_system_file ("services"); | |
52 | } | |
53 | ||
54 | /* Read an entire line up till the next \n character. Memory for the | |
55 | line is dynamically allocated, and the caller must call free() to | |
56 | deallocate it. When the end of file is reached, NULL is returned. */ | |
57 | static char * | |
58 | get_entire_line (FILE *fd) | |
59 | { | |
60 | static const int BUFF_SIZE = 1024; | |
61 | struct line_fragment | |
62 | { | |
63 | char buffer[BUFF_SIZE]; | |
64 | line_fragment *next; | |
65 | }; | |
66 | ||
67 | line_fragment *fragment_list_head = NULL; | |
68 | line_fragment *fragment = NULL; | |
69 | int fragment_count = 0; | |
70 | char *result; | |
71 | ||
72 | do | |
73 | { | |
74 | line_fragment *new_fragment = (line_fragment *) malloc (sizeof (line_fragment)); | |
75 | paranoid_printf ("line fragment allocated %p", new_fragment); | |
76 | if (!fragment_list_head) | |
77 | fragment_list_head = new_fragment; | |
78 | if (fragment) | |
79 | fragment->next = new_fragment; | |
80 | fragment = new_fragment; | |
81 | fragment->next = NULL; | |
82 | *fragment->buffer = '\0'; | |
83 | result = fgets (fragment->buffer, BUFF_SIZE, fd); | |
84 | ++fragment_count; | |
85 | } | |
86 | while (result && !strchr (fragment->buffer, '\n')); | |
87 | ||
88 | if (*fragment_list_head->buffer != '\0') | |
89 | { | |
90 | char *concatenated_line = (char *) calloc (fragment_count * BUFF_SIZE , sizeof (char)); | |
91 | paranoid_printf ("concatenated line allocated %p", concatenated_line); | |
92 | *concatenated_line = '\0'; | |
93 | fragment = fragment_list_head; | |
94 | while (fragment != NULL) | |
95 | { | |
96 | line_fragment *previous = fragment; | |
97 | strcat (concatenated_line, fragment->buffer); | |
98 | fragment = fragment->next; | |
99 | free (previous); | |
100 | } | |
101 | return concatenated_line; | |
102 | } | |
103 | else | |
104 | { | |
105 | fragment = fragment_list_head; | |
106 | while (fragment != NULL) | |
107 | { | |
108 | line_fragment *previous = fragment; | |
109 | fragment = fragment->next; | |
110 | free (previous); | |
111 | } | |
112 | return NULL; | |
113 | } | |
114 | } | |
115 | ||
116 | /* Characters representing whitespace. Used by parse_* routines to | |
117 | delimit tokens. */ | |
118 | static const NO_COPY char *SPACE = " \t\n\r\f"; | |
119 | ||
120 | /* Parse a list aliases from a network database file. Returns a | |
b60e545b | 121 | char** structure terminated by a NULL. */ |
838ad582 | 122 | static void |
bb241345 | 123 | parse_alias_list (char ***aliases, char **lasts) |
838ad582 CF |
124 | { |
125 | struct alias_t | |
126 | { | |
127 | char *alias_name; | |
128 | alias_t *next; | |
129 | }; | |
130 | alias_t *alias_list_head = NULL, *alias_list_tail = NULL; | |
131 | char *alias; | |
132 | int alias_count = 0; | |
bb241345 | 133 | alias = strtok_r (NULL, SPACE, lasts); |
838ad582 CF |
134 | |
135 | while (alias) | |
136 | { | |
137 | ++alias_count; | |
138 | alias_t *new_alias = (alias_t *) malloc (sizeof (alias_t)); | |
139 | paranoid_printf ("new alias alloc %p", new_alias); | |
140 | if (!alias_list_head) | |
141 | alias_list_head = new_alias; | |
142 | if (alias_list_tail) | |
143 | alias_list_tail->next = new_alias; | |
144 | new_alias->next = NULL; | |
145 | new_alias->alias_name = alias; | |
146 | alias_list_tail = new_alias; | |
bb241345 | 147 | alias = strtok_r (NULL, SPACE, lasts); |
838ad582 CF |
148 | } |
149 | ||
150 | *aliases = (char**) calloc (alias_count + 1, sizeof (char *)); | |
151 | paranoid_printf ("aliases alloc %p", *aliases); | |
152 | ||
153 | char **current_entry = *aliases; | |
154 | while (alias_list_head) | |
155 | { | |
156 | alias_t *previous = alias_list_head; | |
157 | *current_entry = strdup (alias_list_head->alias_name); | |
158 | paranoid_printf ("*current entry strdup %p", *current_entry); | |
159 | alias_list_head = alias_list_head->next; | |
160 | free (previous); | |
161 | ++current_entry; | |
162 | } | |
163 | ||
164 | *current_entry = NULL; | |
165 | } | |
166 | ||
167 | /* Read the next line from svc_file, and parse it into the structure | |
168 | pointed to by sep. sep can point to stack or static data, but it's | |
169 | members will be overwritten with pointers to dynamically allocated | |
170 | heap data accommodating parsed data. It is the responsibility of the | |
171 | caller to free up the allocated structures. The function returns true | |
172 | to indicate that a line was successfully read and parsed. False is | |
173 | used to indicate that no more lines can be read and parsed. This | |
174 | should also interpreted as end of file. */ | |
175 | static bool | |
176 | parse_services_line (FILE *svc_file, struct servent *sep) | |
177 | { | |
178 | char *line; | |
179 | while ((line = get_entire_line (svc_file))) | |
180 | { | |
bb241345 | 181 | char *name, *port, *protocol, *lasts; |
838ad582 CF |
182 | |
183 | line[strcspn (line, "#")] = '\0'; // truncate at comment marker. | |
bb241345 | 184 | name = strtok_r (line, SPACE, &lasts); |
838ad582 CF |
185 | if (!name) |
186 | { | |
187 | free (line); | |
188 | continue; | |
189 | } | |
bb241345 | 190 | port = strtok_r (NULL, SPACE, &lasts); |
838ad582 CF |
191 | protocol = strchr (port, '/'); |
192 | *protocol++ = '\0'; | |
193 | sep->s_name = strdup (name); | |
194 | paranoid_printf ("sep->s_name strdup %p", sep->s_name); | |
195 | sep->s_port = atoi (port); | |
196 | sep->s_proto = strdup (protocol); | |
197 | paranoid_printf ("sep->s_proto strdup %p", sep->s_proto); | |
198 | /* parse_alias_list relies on side effects. Read the comments | |
199 | for that function.*/ | |
bb241345 | 200 | parse_alias_list (& sep->s_aliases, &lasts); |
838ad582 CF |
201 | free (line); |
202 | return true; | |
203 | } | |
204 | return false; | |
205 | } | |
206 | ||
207 | static FILE *svc_file = NULL; | |
208 | static long int svc_read_pos = 0; | |
209 | static struct servent current_servent; | |
210 | ||
211 | /* Steps through a struct servent, and frees all of the internal | |
212 | structures.*/ | |
213 | static void | |
214 | free_servent (struct servent *sep) | |
215 | { | |
216 | free (sep->s_name); | |
217 | free (sep->s_proto); | |
218 | char ** current = sep->s_aliases; | |
219 | while (current && *current) | |
220 | { | |
221 | free (*current); | |
222 | ++current; | |
223 | } | |
224 | free (sep->s_aliases); | |
225 | sep->s_name = NULL; | |
226 | sep->s_port = 0; | |
227 | sep->s_proto = NULL; | |
228 | sep->s_aliases = NULL; | |
229 | } | |
230 | ||
231 | extern "C" void | |
232 | cygwin_setservent (int stay_open) | |
233 | { | |
234 | if (svc_file) | |
235 | fclose (svc_file); | |
236 | if (stay_open) | |
237 | svc_file = open_services_file (); | |
238 | free_servent (¤t_servent); | |
239 | svc_read_pos = 0; | |
240 | syscall_printf ("setservent (%d)", stay_open); | |
241 | } | |
242 | ||
243 | extern "C" struct servent * | |
244 | cygwin_getservent (void) | |
245 | { | |
246 | FILE *fd; | |
247 | if (svc_file) | |
248 | fd = svc_file; | |
249 | else | |
250 | { | |
251 | fd = open_services_file (); | |
252 | if (!fd) | |
253 | { | |
254 | syscall_printf ("%p = getservent()", NULL); | |
255 | return NULL; | |
256 | } | |
257 | fseek (fd, svc_read_pos, SEEK_SET); | |
258 | } | |
259 | free_servent (¤t_servent); | |
260 | bool found = parse_services_line (fd, ¤t_servent); | |
261 | if (!svc_file) | |
262 | { | |
263 | svc_read_pos = ftell (fd); | |
264 | fclose (fd); | |
265 | } | |
266 | struct servent *result; | |
267 | if (found) | |
268 | result = ¤t_servent; | |
269 | else | |
270 | result = NULL; | |
271 | syscall_printf ("%p = getservent()", result); | |
272 | return result; | |
273 | } | |
274 | ||
275 | extern "C" void | |
276 | cygwin_endservent (void) | |
277 | { | |
278 | if (svc_file) | |
279 | { | |
280 | fclose (svc_file); | |
281 | svc_file = NULL; | |
282 | } | |
283 | free_servent (¤t_servent); | |
284 | svc_read_pos = 0; | |
285 | syscall_printf ("endservent ()"); | |
286 | } | |
287 | ||
288 | /* Read the next line from proto_file, and parse it into the structure | |
289 | pointed to by pep. pep can point to stack or static data, but it's | |
290 | members will be overwritten with pointers to dynamically allocated | |
291 | heap data accommodating parsed data. It is the responsibility of the | |
292 | caller to free up the allocated structures. The function returns true | |
293 | to indicate that a line was successfully read and parsed. False is | |
294 | used to indicate that no more lines can be read and parsed. This | |
295 | should also interpreted as end of file. */ | |
296 | static bool | |
297 | parse_protocol_line (FILE *proto_file, struct protoent *pep) | |
298 | { | |
299 | char *line; | |
300 | while ((line = get_entire_line (proto_file))) | |
301 | { | |
bb241345 | 302 | char *name, *protocol, *lasts; |
838ad582 CF |
303 | |
304 | line[strcspn (line, "#")] = '\0'; // truncate at comment marker. | |
bb241345 | 305 | name = strtok_r (line, SPACE, &lasts); |
838ad582 CF |
306 | if (!name) |
307 | { | |
308 | free (line); | |
309 | continue; | |
310 | } | |
bb241345 | 311 | protocol = strtok_r (NULL, SPACE, &lasts); |
838ad582 CF |
312 | pep->p_name = strdup (name); |
313 | paranoid_printf ("pep->p_name strdup %p", pep->p_name); | |
314 | pep->p_proto = atoi (protocol); | |
315 | /* parse_alias_list relies on side effects. Read the comments | |
316 | for that function.*/ | |
bb241345 | 317 | parse_alias_list (& pep->p_aliases, &lasts); |
838ad582 CF |
318 | free (line); |
319 | return true; | |
320 | } | |
321 | return false; | |
322 | } | |
323 | ||
324 | static FILE *proto_file = NULL; | |
325 | static long int proto_read_pos = 0; | |
326 | static struct protoent current_protoent; | |
327 | ||
328 | /* Steps through a struct protoent, and frees all the internal | |
329 | structures. */ | |
330 | static void | |
331 | free_protoent (struct protoent *pep) | |
332 | { | |
333 | free (pep->p_name); | |
334 | char ** current = pep->p_aliases; | |
335 | while (current && *current) | |
336 | { | |
337 | free (*current); | |
338 | ++current; | |
339 | } | |
340 | free (pep->p_aliases); | |
341 | pep->p_name = NULL; | |
342 | pep->p_proto = 0; | |
343 | pep->p_aliases = NULL; | |
344 | } | |
345 | ||
346 | extern "C" void | |
347 | cygwin_setprotoent (int stay_open) | |
348 | { | |
349 | if (proto_file) | |
350 | fclose (proto_file); | |
351 | ||
352 | if (stay_open) | |
353 | proto_file = open_protocol_file (); | |
354 | ||
355 | free_protoent (¤t_protoent); | |
356 | proto_read_pos = 0; | |
357 | syscall_printf ("setprotoent (%d)", stay_open); | |
358 | } | |
359 | ||
360 | extern "C" struct protoent * | |
361 | cygwin_getprotoent (void) | |
362 | { | |
363 | FILE *fd; | |
364 | ||
365 | if (proto_file) | |
366 | fd = proto_file; | |
367 | else | |
368 | { | |
369 | fd = open_protocol_file (); | |
370 | if (!fd) | |
371 | { | |
372 | syscall_printf ("%p = getprotoent()", NULL); | |
373 | return NULL; | |
374 | } | |
375 | fseek (fd, proto_read_pos, SEEK_SET); | |
376 | } | |
377 | free_protoent (¤t_protoent); | |
378 | ||
379 | bool found = parse_protocol_line (fd, ¤t_protoent); | |
380 | if (!proto_file) | |
381 | { | |
382 | proto_read_pos = ftell (fd); | |
383 | fclose (fd); | |
384 | } | |
385 | ||
386 | struct protoent *result; | |
387 | if (found) | |
388 | result = ¤t_protoent; | |
389 | else | |
390 | result = NULL; | |
391 | ||
392 | syscall_printf ("%p = getprotoent()", result); | |
393 | return result; | |
394 | } | |
395 | ||
396 | extern "C" void | |
397 | cygwin_endprotoent (void) | |
398 | { | |
399 | if (proto_file) | |
400 | { | |
401 | fclose (proto_file); | |
402 | proto_file = NULL; | |
403 | } | |
404 | ||
405 | free_protoent (¤t_protoent); | |
406 | proto_read_pos = 0; | |
407 | syscall_printf ("endprotoent ()"); | |
408 | } |