Cygwin: strptime: add release note
[newlib-cygwin.git] / winsup / cygwin / fhandler / procnet.cc
blobd512887d5f8f30366267a53e377ba75db1b9ada1
1 /* fhandler_procnet.cc: fhandler for /proc/net virtual filesystem
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 #define __INSIDE_CYGWIN_NET__
10 #define USE_SYS_TYPES_FD_SET
11 #include "winsup.h"
12 /* 2014-04-24: Current Mingw headers define sockaddr_in6 using u_long (8 byte)
13 because a redefinition for LP64 systems is missing. This leads to a wrong
14 definition and size of sockaddr_in6 when building with winsock headers. */
15 #undef u_long
16 #define u_long __ms_u_long
17 #include <w32api/ws2tcpip.h>
18 #include <w32api/iphlpapi.h>
19 #include <asm/byteorder.h>
20 #include <stdio.h>
21 #include "cygerrno.h"
22 #include "path.h"
23 #include "fhandler.h"
24 #include "fhandler_virtual.h"
25 #include "dtable.h"
27 bool get_adapters_addresses (PIP_ADAPTER_ADDRESSES *pa0, ULONG family);
29 static off_t format_procnet_ifinet6 (void *, char *&);
31 static const virt_tab_t procnet_tab[] =
33 { _VN ("."), FH_PROCNET, virt_directory, NULL },
34 { _VN (".."), FH_PROCNET, virt_directory, NULL },
35 { _VN ("if_inet6"), FH_PROCNET, virt_file, format_procnet_ifinet6 },
36 { NULL, 0, FH_NADA, virt_none, NULL }
39 static const int PROCNET_LINK_COUNT =
40 (sizeof (procnet_tab) / sizeof (virt_tab_t)) - 1;
42 virtual_ftype_t
43 fhandler_procnet::exists ()
45 const char *path = get_name ();
46 debug_printf ("exists (%s)", path);
47 path += proc_len + 1;
48 while (*path != 0 && !isdirsep (*path))
49 path++;
50 if (*path == 0)
51 return virt_rootdir;
53 virt_tab_t *entry = virt_tab_search (path + 1, false, procnet_tab,
54 PROCNET_LINK_COUNT);
55 if (entry)
57 if (entry->type == virt_file && !get_adapters_addresses (NULL, AF_INET6))
58 return virt_none;
59 fileid = entry - procnet_tab;
60 return entry->type;
62 return virt_none;
65 fhandler_procnet::fhandler_procnet ():
66 fhandler_proc ()
70 int
71 fhandler_procnet::fstat (struct stat *buf)
73 fhandler_base::fstat (buf);
74 buf->st_mode &= ~_IFMT & NO_W;
75 int file_type = exists ();
76 switch (file_type)
78 case virt_none:
79 set_errno (ENOENT);
80 return -1;
81 case virt_directory:
82 case virt_rootdir:
83 buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
84 buf->st_nlink = 2;
85 return 0;
86 case virt_file:
87 default:
88 buf->st_mode |= S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
89 return 0;
93 int
94 fhandler_procnet::readdir (DIR *dir, dirent *de)
96 int res = ENMFILE;
97 if (dir->__d_position >= PROCNET_LINK_COUNT)
98 goto out;
99 if (procnet_tab[dir->__d_position].type == virt_file
100 && !get_adapters_addresses (NULL, AF_INET6))
101 goto out;
102 strcpy (de->d_name, procnet_tab[dir->__d_position].name);
103 de->d_type = virt_ftype_to_dtype (procnet_tab[dir->__d_position].type);
104 dir->__d_position++;
105 dir->__flags |= dirent_saw_dot | dirent_saw_dot_dot;
106 res = 0;
107 out:
108 syscall_printf ("%d = readdir(%p, %p) (%s)", res, dir, de, de->d_name);
109 return res;
113 fhandler_procnet::open (int flags, mode_t mode)
115 int res = fhandler_virtual::open (flags, mode);
116 if (!res)
117 goto out;
119 nohandle (true);
121 const char *path;
122 path = get_name () + proc_len + 1;
123 while (*path != 0 && !isdirsep (*path))
124 path++;
126 if (*path == 0)
128 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
130 set_errno (EEXIST);
131 res = 0;
132 goto out;
134 else if (flags & O_WRONLY)
136 set_errno (EISDIR);
137 res = 0;
138 goto out;
140 else
142 diropen = true;
143 goto success;
147 virt_tab_t *entry;
148 entry = virt_tab_search (path + 1, true, procnet_tab, PROCNET_LINK_COUNT);
149 if (!entry)
151 set_errno ((flags & O_CREAT) ? EROFS : ENOENT);
152 res = 0;
153 goto out;
155 if (flags & O_WRONLY)
157 set_errno (EROFS);
158 res = 0;
159 goto out;
162 fileid = entry - procnet_tab;
163 if (!fill_filebuf ())
165 res = 0;
166 goto out;
169 if (flags & O_APPEND)
170 position = filesize;
171 else
172 position = 0;
174 success:
175 res = 1;
176 set_flags ((flags & ~O_TEXT) | O_BINARY);
177 set_open_status ();
178 out:
179 syscall_printf ("%d = fhandler_proc::open(%y, 0%o)", res, flags, mode);
180 return res;
183 bool
184 fhandler_procnet::fill_filebuf ()
186 if (procnet_tab[fileid].format_func)
188 filesize = procnet_tab[fileid].format_func (NULL, filebuf);
189 return true;
191 return false;
194 /* Return the same scope values as Linux. */
195 static unsigned int
196 get_scope (struct in6_addr *addr)
198 if (IN6_IS_ADDR_LOOPBACK (addr))
199 return 0x10;
200 if (IN6_IS_ADDR_LINKLOCAL (addr))
201 return 0x20;
202 if (IN6_IS_ADDR_SITELOCAL (addr))
203 return 0x40;
204 if (IN6_IS_ADDR_V4COMPAT (addr))
205 return 0x80;
206 return 0x0;
209 /* Convert DAD state into Linux compatible values. */
210 static unsigned int dad_to_flags[] =
212 0x02, /* Invalid -> NODAD */
213 0x40, /* Tentative -> TENTATIVE */
214 0xc0, /* Duplicate -> PERMANENT | TENTATIVE */
215 0x20, /* Deprecated -> DEPRECATED */
216 0x80 /* Preferred -> PERMANENT */
219 static off_t
220 format_procnet_ifinet6 (void *, char *&filebuf)
222 PIP_ADAPTER_ADDRESSES pa0 = NULL, pap;
223 PIP_ADAPTER_UNICAST_ADDRESS pua;
224 ULONG alloclen;
225 off_t filesize = 0;
227 if (!get_adapters_addresses (&pa0, AF_INET6))
228 goto out;
229 alloclen = 0;
230 for (pap = pa0; pap; pap = pap->Next)
231 for (pua = pap->FirstUnicastAddress; pua; pua = pua->Next)
232 alloclen += 100;
233 if (!alloclen)
234 goto out;
235 filebuf = (char *) crealloc (filebuf, alloclen);
236 if (!filebuf)
237 goto out;
238 for (pap = pa0; pap; pap = pap->Next)
239 for (pua = pap->FirstUnicastAddress; pua; pua = pua->Next)
241 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)
242 pua->Address.lpSockaddr;
243 for (int i = 0; i < 8; ++i)
244 /* __small_sprintf generates upper-case hex. */
245 filesize += sprintf (filebuf + filesize, "%04x",
246 ntohs (sin6->sin6_addr.s6_addr16[i]));
247 filebuf[filesize++] = ' ';
248 filesize += sprintf (filebuf + filesize,
249 "%02lx %02x %02x %02x %s\n",
250 (long) pap->Ipv6IfIndex,
251 pua->OnLinkPrefixLength,
252 get_scope (&((struct sockaddr_in6 *)
253 pua->Address.lpSockaddr)->sin6_addr),
254 dad_to_flags [pua->DadState],
255 pap->AdapterName);
258 out:
259 if (pa0)
260 free (pa0);
261 return filesize;