Cygwin: strptime: add release note
[newlib-cygwin.git] / winsup / cygwin / netdb.cc
blobcfae78220707b5eba5d8bde5e35571e68f288cad
1 /* netdb.cc: network database related routines.
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7 details. */
9 #include "winsup.h"
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <netdb.h>
13 #include <shared_info.h>
15 /* Locate and open a system network database file. relative_path
16 should be one of the following values:
17 "protocol"
18 "services"
19 "networks"
20 "hosts"
22 It is the callers responsibility to close the file. */
23 static FILE *
24 open_system_file (const char *relative_path)
26 /* system dir path is never longer. */
27 char win32_name[MAX_PATH];
29 user_shared->warned_msdos = true;
30 sys_wcstombs (win32_name, MAX_PATH, windows_system_directory);
31 strcat (win32_name, "drivers\\etc\\");
32 strcat (win32_name, relative_path);
33 FILE *result = fopen (win32_name, "rt");
34 debug_printf ("handle to netdb file %s: %p", win32_name, result);
35 return result;
38 inline static FILE *
39 open_protocol_file ()
41 return open_system_file ("protocol");
44 /* Wrapper for open_system_file(), fixing the constant name
45 "services". Returns the open file. */
46 inline static FILE *
47 open_services_file ()
49 return open_system_file ("services");
52 /* Read an entire line up till the next \n character. Memory for the
53 line is dynamically allocated, and the caller must call free() to
54 deallocate it. When the end of file is reached, NULL is returned. */
55 static char *
56 get_entire_line (FILE *fd)
58 static const int BUFF_SIZE = 1024;
59 struct line_fragment
61 char buffer[BUFF_SIZE];
62 line_fragment *next;
65 line_fragment *fragment_list_head = NULL;
66 line_fragment *fragment = NULL;
67 int fragment_count = 0;
68 char *result;
72 line_fragment *new_fragment = (line_fragment *) malloc (sizeof (line_fragment));
73 paranoid_printf ("line fragment allocated %p", new_fragment);
74 if (!fragment_list_head)
75 fragment_list_head = new_fragment;
76 if (fragment)
77 fragment->next = new_fragment;
78 fragment = new_fragment;
79 fragment->next = NULL;
80 *fragment->buffer = '\0';
81 result = fgets (fragment->buffer, BUFF_SIZE, fd);
82 ++fragment_count;
84 while (result && !strchr (fragment->buffer, '\n'));
86 if (*fragment_list_head->buffer != '\0')
88 char *concatenated_line = (char *) calloc (fragment_count * BUFF_SIZE , sizeof (char));
89 paranoid_printf ("concatenated line allocated %p", concatenated_line);
90 *concatenated_line = '\0';
91 fragment = fragment_list_head;
92 while (fragment != NULL)
94 line_fragment *previous = fragment;
95 strcat (concatenated_line, fragment->buffer);
96 fragment = fragment->next;
97 free (previous);
99 return concatenated_line;
101 else
103 fragment = fragment_list_head;
104 while (fragment != NULL)
106 line_fragment *previous = fragment;
107 fragment = fragment->next;
108 free (previous);
110 return NULL;
114 /* Characters representing whitespace. Used by parse_* routines to
115 delimit tokens. */
116 static const char *SPACE = " \t\n\r\f";
118 /* Parse a list aliases from a network database file. Returns a
119 char** structure terminated by a NULL. */
120 static void
121 parse_alias_list (char ***aliases, char **lasts)
123 struct alias_t
125 char *alias_name;
126 alias_t *next;
128 alias_t *alias_list_head = NULL, *alias_list_tail = NULL;
129 char *alias;
130 int alias_count = 0;
131 alias = strtok_r (NULL, SPACE, lasts);
133 while (alias)
135 ++alias_count;
136 alias_t *new_alias = (alias_t *) malloc (sizeof (alias_t));
137 paranoid_printf ("new alias alloc %p", new_alias);
138 if (!alias_list_head)
139 alias_list_head = new_alias;
140 if (alias_list_tail)
141 alias_list_tail->next = new_alias;
142 new_alias->next = NULL;
143 new_alias->alias_name = alias;
144 alias_list_tail = new_alias;
145 alias = strtok_r (NULL, SPACE, lasts);
148 *aliases = (char**) calloc (alias_count + 1, sizeof (char *));
149 paranoid_printf ("aliases alloc %p", *aliases);
151 char **current_entry = *aliases;
152 while (alias_list_head)
154 alias_t *previous = alias_list_head;
155 *current_entry = strdup (alias_list_head->alias_name);
156 paranoid_printf ("*current entry strdup %p", *current_entry);
157 alias_list_head = alias_list_head->next;
158 free (previous);
159 ++current_entry;
162 *current_entry = NULL;
165 /* Read the next line from svc_file, and parse it into the structure
166 pointed to by sep. sep can point to stack or static data, but it's
167 members will be overwritten with pointers to dynamically allocated
168 heap data accommodating parsed data. It is the responsibility of the
169 caller to free up the allocated structures. The function returns true
170 to indicate that a line was successfully read and parsed. False is
171 used to indicate that no more lines can be read and parsed. This
172 should also interpreted as end of file. */
173 static bool
174 parse_services_line (FILE *svc_file, struct servent *sep)
176 char *line;
177 while ((line = get_entire_line (svc_file)))
179 char *name, *port, *protocol, *lasts;
181 line[strcspn (line, "#")] = '\0'; // truncate at comment marker.
182 name = strtok_r (line, SPACE, &lasts);
183 if (!name)
185 free (line);
186 continue;
188 port = strtok_r (NULL, SPACE, &lasts);
189 protocol = strchr (port, '/');
190 *protocol++ = '\0';
191 sep->s_name = strdup (name);
192 paranoid_printf ("sep->s_name strdup %p", sep->s_name);
193 sep->s_port = htons (atoi (port));
194 sep->s_proto = strdup (protocol);
195 paranoid_printf ("sep->s_proto strdup %p", sep->s_proto);
196 /* parse_alias_list relies on side effects. Read the comments
197 for that function.*/
198 parse_alias_list (& sep->s_aliases, &lasts);
199 free (line);
200 return true;
202 return false;
205 static FILE *svc_file = NULL;
206 static long int svc_read_pos = 0;
207 static struct servent current_servent;
209 /* Steps through a struct servent, and frees all of the internal
210 structures.*/
211 static void
212 free_servent (struct servent *sep)
214 free (sep->s_name);
215 free (sep->s_proto);
216 char ** current = sep->s_aliases;
217 while (current && *current)
219 free (*current);
220 ++current;
222 free (sep->s_aliases);
223 sep->s_name = NULL;
224 sep->s_port = 0;
225 sep->s_proto = NULL;
226 sep->s_aliases = NULL;
229 extern "C" void
230 cygwin_setservent (int stay_open)
232 if (svc_file)
233 fclose (svc_file);
234 if (stay_open)
235 svc_file = open_services_file ();
236 free_servent (&current_servent);
237 svc_read_pos = 0;
238 syscall_printf ("setservent (%d)", stay_open);
241 extern "C" struct servent *
242 cygwin_getservent (void)
244 FILE *fd;
245 if (svc_file)
246 fd = svc_file;
247 else
249 fd = open_services_file ();
250 if (!fd)
252 syscall_printf ("%p = getservent()", NULL);
253 return NULL;
255 fseek (fd, svc_read_pos, SEEK_SET);
257 free_servent (&current_servent);
258 bool found = parse_services_line (fd, &current_servent);
259 if (!svc_file)
261 svc_read_pos = ftell (fd);
262 fclose (fd);
264 struct servent *result;
265 if (found)
266 result = &current_servent;
267 else
268 result = NULL;
269 syscall_printf ("%p = getservent()", result);
270 return result;
273 extern "C" void
274 cygwin_endservent (void)
276 if (svc_file)
278 fclose (svc_file);
279 svc_file = NULL;
281 free_servent (&current_servent);
282 svc_read_pos = 0;
283 syscall_printf ("endservent ()");
286 /* Read the next line from proto_file, and parse it into the structure
287 pointed to by pep. pep can point to stack or static data, but it's
288 members will be overwritten with pointers to dynamically allocated
289 heap data accommodating parsed data. It is the responsibility of the
290 caller to free up the allocated structures. The function returns true
291 to indicate that a line was successfully read and parsed. False is
292 used to indicate that no more lines can be read and parsed. This
293 should also interpreted as end of file. */
294 static bool
295 parse_protocol_line (FILE *proto_file, struct protoent *pep)
297 char *line;
298 while ((line = get_entire_line (proto_file)))
300 char *name, *protocol, *lasts;
302 line[strcspn (line, "#")] = '\0'; // truncate at comment marker.
303 name = strtok_r (line, SPACE, &lasts);
304 if (!name)
306 free (line);
307 continue;
309 protocol = strtok_r (NULL, SPACE, &lasts);
310 pep->p_name = strdup (name);
311 paranoid_printf ("pep->p_name strdup %p", pep->p_name);
312 pep->p_proto = atoi (protocol);
313 /* parse_alias_list relies on side effects. Read the comments
314 for that function.*/
315 parse_alias_list (& pep->p_aliases, &lasts);
316 free (line);
317 return true;
319 return false;
322 static FILE *proto_file = NULL;
323 static long int proto_read_pos = 0;
324 static struct protoent current_protoent;
326 /* Steps through a struct protoent, and frees all the internal
327 structures. */
328 static void
329 free_protoent (struct protoent *pep)
331 free (pep->p_name);
332 char ** current = pep->p_aliases;
333 while (current && *current)
335 free (*current);
336 ++current;
338 free (pep->p_aliases);
339 pep->p_name = NULL;
340 pep->p_proto = 0;
341 pep->p_aliases = NULL;
344 extern "C" void
345 cygwin_setprotoent (int stay_open)
347 if (proto_file)
348 fclose (proto_file);
350 if (stay_open)
351 proto_file = open_protocol_file ();
353 free_protoent (&current_protoent);
354 proto_read_pos = 0;
355 syscall_printf ("setprotoent (%d)", stay_open);
358 extern "C" struct protoent *
359 cygwin_getprotoent (void)
361 FILE *fd;
363 if (proto_file)
364 fd = proto_file;
365 else
367 fd = open_protocol_file ();
368 if (!fd)
370 syscall_printf ("%p = getprotoent()", NULL);
371 return NULL;
373 fseek (fd, proto_read_pos, SEEK_SET);
375 free_protoent (&current_protoent);
377 bool found = parse_protocol_line (fd, &current_protoent);
378 if (!proto_file)
380 proto_read_pos = ftell (fd);
381 fclose (fd);
384 struct protoent *result;
385 if (found)
386 result = &current_protoent;
387 else
388 result = NULL;
390 syscall_printf ("%p = getprotoent()", result);
391 return result;
394 extern "C" void
395 cygwin_endprotoent (void)
397 if (proto_file)
399 fclose (proto_file);
400 proto_file = NULL;
403 free_protoent (&current_protoent);
404 proto_read_pos = 0;
405 syscall_printf ("endprotoent ()");