Cygwin: fhandler_virtual::exists: always set fileid
[newlib-cygwin.git] / winsup / cygwin / fhandler / procnet.cc
blob631fe8cc1e436ffba05224140c8bb69d246c8e29
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)
52 fileid () = 0;
53 return virt_rootdir;
56 virt_tab_t *entry = virt_tab_search (path + 1, false, procnet_tab,
57 PROCNET_LINK_COUNT);
58 if (entry)
60 if (entry->type == virt_file && !get_adapters_addresses (NULL, AF_INET6))
61 return virt_none;
62 fileid () = entry - procnet_tab;
63 return entry->type;
65 fileid () = -1;
66 return virt_none;
69 fhandler_procnet::fhandler_procnet ():
70 fhandler_proc ()
74 int
75 fhandler_procnet::fstat (struct stat *buf)
77 fhandler_base::fstat (buf);
78 buf->st_mode &= ~_IFMT & NO_W;
79 int file_type = exists ();
80 switch (file_type)
82 case virt_none:
83 set_errno (ENOENT);
84 return -1;
85 case virt_directory:
86 case virt_rootdir:
87 buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
88 buf->st_nlink = 2;
89 return 0;
90 case virt_file:
91 default:
92 buf->st_mode |= S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
93 return 0;
97 int
98 fhandler_procnet::readdir (DIR *dir, dirent *de)
100 int res = ENMFILE;
101 if (dir->__d_position >= PROCNET_LINK_COUNT)
102 goto out;
103 if (procnet_tab[dir->__d_position].type == virt_file
104 && !get_adapters_addresses (NULL, AF_INET6))
105 goto out;
106 strcpy (de->d_name, procnet_tab[dir->__d_position].name);
107 de->d_type = virt_ftype_to_dtype (procnet_tab[dir->__d_position].type);
108 dir->__d_position++;
109 dir->__flags |= dirent_saw_dot | dirent_saw_dot_dot;
110 res = 0;
111 out:
112 syscall_printf ("%d = readdir(%p, %p) (%s)", res, dir, de, de->d_name);
113 return res;
117 fhandler_procnet::open (int flags, mode_t mode)
119 int res = fhandler_virtual::open (flags, mode);
120 if (!res)
121 goto out;
123 nohandle (true);
125 const char *path;
126 path = get_name () + proc_len + 1;
127 while (*path != 0 && !isdirsep (*path))
128 path++;
130 if (*path == 0)
132 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
134 set_errno (EEXIST);
135 res = 0;
136 goto out;
138 else if (flags & O_WRONLY)
140 set_errno (EISDIR);
141 res = 0;
142 goto out;
144 else
146 diropen = true;
147 goto success;
151 virt_tab_t *entry;
152 entry = virt_tab_search (path + 1, true, procnet_tab, PROCNET_LINK_COUNT);
153 if (!entry)
155 set_errno ((flags & O_CREAT) ? EROFS : ENOENT);
156 res = 0;
157 goto out;
159 if (flags & O_WRONLY)
161 set_errno (EROFS);
162 res = 0;
163 goto out;
166 fileid () = entry - procnet_tab;
167 if (!fill_filebuf ())
169 res = 0;
170 goto out;
173 if (flags & O_APPEND)
174 position = filesize;
175 else
176 position = 0;
178 success:
179 res = 1;
180 set_flags ((flags & ~O_TEXT) | O_BINARY);
181 set_open_status ();
182 out:
183 syscall_printf ("%d = fhandler_proc::open(%y, 0%o)", res, flags, mode);
184 return res;
187 bool
188 fhandler_procnet::fill_filebuf ()
190 if (procnet_tab[fileid ()].format_func)
192 filesize = procnet_tab[fileid ()].format_func (NULL, filebuf);
193 return true;
195 return false;
198 /* Return the same scope values as Linux. */
199 static unsigned int
200 get_scope (struct in6_addr *addr)
202 if (IN6_IS_ADDR_LOOPBACK (addr))
203 return 0x10;
204 if (IN6_IS_ADDR_LINKLOCAL (addr))
205 return 0x20;
206 if (IN6_IS_ADDR_SITELOCAL (addr))
207 return 0x40;
208 if (IN6_IS_ADDR_V4COMPAT (addr))
209 return 0x80;
210 return 0x0;
213 /* Convert DAD state into Linux compatible values. */
214 static unsigned int dad_to_flags[] =
216 0x02, /* Invalid -> NODAD */
217 0x40, /* Tentative -> TENTATIVE */
218 0xc0, /* Duplicate -> PERMANENT | TENTATIVE */
219 0x20, /* Deprecated -> DEPRECATED */
220 0x80 /* Preferred -> PERMANENT */
223 static off_t
224 format_procnet_ifinet6 (void *, char *&filebuf)
226 PIP_ADAPTER_ADDRESSES pa0 = NULL, pap;
227 PIP_ADAPTER_UNICAST_ADDRESS pua;
228 ULONG alloclen;
229 off_t filesize = 0;
231 if (!get_adapters_addresses (&pa0, AF_INET6))
232 goto out;
233 alloclen = 0;
234 for (pap = pa0; pap; pap = pap->Next)
235 for (pua = pap->FirstUnicastAddress; pua; pua = pua->Next)
236 alloclen += 100;
237 if (!alloclen)
238 goto out;
239 filebuf = (char *) crealloc (filebuf, alloclen);
240 if (!filebuf)
241 goto out;
242 for (pap = pa0; pap; pap = pap->Next)
243 for (pua = pap->FirstUnicastAddress; pua; pua = pua->Next)
245 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)
246 pua->Address.lpSockaddr;
247 for (int i = 0; i < 8; ++i)
248 /* __small_sprintf generates upper-case hex. */
249 filesize += sprintf (filebuf + filesize, "%04x",
250 ntohs (sin6->sin6_addr.s6_addr16[i]));
251 filebuf[filesize++] = ' ';
252 filesize += sprintf (filebuf + filesize,
253 "%02lx %02x %02x %02x %s\n",
254 (long) pap->Ipv6IfIndex,
255 pua->OnLinkPrefixLength,
256 get_scope (&((struct sockaddr_in6 *)
257 pua->Address.lpSockaddr)->sin6_addr),
258 dad_to_flags [pua->DadState],
259 pap->AdapterName);
262 out:
263 if (pa0)
264 free (pa0);
265 return filesize;