]>
Commit | Line | Data |
---|---|---|
c477dccf CF |
1 | /* fhandler_proc.cc: fhandler for /proc virtual filesystem |
2 | ||
c477dccf CF |
3 | This file is part of Cygwin. |
4 | ||
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. */ | |
8 | ||
9 | #include "winsup.h" | |
ade47a34 | 10 | #include "miscfuncs.h" |
c477dccf CF |
11 | #include <unistd.h> |
12 | #include <stdlib.h> | |
5f6d028d | 13 | #include <stdio.h> |
c477dccf CF |
14 | #include "cygerrno.h" |
15 | #include "security.h" | |
c477dccf | 16 | #include "path.h" |
f207699a | 17 | #include "shared_info.h" |
7ac61736 | 18 | #include "fhandler.h" |
38f50ae4 | 19 | #include "fhandler_virtual.h" |
c477dccf | 20 | #include "pinfo.h" |
8761c1dc CF |
21 | #include "dtable.h" |
22 | #include "cygheap.h" | |
38f50ae4 | 23 | #include "tls_pbuf.h" |
c477dccf | 24 | #include <sys/utsname.h> |
c8bef400 | 25 | #include <sys/param.h> |
205b8208 | 26 | #include <sys/sysinfo.h> |
9ba913a5 | 27 | #include "ntdll.h" |
c367dfd0 | 28 | #include <winioctl.h> |
e9c8cb31 | 29 | #include <wchar.h> |
483e9d00 | 30 | #include <wctype.h> |
c448f78f | 31 | #include "cpuid.h" |
a52993d4 | 32 | #include "mount.h" |
c84697c2 | 33 | #include <math.h> |
c477dccf CF |
34 | |
35 | #define _COMPILING_NEWLIB | |
36 | #include <dirent.h> | |
37 | ||
61522196 CV |
38 | static off_t format_proc_loadavg (void *, char *&); |
39 | static off_t format_proc_meminfo (void *, char *&); | |
40 | static off_t format_proc_stat (void *, char *&); | |
41 | static off_t format_proc_version (void *, char *&); | |
42 | static off_t format_proc_uptime (void *, char *&); | |
43 | static off_t format_proc_cpuinfo (void *, char *&); | |
44 | static off_t format_proc_partitions (void *, char *&); | |
45 | static off_t format_proc_self (void *, char *&); | |
f207699a | 46 | static off_t format_proc_cygdrive (void *, char *&); |
61522196 CV |
47 | static off_t format_proc_mounts (void *, char *&); |
48 | static off_t format_proc_filesystems (void *, char *&); | |
49 | static off_t format_proc_swaps (void *, char *&); | |
50 | static off_t format_proc_devices (void *, char *&); | |
51 | static off_t format_proc_misc (void *, char *&); | |
c477dccf CF |
52 | |
53 | /* names of objects in /proc */ | |
38f50ae4 | 54 | static const virt_tab_t proc_tab[] = { |
43f65cdd CV |
55 | { _VN ("."), FH_PROC, virt_directory, NULL }, |
56 | { _VN (".."), FH_PROC, virt_directory, NULL }, | |
57 | { _VN ("cpuinfo"), FH_PROC, virt_file, format_proc_cpuinfo }, | |
f207699a | 58 | { _VN ("cygdrive"), FH_PROC, virt_symlink, format_proc_cygdrive }, |
07797cc0 | 59 | { _VN ("devices"), FH_PROC, virt_file, format_proc_devices }, |
43f65cdd CV |
60 | { _VN ("filesystems"), FH_PROC, virt_file, format_proc_filesystems }, |
61 | { _VN ("loadavg"), FH_PROC, virt_file, format_proc_loadavg }, | |
62 | { _VN ("meminfo"), FH_PROC, virt_file, format_proc_meminfo }, | |
07797cc0 | 63 | { _VN ("misc"), FH_PROC, virt_file, format_proc_misc }, |
43f65cdd CV |
64 | { _VN ("mounts"), FH_PROC, virt_symlink, format_proc_mounts }, |
65 | { _VN ("net"), FH_PROCNET, virt_directory, NULL }, | |
66 | { _VN ("partitions"), FH_PROC, virt_file, format_proc_partitions }, | |
67 | { _VN ("registry"), FH_REGISTRY, virt_directory, NULL }, | |
68 | { _VN ("registry32"), FH_REGISTRY, virt_directory, NULL }, | |
69 | { _VN ("registry64"), FH_REGISTRY, virt_directory, NULL }, | |
70 | { _VN ("self"), FH_PROC, virt_symlink, format_proc_self }, | |
71 | { _VN ("stat"), FH_PROC, virt_file, format_proc_stat }, | |
5f6d028d | 72 | { _VN ("swaps"), FH_PROC, virt_file, format_proc_swaps }, |
43f65cdd | 73 | { _VN ("sys"), FH_PROCSYS, virt_directory, NULL }, |
d68288f6 | 74 | { _VN ("sysvipc"), FH_PROCSYSVIPC, virt_directory, NULL }, |
43f65cdd CV |
75 | { _VN ("uptime"), FH_PROC, virt_file, format_proc_uptime }, |
76 | { _VN ("version"), FH_PROC, virt_file, format_proc_version }, | |
c3a9063f | 77 | { NULL, 0, FH_NADA, virt_none, NULL } |
c477dccf CF |
78 | }; |
79 | ||
214c3a11 CV |
80 | #define PROC_DIR_COUNT 4 |
81 | ||
38f50ae4 | 82 | static const int PROC_LINK_COUNT = (sizeof (proc_tab) / sizeof (virt_tab_t)) - 1; |
c477dccf CF |
83 | |
84 | /* name of the /proc filesystem */ | |
85 | const char proc[] = "/proc"; | |
43f65cdd | 86 | const size_t proc_len = sizeof (proc) - 1; |
c477dccf | 87 | |
43f65cdd CV |
88 | /* bsearch compare function. */ |
89 | static int | |
90 | proc_tab_cmp (const void *key, const void *memb) | |
91 | { | |
92 | int ret = strncmp (((virt_tab_t *) key)->name, ((virt_tab_t *) memb)->name, | |
93 | ((virt_tab_t *) memb)->name_len); | |
94 | if (!ret && ((virt_tab_t *) key)->name[((virt_tab_t *) memb)->name_len] != '\0' && ((virt_tab_t *) key)->name[((virt_tab_t *) memb)->name_len] != '/') | |
95 | return 1; | |
96 | return ret; | |
97 | } | |
98 | ||
483e9d00 | 99 | /* Helper function to perform a binary search of the incoming pathname |
43f65cdd CV |
100 | against the alpha-sorted virtual file table. */ |
101 | virt_tab_t * | |
102 | virt_tab_search (const char *path, bool prefix, const virt_tab_t *table, | |
103 | size_t nelem) | |
104 | { | |
c3a9063f | 105 | virt_tab_t key = { path, 0, FH_NADA, virt_none, NULL }; |
43f65cdd CV |
106 | virt_tab_t *entry = (virt_tab_t *) bsearch (&key, table, nelem, |
107 | sizeof (virt_tab_t), | |
108 | proc_tab_cmp); | |
109 | if (entry && (path[entry->name_len] == '\0' | |
110 | || (prefix && path[entry->name_len] == '/'))) | |
111 | return entry; | |
112 | return NULL; | |
113 | } | |
114 | ||
115 | /* Auxillary function that returns the fhandler associated with the given | |
116 | path. */ | |
44d2fc0a | 117 | fh_devices |
c477dccf CF |
118 | fhandler_proc::get_proc_fhandler (const char *path) |
119 | { | |
120 | debug_printf ("get_proc_fhandler(%s)", path); | |
121 | path += proc_len; | |
122 | /* Since this method is called from path_conv::check we can't rely on | |
c367dfd0 CF |
123 | it being normalised and therefore the path may have runs of slashes |
124 | in it. */ | |
85ba109d | 125 | while (isdirsep (*path)) |
c477dccf CF |
126 | path++; |
127 | ||
128 | /* Check if this is the root of the virtual filesystem (i.e. /proc). */ | |
129 | if (*path == 0) | |
130 | return FH_PROC; | |
131 | ||
43f65cdd CV |
132 | virt_tab_t *entry = virt_tab_search (path, true, proc_tab, |
133 | PROC_LINK_COUNT); | |
134 | if (entry) | |
135 | return entry->fhandler; | |
c477dccf | 136 | |
6e2c5823 CV |
137 | int pid = atoi (path); |
138 | pinfo p (pid); | |
139 | /* If p->pid != pid, then pid is actually the Windows PID for an execed | |
140 | Cygwin process, and the pinfo entry is the additional entry created | |
141 | at exec time. We don't want to enable the user to access a process | |
142 | entry by using the Win32 PID, though. */ | |
143 | if (p && p->pid == pid) | |
6b7cd251 | 144 | return FH_PROCESS; |
8761c1dc | 145 | |
6b7cd251 CF |
146 | bool has_subdir = false; |
147 | while (*path) | |
85ba109d | 148 | if (isdirsep (*path++)) |
6b7cd251 CF |
149 | { |
150 | has_subdir = true; | |
151 | break; | |
152 | } | |
8761c1dc | 153 | |
6b7cd251 CF |
154 | if (has_subdir) |
155 | /* The user is trying to access a non-existent subdirectory of /proc. */ | |
c3a9063f | 156 | return FH_NADA; |
6b7cd251 | 157 | else |
fcdca881 CV |
158 | /* Return FH_PROC so that we can return EROFS if the user is trying to |
159 | create a file. */ | |
6b7cd251 | 160 | return FH_PROC; |
c477dccf CF |
161 | } |
162 | ||
163 | /* Returns 0 if path doesn't exist, >0 if path is a directory, | |
e8309efd | 164 | -1 if path is a file, -2 if it's a symlink. */ |
43f65cdd | 165 | virtual_ftype_t |
fc240f58 | 166 | fhandler_proc::exists () |
c477dccf | 167 | { |
fc240f58 | 168 | const char *path = get_name (); |
c477dccf CF |
169 | debug_printf ("exists (%s)", path); |
170 | path += proc_len; | |
171 | if (*path == 0) | |
38f50ae4 | 172 | return virt_rootdir; |
43f65cdd CV |
173 | virt_tab_t *entry = virt_tab_search (path + 1, false, proc_tab, |
174 | PROC_LINK_COUNT); | |
175 | if (entry) | |
176 | { | |
177 | fileid = entry - proc_tab; | |
178 | return entry->type; | |
179 | } | |
38f50ae4 | 180 | return virt_none; |
c477dccf CF |
181 | } |
182 | ||
183 | fhandler_proc::fhandler_proc (): | |
7ac61736 | 184 | fhandler_virtual () |
c477dccf CF |
185 | { |
186 | } | |
187 | ||
6e75c72b | 188 | int __reg2 |
61522196 | 189 | fhandler_proc::fstat (struct stat *buf) |
c477dccf | 190 | { |
c477dccf | 191 | const char *path = get_name (); |
e065a187 CF |
192 | debug_printf ("fstat (%s)", path); |
193 | ||
c477dccf | 194 | path += proc_len; |
0c55f6ed | 195 | fhandler_base::fstat (buf); |
c477dccf CF |
196 | |
197 | buf->st_mode &= ~_IFMT & NO_W; | |
198 | ||
199 | if (!*path) | |
200 | { | |
214c3a11 CV |
201 | winpids pids ((DWORD) 0); |
202 | buf->st_ino = 2; | |
c477dccf | 203 | buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; |
214c3a11 | 204 | buf->st_nlink = PROC_DIR_COUNT + 2 + pids.npids; |
c477dccf CF |
205 | return 0; |
206 | } | |
207 | else | |
208 | { | |
43f65cdd CV |
209 | virt_tab_t *entry = virt_tab_search (path + 1, false, proc_tab, |
210 | PROC_LINK_COUNT); | |
211 | if (entry) | |
212 | { | |
213 | if (entry->type == virt_directory) | |
214 | buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; | |
215 | else if (entry->type == virt_symlink) | |
216 | buf->st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; | |
217 | else | |
218 | { | |
219 | buf->st_mode &= NO_X; | |
220 | buf->st_mode |= S_IFREG; | |
221 | } | |
222 | return 0; | |
223 | } | |
c477dccf CF |
224 | } |
225 | set_errno (ENOENT); | |
226 | return -1; | |
227 | } | |
228 | ||
1f08558f CV |
229 | DIR * |
230 | fhandler_proc::opendir (int fd) | |
231 | { | |
232 | DIR *dir = fhandler_virtual::opendir (fd); | |
233 | if (dir && !(dir->__handle = (void *) new winpids ((DWORD) 0))) | |
234 | { | |
235 | free (dir); | |
236 | dir = NULL; | |
237 | set_errno (ENOMEM); | |
238 | } | |
239 | return dir; | |
240 | } | |
241 | ||
242 | int | |
243 | fhandler_proc::closedir (DIR *dir) | |
244 | { | |
ad391746 | 245 | delete (winpids *) dir->__handle; |
1f08558f CV |
246 | return fhandler_virtual::closedir (dir); |
247 | } | |
248 | ||
d9a22764 CF |
249 | int |
250 | fhandler_proc::readdir (DIR *dir, dirent *de) | |
c477dccf | 251 | { |
d9a22764 CF |
252 | int res; |
253 | if (dir->__d_position < PROC_LINK_COUNT) | |
254 | { | |
54338f16 CV |
255 | strcpy (de->d_name, proc_tab[dir->__d_position].name); |
256 | de->d_type = virt_ftype_to_dtype (proc_tab[dir->__d_position].type); | |
257 | dir->__d_position++; | |
9e5f45ed | 258 | dir->__flags |= dirent_saw_dot | dirent_saw_dot_dot; |
d9a22764 CF |
259 | res = 0; |
260 | } | |
261 | else | |
c477dccf | 262 | { |
1f08558f | 263 | winpids &pids = *(winpids *) dir->__handle; |
c477dccf | 264 | int found = 0; |
d9a22764 | 265 | res = ENMFILE; |
c477dccf | 266 | for (unsigned i = 0; i < pids.npids; i++) |
6b7cd251 CF |
267 | if (found++ == dir->__d_position - PROC_LINK_COUNT) |
268 | { | |
d9a22764 | 269 | __small_sprintf (de->d_name, "%d", pids[i]->pid); |
54338f16 | 270 | de->d_type = DT_DIR; |
6b7cd251 | 271 | dir->__d_position++; |
d9a22764 CF |
272 | res = 0; |
273 | break; | |
6b7cd251 | 274 | } |
c477dccf CF |
275 | } |
276 | ||
b9aa8149 | 277 | syscall_printf ("%d = readdir(%p, %p) (%s)", res, dir, de, de->d_name); |
d9a22764 | 278 | return res; |
c477dccf CF |
279 | } |
280 | ||
281 | int | |
7ac61736 | 282 | fhandler_proc::open (int flags, mode_t mode) |
c477dccf CF |
283 | { |
284 | int proc_file_no = -1; | |
285 | ||
7ac61736 | 286 | int res = fhandler_virtual::open (flags, mode); |
c477dccf CF |
287 | if (!res) |
288 | goto out; | |
289 | ||
56551a9b | 290 | nohandle (true); |
74fcdaec | 291 | |
c477dccf CF |
292 | const char *path; |
293 | ||
335c87f9 | 294 | path = get_name () + proc_len; |
c477dccf CF |
295 | |
296 | if (!*path) | |
297 | { | |
8761c1dc | 298 | if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) |
2402700d CF |
299 | { |
300 | set_errno (EEXIST); | |
301 | res = 0; | |
302 | goto out; | |
303 | } | |
8761c1dc | 304 | else if (flags & O_WRONLY) |
2402700d CF |
305 | { |
306 | set_errno (EISDIR); | |
307 | res = 0; | |
308 | goto out; | |
309 | } | |
c477dccf | 310 | else |
2402700d CF |
311 | { |
312 | flags |= O_DIROPEN; | |
313 | goto success; | |
314 | } | |
c477dccf CF |
315 | } |
316 | ||
317 | proc_file_no = -1; | |
40255b64 CV |
318 | for (int i = 0; proc_tab[i].name; i++) |
319 | if (path_prefix_p (proc_tab[i].name, path + 1, strlen (proc_tab[i].name), | |
e4b57503 | 320 | false)) |
c477dccf | 321 | { |
2402700d | 322 | proc_file_no = i; |
40255b64 | 323 | if (proc_tab[i].fhandler != FH_PROC) |
2402700d CF |
324 | { |
325 | if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) | |
326 | { | |
327 | set_errno (EEXIST); | |
328 | res = 0; | |
329 | goto out; | |
330 | } | |
331 | else if (flags & O_WRONLY) | |
332 | { | |
333 | set_errno (EISDIR); | |
334 | res = 0; | |
335 | goto out; | |
336 | } | |
337 | else | |
338 | { | |
339 | flags |= O_DIROPEN; | |
340 | goto success; | |
341 | } | |
342 | } | |
c477dccf CF |
343 | } |
344 | ||
345 | if (proc_file_no == -1) | |
346 | { | |
8761c1dc | 347 | if (flags & O_CREAT) |
2402700d CF |
348 | { |
349 | set_errno (EROFS); | |
350 | res = 0; | |
351 | goto out; | |
352 | } | |
c477dccf | 353 | else |
2402700d CF |
354 | { |
355 | set_errno (ENOENT); | |
356 | res = 0; | |
357 | goto out; | |
358 | } | |
c477dccf | 359 | } |
8761c1dc | 360 | if (flags & O_WRONLY) |
c477dccf CF |
361 | { |
362 | set_errno (EROFS); | |
363 | res = 0; | |
364 | goto out; | |
365 | } | |
9ba913a5 CF |
366 | |
367 | fileid = proc_file_no; | |
74fcdaec CF |
368 | if (!fill_filebuf ()) |
369 | { | |
370 | res = 0; | |
371 | goto out; | |
40255b64 | 372 | } |
9ba913a5 CF |
373 | |
374 | if (flags & O_APPEND) | |
375 | position = filesize; | |
376 | else | |
377 | position = 0; | |
378 | ||
379 | success: | |
380 | res = 1; | |
1bc9effd | 381 | set_flags ((flags & ~O_TEXT) | O_BINARY); |
9ba913a5 | 382 | set_open_status (); |
9ba913a5 | 383 | out: |
61522196 | 384 | syscall_printf ("%d = fhandler_proc::open(%y, 0%o)", res, flags, mode); |
9ba913a5 CF |
385 | return res; |
386 | } | |
387 | ||
74fcdaec | 388 | bool |
9ba913a5 CF |
389 | fhandler_proc::fill_filebuf () |
390 | { | |
40255b64 | 391 | if (fileid < PROC_LINK_COUNT && proc_tab[fileid].format_func) |
c477dccf | 392 | { |
38f50ae4 | 393 | filesize = proc_tab[fileid].format_func (NULL, filebuf); |
483e9d00 CV |
394 | if (filesize > 0) |
395 | return true; | |
c477dccf | 396 | } |
40255b64 CV |
397 | return false; |
398 | } | |
399 | ||
61522196 | 400 | static off_t |
38f50ae4 | 401 | format_proc_version (void *, char *&destbuf) |
40255b64 | 402 | { |
a2ef34bf YS |
403 | tmp_pathbuf tp; |
404 | char *buf = tp.c_get (); | |
405 | char *bufptr = buf; | |
40255b64 CV |
406 | struct utsname uts_name; |
407 | ||
408 | uname (&uts_name); | |
a2ef34bf YS |
409 | bufptr += __small_sprintf (bufptr, "%s version %s (%s@%s) (%s) %s\n", |
410 | uts_name.sysname, uts_name.release, USERNAME, HOSTNAME, | |
411 | GCC_VERSION, uts_name.version); | |
412 | ||
413 | destbuf = (char *) crealloc_abort (destbuf, bufptr - buf); | |
414 | memcpy (destbuf, buf, bufptr - buf); | |
415 | return bufptr - buf; | |
40255b64 CV |
416 | } |
417 | ||
61522196 | 418 | static off_t |
38f50ae4 | 419 | format_proc_loadavg (void *, char *&destbuf) |
40255b64 | 420 | { |
9ca65531 | 421 | extern int get_process_state (DWORD dwProcessId); |
d0a359f6 | 422 | unsigned int running = 0; |
9ca65531 YS |
423 | winpids pids ((DWORD) 0); |
424 | ||
425 | for (unsigned i = 0; i < pids.npids; i++) | |
426 | switch (get_process_state (i)) { | |
427 | case 'O': | |
428 | case 'R': | |
b86f999a CF |
429 | running++; |
430 | break; | |
9ca65531 YS |
431 | } |
432 | ||
d0a359f6 JT |
433 | double loadavg[3] = { 0.0, 0.0, 0.0 }; |
434 | getloadavg (loadavg, 3); | |
435 | ||
c84697c2 JT |
436 | #define HUNDRETHS(l) (int)((l - floor(l))*100) |
437 | ||
7810aa7c | 438 | destbuf = (char *) crealloc_abort (destbuf, 48); |
c84697c2 JT |
439 | return __small_sprintf (destbuf, "%u.%02u %u.%02u %u.%02u %u/%u\n", |
440 | (int)loadavg[0], HUNDRETHS(loadavg[0]), | |
441 | (int)loadavg[1], HUNDRETHS(loadavg[1]), | |
442 | (int)loadavg[2], HUNDRETHS(loadavg[2]), | |
443 | running, (unsigned int)pids.npids); | |
9ba913a5 | 444 | } |
c477dccf | 445 | |
61522196 | 446 | static off_t |
38f50ae4 | 447 | format_proc_meminfo (void *, char *&destbuf) |
9ba913a5 | 448 | { |
205b8208 YS |
449 | unsigned long long mem_total, mem_free, swap_total, swap_free; |
450 | struct sysinfo info; | |
451 | ||
452 | sysinfo (&info); | |
453 | mem_total = (unsigned long long) info.totalram * info.mem_unit; | |
454 | mem_free = (unsigned long long) info.freeram * info.mem_unit; | |
455 | swap_total = (unsigned long long) info.totalswap * info.mem_unit; | |
456 | swap_free = (unsigned long long) info.freeswap * info.mem_unit; | |
38f50ae4 | 457 | |
38f50ae4 | 458 | destbuf = (char *) crealloc_abort (destbuf, 512); |
205b8208 YS |
459 | return sprintf (destbuf, "MemTotal: %10llu kB\n" |
460 | "MemFree: %10llu kB\n" | |
461 | "HighTotal: 0 kB\n" | |
462 | "HighFree: 0 kB\n" | |
463 | "LowTotal: %10llu kB\n" | |
464 | "LowFree: %10llu kB\n" | |
465 | "SwapTotal: %10llu kB\n" | |
466 | "SwapFree: %10llu kB\n", | |
467 | mem_total >> 10, mem_free >> 10, | |
468 | mem_total >> 10, mem_free >> 10, | |
469 | swap_total >> 10, swap_free >> 10); | |
9ba913a5 CF |
470 | } |
471 | ||
61522196 | 472 | static off_t |
38f50ae4 | 473 | format_proc_uptime (void *, char *&destbuf) |
9ba913a5 CF |
474 | { |
475 | unsigned long long uptime = 0ULL, idle_time = 0ULL; | |
177dc6c7 | 476 | NTSTATUS status; |
61522196 | 477 | SYSTEM_TIMEOFDAY_INFORMATION stodi; |
962082b9 CV |
478 | /* Sizeof SYSTEM_PERFORMANCE_INFORMATION on 64 bit systems. It |
479 | appears to contain some trailing additional information from | |
480 | what I can tell after examining the content. | |
481 | FIXME: It would be nice if this could be verified somehow. */ | |
482 | const size_t sizeof_spi = sizeof (SYSTEM_PERFORMANCE_INFORMATION) + 16; | |
483 | PSYSTEM_PERFORMANCE_INFORMATION spi = (PSYSTEM_PERFORMANCE_INFORMATION) | |
484 | alloca (sizeof_spi); | |
570858c3 | 485 | |
177dc6c7 CV |
486 | status = NtQuerySystemInformation (SystemTimeOfDayInformation, &stodi, |
487 | sizeof stodi, NULL); | |
488 | if (NT_SUCCESS (status)) | |
fcdca881 | 489 | uptime = (stodi.CurrentTime.QuadPart - stodi.BootTime.QuadPart) / 100000ULL; |
d8e551a1 CV |
490 | else |
491 | debug_printf ("NtQuerySystemInformation(SystemTimeOfDayInformation), " | |
61522196 | 492 | "status %y", status); |
d8e551a1 | 493 | |
962082b9 CV |
494 | if (NT_SUCCESS (NtQuerySystemInformation (SystemPerformanceInformation, |
495 | spi, sizeof_spi, NULL))) | |
c29e6933 | 496 | idle_time = (spi->IdleTime.QuadPart / wincap.cpu_count ()) |
962082b9 | 497 | / 100000ULL; |
c477dccf | 498 | |
38f50ae4 | 499 | destbuf = (char *) crealloc_abort (destbuf, 80); |
9ba913a5 | 500 | return __small_sprintf (destbuf, "%U.%02u %U.%02u\n", |
2402700d CF |
501 | uptime / 100, long (uptime % 100), |
502 | idle_time / 100, long (idle_time % 100)); | |
9ba913a5 CF |
503 | } |
504 | ||
61522196 | 505 | static off_t |
38f50ae4 | 506 | format_proc_stat (void *, char *&destbuf) |
9ba913a5 | 507 | { |
9ba913a5 | 508 | unsigned long pages_in = 0UL, pages_out = 0UL, interrupt_count = 0UL, |
2402700d | 509 | context_switches = 0UL, swap_in = 0UL, swap_out = 0UL; |
9ba913a5 | 510 | time_t boot_time = 0; |
177dc6c7 | 511 | NTSTATUS status; |
962082b9 CV |
512 | /* Sizeof SYSTEM_PERFORMANCE_INFORMATION on 64 bit systems. It |
513 | appears to contain some trailing additional information from | |
514 | what I can tell after examining the content. | |
515 | FIXME: It would be nice if this could be verified somehow. */ | |
516 | const size_t sizeof_spi = sizeof (SYSTEM_PERFORMANCE_INFORMATION) + 16; | |
517 | PSYSTEM_PERFORMANCE_INFORMATION spi = (PSYSTEM_PERFORMANCE_INFORMATION) | |
518 | alloca (sizeof_spi); | |
61522196 | 519 | SYSTEM_TIMEOFDAY_INFORMATION stodi; |
38f50ae4 CV |
520 | tmp_pathbuf tp; |
521 | ||
522 | char *buf = tp.c_get (); | |
523 | char *eobuf = buf; | |
524 | ||
61522196 CV |
525 | SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION spt[wincap.cpu_count ()]; |
526 | status = NtQuerySystemInformation (SystemProcessorPerformanceInformation, | |
527 | (PVOID) spt, | |
177dc6c7 CV |
528 | sizeof spt[0] * wincap.cpu_count (), NULL); |
529 | if (!NT_SUCCESS (status)) | |
61522196 CV |
530 | debug_printf ("NtQuerySystemInformation(SystemProcessorPerformanceInformation), " |
531 | "status %y", status); | |
d8e551a1 | 532 | else |
9ba913a5 | 533 | { |
570858c3 | 534 | unsigned long long user_time = 0ULL, kernel_time = 0ULL, idle_time = 0ULL; |
c29e6933 | 535 | for (unsigned long i = 0; i < wincap.cpu_count (); i++) |
cf38615c | 536 | { |
570858c3 CV |
537 | kernel_time += (spt[i].KernelTime.QuadPart - spt[i].IdleTime.QuadPart) |
538 | * HZ / 10000000ULL; | |
539 | user_time += spt[i].UserTime.QuadPart * HZ / 10000000ULL; | |
540 | idle_time += spt[i].IdleTime.QuadPart * HZ / 10000000ULL; | |
cf38615c CF |
541 | } |
542 | ||
570858c3 CV |
543 | eobuf += __small_sprintf (eobuf, "cpu %U %U %U %U\n", |
544 | user_time, 0ULL, kernel_time, idle_time); | |
545 | user_time = 0ULL, kernel_time = 0ULL, idle_time = 0ULL; | |
c29e6933 | 546 | for (unsigned long i = 0; i < wincap.cpu_count (); i++) |
cf38615c | 547 | { |
570858c3 CV |
548 | interrupt_count += spt[i].InterruptCount; |
549 | kernel_time = (spt[i].KernelTime.QuadPart - spt[i].IdleTime.QuadPart) * HZ / 10000000ULL; | |
550 | user_time = spt[i].UserTime.QuadPart * HZ / 10000000ULL; | |
551 | idle_time = spt[i].IdleTime.QuadPart * HZ / 10000000ULL; | |
552 | eobuf += __small_sprintf (eobuf, "cpu%d %U %U %U %U\n", i, | |
cf38615c | 553 | user_time, 0ULL, kernel_time, idle_time); |
2402700d | 554 | } |
570858c3 | 555 | |
177dc6c7 CV |
556 | status = NtQuerySystemInformation (SystemPerformanceInformation, |
557 | (PVOID) spi, sizeof_spi, NULL); | |
558 | if (!NT_SUCCESS (status)) | |
d8e551a1 CV |
559 | { |
560 | debug_printf ("NtQuerySystemInformation(SystemPerformanceInformation)" | |
61522196 | 561 | ", status %y", status); |
962082b9 | 562 | memset (spi, 0, sizeof_spi); |
d8e551a1 | 563 | } |
177dc6c7 CV |
564 | status = NtQuerySystemInformation (SystemTimeOfDayInformation, |
565 | (PVOID) &stodi, sizeof stodi, NULL); | |
566 | if (!NT_SUCCESS (status)) | |
d8e551a1 | 567 | debug_printf ("NtQuerySystemInformation(SystemTimeOfDayInformation), " |
61522196 | 568 | "status %y", status); |
9ba913a5 | 569 | } |
177dc6c7 | 570 | if (!NT_SUCCESS (status)) |
483e9d00 | 571 | { |
177dc6c7 | 572 | __seterrno_from_nt_status (status); |
483e9d00 CV |
573 | return 0; |
574 | } | |
d8e551a1 | 575 | |
962082b9 CV |
576 | pages_in = spi->PagesRead; |
577 | pages_out = spi->PagefilePagesWritten + spi->MappedFilePagesWritten; | |
177dc6c7 CV |
578 | /* Note: there is no distinction made in this structure between pages read |
579 | from the page file and pages read from mapped files, but there is such | |
580 | a distinction made when it comes to writing. Goodness knows why. The | |
581 | value of swap_in, then, will obviously be wrong but its our best guess. */ | |
962082b9 CV |
582 | swap_in = spi->PagesRead; |
583 | swap_out = spi->PagefilePagesWritten; | |
584 | context_switches = spi->ContextSwitches; | |
0ff057d5 | 585 | boot_time = to_time_t (&stodi.BootTime); |
570858c3 | 586 | |
cf38615c | 587 | eobuf += __small_sprintf (eobuf, "page %u %u\n" |
2402700d CF |
588 | "swap %u %u\n" |
589 | "intr %u\n" | |
590 | "ctxt %u\n" | |
591 | "btime %u\n", | |
cf38615c CF |
592 | pages_in, pages_out, |
593 | swap_in, swap_out, | |
594 | interrupt_count, | |
595 | context_switches, | |
596 | boot_time); | |
38f50ae4 CV |
597 | destbuf = (char *) crealloc_abort (destbuf, eobuf - buf); |
598 | memcpy (destbuf, buf, eobuf - buf); | |
599 | return eobuf - buf; | |
c477dccf | 600 | } |
c367dfd0 | 601 | |
e0d48deb | 602 | #define add_size(p,s) ((p) = ((__typeof__(p))((PBYTE)(p)+(s)))) |
f5ab5b84 | 603 | #define print(x) { bufptr = stpcpy (bufptr, (x)); } |
c367dfd0 | 604 | |
e0d48deb CV |
605 | static inline uint32_t |
606 | get_msb (uint32_t in) | |
607 | { | |
608 | return 32 - __builtin_clz (in); | |
609 | } | |
610 | ||
611 | static inline uint32_t | |
612 | mask_bits (uint32_t in) | |
613 | { | |
614 | uint32_t bits = get_msb (in) - 1; | |
615 | if (in & (in - 1)) | |
616 | ++bits; | |
617 | return bits; | |
618 | } | |
619 | ||
61522196 | 620 | static off_t |
38f50ae4 | 621 | format_proc_cpuinfo (void *, char *&destbuf) |
c367dfd0 | 622 | { |
e0d48deb CV |
623 | WCHAR cpu_key[128], *cpu_num_p; |
624 | DWORD orig_affinity_mask = 0; | |
625 | GROUP_AFFINITY orig_group_affinity; | |
c367dfd0 CF |
626 | int cpu_number; |
627 | const int BUFSIZE = 256; | |
523a66d9 CV |
628 | union |
629 | { | |
630 | BYTE b[BUFSIZE]; | |
631 | char s[BUFSIZE]; | |
f5ab5b84 | 632 | WCHAR w[BUFSIZE / sizeof (WCHAR)]; |
523a66d9 | 633 | DWORD d; |
5b4e301b | 634 | uint32_t m[13]; |
523a66d9 | 635 | } in_buf; |
38f50ae4 | 636 | tmp_pathbuf tp; |
c367dfd0 | 637 | |
38f50ae4 CV |
638 | char *buf = tp.c_get (); |
639 | char *bufptr = buf; | |
c367dfd0 | 640 | |
e0d48deb CV |
641 | DWORD lpi_size = NT_MAX_PATH; |
642 | //WORD num_cpu_groups = 1; /* Pre Windows 7, only one group... */ | |
643 | WORD num_cpu_per_group = 64; /* ...and a max of 64 CPUs. */ | |
644 | ||
645 | if (wincap.has_processor_groups ()) | |
646 | { | |
647 | PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX lpi = | |
648 | (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) tp.c_get (); | |
649 | lpi_size = NT_MAX_PATH; | |
9074b9b8 | 650 | if (!GetLogicalProcessorInformationEx (RelationGroup, lpi, &lpi_size)) |
e0d48deb CV |
651 | lpi = NULL; |
652 | else | |
653 | { | |
654 | PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX plpi = lpi; | |
655 | for (DWORD size = lpi_size; size > 0; | |
656 | size -= plpi->Size, add_size (plpi, plpi->Size)) | |
657 | if (plpi->Relationship == RelationGroup) | |
658 | { | |
659 | //num_cpu_groups = plpi->Group.MaximumGroupCount; | |
660 | num_cpu_per_group | |
661 | = plpi->Group.GroupInfo[0].MaximumProcessorCount; | |
662 | break; | |
663 | } | |
664 | } | |
665 | } | |
666 | ||
667 | cpu_num_p = wcpcpy (cpu_key, L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION" | |
668 | "\\System\\CentralProcessor\\"); | |
0cb6fc5d | 669 | for (cpu_number = 0; ; cpu_number++) |
c367dfd0 | 670 | { |
e0d48deb | 671 | __small_swprintf (cpu_num_p, L"%d", cpu_number); |
f5ab5b84 CV |
672 | if (!NT_SUCCESS (RtlCheckRegistryKey (RTL_REGISTRY_ABSOLUTE, cpu_key))) |
673 | break; | |
fcdca881 | 674 | if (cpu_number) |
8581e92c | 675 | print ("\n"); |
fcdca881 | 676 | |
e0d48deb CV |
677 | WORD cpu_group = cpu_number / num_cpu_per_group; |
678 | KAFFINITY cpu_mask = 1L << (cpu_number % num_cpu_per_group); | |
679 | ||
680 | if (wincap.has_processor_groups ()) | |
681 | { | |
682 | GROUP_AFFINITY affinity = { | |
683 | .Mask = cpu_mask, | |
684 | .Group = cpu_group, | |
685 | }; | |
686 | ||
687 | if (!SetThreadGroupAffinity (GetCurrentThread (), &affinity, | |
688 | &orig_group_affinity)) | |
689 | system_printf ("SetThreadGroupAffinity(%x,%d (%x/%d)) failed %E", cpu_mask, cpu_group, cpu_number, cpu_number); | |
690 | orig_affinity_mask = 1; /* Just mark success. */ | |
691 | } | |
692 | else | |
693 | { | |
694 | orig_affinity_mask = SetThreadAffinityMask (GetCurrentThread (), | |
695 | 1 << cpu_number); | |
696 | if (orig_affinity_mask == 0) | |
697 | debug_printf ("SetThreadAffinityMask failed %E"); | |
698 | } | |
f5ab5b84 CV |
699 | /* I'm not sure whether the thread changes processor immediately |
700 | and I'm not sure whether this function will cause the thread | |
701 | to be rescheduled */ | |
084ea510 | 702 | yield (); |
c367dfd0 | 703 | |
e0d48deb CV |
704 | DWORD cpu_mhz = 0; |
705 | RTL_QUERY_REGISTRY_TABLE tab[2] = { | |
706 | { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOSTRING, | |
707 | L"~Mhz", &cpu_mhz, REG_NONE, NULL, 0 }, | |
708 | { NULL, 0, NULL, NULL, 0, NULL, 0 } | |
709 | }; | |
710 | ||
711 | RtlQueryRegistryValues (RTL_REGISTRY_ABSOLUTE, cpu_key, tab, | |
712 | NULL, NULL); | |
713 | bufptr += __small_sprintf (bufptr, "processor\t: %d\n", cpu_number); | |
714 | uint32_t maxf, vendor_id[4], unused; | |
715 | ||
716 | cpuid (&maxf, &vendor_id[0], &vendor_id[2], &vendor_id[1], 0x00000000); | |
717 | maxf &= 0xffff; | |
718 | vendor_id[3] = 0; | |
719 | ||
720 | /* Vendor identification. */ | |
721 | bool is_amd = false, is_intel = false; | |
722 | if (!strcmp ((char*)vendor_id, "AuthenticAMD")) | |
723 | is_amd = true; | |
724 | else if (!strcmp ((char*)vendor_id, "GenuineIntel")) | |
725 | is_intel = true; | |
726 | ||
727 | bufptr += __small_sprintf (bufptr, "vendor_id\t: %s\n", | |
728 | (char *)vendor_id); | |
729 | ||
730 | uint32_t features1, features2, extra_info, cpuid_sig; | |
731 | cpuid (&cpuid_sig, &extra_info, &features2, &features1, 0x00000001); | |
732 | uint32_t family = (cpuid_sig & 0x00000f00) >> 8, | |
733 | model = (cpuid_sig & 0x000000f0) >> 4, | |
734 | stepping = cpuid_sig & 0x0000000f, | |
735 | apic_id = (extra_info & 0xff000000) >> 24; | |
736 | if (family == 15) | |
737 | family += (cpuid_sig >> 20) & 0xff; | |
738 | if (family >= 6) | |
739 | model += ((cpuid_sig >> 16) & 0x0f) << 4; | |
740 | ||
741 | uint32_t maxe = 0; | |
742 | cpuid (&maxe, &unused, &unused, &unused, 0x80000000); | |
743 | if (maxe >= 0x80000004) | |
744 | { | |
745 | cpuid (&in_buf.m[0], &in_buf.m[1], &in_buf.m[2], | |
746 | &in_buf.m[3], 0x80000002); | |
747 | cpuid (&in_buf.m[4], &in_buf.m[5], &in_buf.m[6], | |
748 | &in_buf.m[7], 0x80000003); | |
749 | cpuid (&in_buf.m[8], &in_buf.m[9], &in_buf.m[10], | |
750 | &in_buf.m[11], 0x80000004); | |
751 | in_buf.m[12] = 0; | |
752 | } | |
c367dfd0 CF |
753 | else |
754 | { | |
e0d48deb CV |
755 | /* Could implement a lookup table here if someone needs it. */ |
756 | strcpy (in_buf.s, "unknown"); | |
757 | } | |
758 | int cache_size = -1, | |
759 | clflush = 64, | |
760 | cache_alignment = 64; | |
761 | if (features1 & (1 << 19)) /* CLFSH */ | |
762 | clflush = ((extra_info >> 8) & 0xff) << 3; | |
763 | if (is_intel && family == 15) | |
764 | cache_alignment = clflush * 2; | |
765 | if (is_intel) | |
766 | { | |
38fd7ddb CV |
767 | extern long get_cpu_cache_intel (int sysc, uint32_t maxf); |
768 | long cs; | |
e0d48deb | 769 | |
38fd7ddb CV |
770 | /* As on Linux, don't check for L3 cache. */ |
771 | cs = get_cpu_cache_intel (_SC_LEVEL2_CACHE_SIZE, maxf); | |
772 | if (cs == -1) | |
c367dfd0 | 773 | { |
38fd7ddb CV |
774 | cs = get_cpu_cache_intel (_SC_LEVEL1_ICACHE_SIZE, maxf); |
775 | if (cs != -1) | |
776 | cache_size = cs; | |
777 | cs = get_cpu_cache_intel (_SC_LEVEL1_DCACHE_SIZE, maxf); | |
778 | if (cs != -1) | |
779 | cache_size += cs; | |
c367dfd0 | 780 | } |
38fd7ddb CV |
781 | else |
782 | cache_size = cs; | |
e0d48deb CV |
783 | if (cache_size != -1) |
784 | cache_size >>= 10; | |
c367dfd0 | 785 | } |
38fd7ddb | 786 | else if (is_amd) |
c367dfd0 | 787 | { |
38fd7ddb CV |
788 | extern long get_cpu_cache_amd (int sysc, uint32_t maxe); |
789 | long cs; | |
f5ab5b84 | 790 | |
38fd7ddb CV |
791 | cs = get_cpu_cache_amd (_SC_LEVEL3_CACHE_SIZE, maxe); |
792 | if (cs == -1) | |
793 | cs = get_cpu_cache_amd (_SC_LEVEL2_CACHE_SIZE, maxe); | |
794 | if (cs == -1) | |
795 | { | |
796 | cs = get_cpu_cache_amd (_SC_LEVEL1_ICACHE_SIZE, maxe); | |
797 | if (cs != -1) | |
798 | cache_size = cs; | |
799 | cs = get_cpu_cache_amd (_SC_LEVEL1_DCACHE_SIZE, maxe); | |
800 | if (cs != -1) | |
801 | cache_size += cs; | |
802 | } | |
803 | else | |
804 | cache_size = cs; | |
805 | if (cache_size != -1) | |
806 | cache_size >>= 10; | |
df04ae29 | 807 | } |
e0d48deb CV |
808 | bufptr += __small_sprintf (bufptr, "cpu family\t: %d\n" |
809 | "model\t\t: %d\n" | |
810 | "model name\t: %s\n" | |
811 | "stepping\t: %d\n" | |
812 | "cpu MHz\t\t: %d.000\n", | |
813 | family, | |
814 | model, | |
815 | in_buf.s + strspn (in_buf.s, " "), | |
816 | stepping, | |
817 | cpu_mhz); | |
818 | ||
819 | if (cache_size >= 0) | |
820 | bufptr += __small_sprintf (bufptr, "cache size\t: %d KB\n", | |
821 | cache_size); | |
822 | ||
823 | /* Recognize multi-core CPUs. */ | |
824 | if (features1 & (1 << 28)) /* HTT */ | |
c367dfd0 | 825 | { |
e0d48deb CV |
826 | uint32_t siblings = 0; |
827 | uint32_t cpu_cores = 0; | |
828 | uint32_t phys_id = 0; | |
829 | uint32_t core_id = 0; | |
830 | uint32_t initial_apic_id = apic_id; | |
831 | ||
832 | uint32_t logical_bits = 0; /* # of logical core bits in apicid. */ | |
833 | uint32_t ht_bits = 0; /* # of thread bits in apic_id. */ | |
f5ab5b84 | 834 | |
e0d48deb | 835 | if (is_intel) |
c367dfd0 | 836 | { |
e0d48deb CV |
837 | bool valid = false; |
838 | if (maxf >= 0x0000000b) /* topoext supported? */ | |
c367dfd0 | 839 | { |
e0d48deb CV |
840 | uint32_t bits, logical, level, unused; |
841 | ||
842 | /* Threads */ | |
843 | cpuid (&bits, &logical, &level, &unused, | |
844 | 0x0000000b, 0x00); | |
845 | /* Even if topoext is supposedly supported, it can return | |
846 | "invalid". */ | |
847 | if (bits != 0 && ((level >> 8) & 0xff) == 1) | |
848 | { | |
849 | valid = true; | |
850 | ht_bits = (bits & 0x1f); | |
851 | siblings = (logical & 0xffff); | |
852 | cpu_cores = siblings; | |
853 | for (uint32_t idx = 1; ; ++idx) | |
854 | { | |
855 | cpuid (&bits, &logical, &level, &initial_apic_id, | |
856 | 0x0000000b, idx); | |
857 | ||
858 | uint32_t level_type = ((level >> 8) & 0xff); | |
859 | if (level_type == 0) /* Invalid */ | |
860 | break; | |
861 | if (level_type == 2) /* Core */ | |
862 | { | |
863 | logical_bits = (bits & 0x1f); | |
864 | siblings = (logical & 0xffff); | |
865 | cpu_cores = siblings >> ht_bits; | |
866 | break; | |
867 | } | |
868 | } | |
869 | } | |
c367dfd0 | 870 | } |
e0d48deb | 871 | if (!valid && maxf >= 0x00000004) |
8581e92c | 872 | { |
e0d48deb | 873 | uint32_t apic_reserved; |
fcdca881 | 874 | |
e0d48deb CV |
875 | cpuid (&apic_reserved, &unused, &unused, &unused, |
876 | 0x00000004, 0x00); | |
877 | if (apic_reserved & 0x1f) | |
878 | { | |
879 | valid = true; | |
880 | cpu_cores = ((apic_reserved >> 26) & 0x3f) + 1; | |
881 | siblings = (extra_info >> 16) & 0xff; | |
882 | if (siblings <= 1) /* HT could be fused out */ | |
883 | { | |
884 | logical_bits = mask_bits (cpu_cores); | |
885 | ht_bits = 0; | |
886 | } | |
887 | else | |
888 | { | |
889 | logical_bits = mask_bits (siblings); | |
890 | ht_bits = mask_bits (siblings / cpu_cores); | |
891 | } | |
892 | } | |
fcdca881 | 893 | } |
e0d48deb | 894 | if (!valid) /* single core, multi thread */ |
8581e92c | 895 | { |
e0d48deb CV |
896 | cpu_cores = 1; |
897 | siblings = (extra_info >> 16) & 0xff; | |
898 | logical_bits = mask_bits (siblings); | |
899 | ht_bits = logical_bits; | |
fcdca881 | 900 | } |
e0d48deb CV |
901 | } |
902 | else if (is_amd) | |
903 | { | |
37b6936f CV |
904 | if (maxe >= 0x8000001e) |
905 | { | |
906 | uint32_t cus, core_info; | |
907 | ||
908 | cpuid (&unused, &unused, &core_info, &unused, 0x80000008); | |
909 | cpuid (&unused, &cus, &unused, &unused, 0x8000001e); | |
910 | siblings = (core_info & 0xff) + 1; | |
911 | logical_bits = (core_info >> 12) & 0xf; | |
912 | cus = ((cus >> 8) & 0x3) + 1; | |
913 | ht_bits = mask_bits (cus); | |
914 | cpu_cores = siblings >> ht_bits; | |
915 | } | |
916 | else if (maxe >= 0x80000008) | |
8581e92c | 917 | { |
5b4e301b | 918 | uint32_t core_info; |
fcdca881 | 919 | |
e0d48deb | 920 | cpuid (&unused, &unused, &core_info, &unused, 0x80000008); |
37b6936f CV |
921 | siblings = (core_info & 0xff) + 1; |
922 | cpu_cores = siblings; | |
923 | logical_bits = (core_info >> 12) & 0xf; | |
924 | if (!logical_bits) | |
925 | logical_bits = mask_bits (siblings); | |
926 | ht_bits = 0; | |
fcdca881 | 927 | } |
e0d48deb | 928 | else |
8581e92c | 929 | { |
37b6936f CV |
930 | siblings = (extra_info >> 16) & 0xff; |
931 | cpu_cores = siblings; | |
932 | logical_bits = mask_bits (siblings); | |
933 | ht_bits = 0; | |
fcdca881 | 934 | } |
e0d48deb CV |
935 | } |
936 | phys_id = initial_apic_id >> logical_bits; | |
937 | core_id = (initial_apic_id & ((1 << logical_bits) - 1)) >> ht_bits; | |
938 | ||
939 | bufptr += __small_sprintf (bufptr, "physical id\t: %d\n", phys_id); | |
940 | if (siblings > 0) | |
941 | bufptr += __small_sprintf (bufptr, "siblings\t: %u\n", siblings); | |
942 | bufptr += __small_sprintf (bufptr, "core id\t\t: %d\n" | |
943 | "cpu cores\t: %d\n", | |
944 | core_id, cpu_cores); | |
945 | if (features1 & (1 << 9)) /* apic */ | |
946 | bufptr += __small_sprintf (bufptr, "apicid\t\t: %d\n" | |
947 | "initial apicid\t: %d\n", | |
948 | apic_id, initial_apic_id); | |
949 | ||
950 | } | |
951 | ||
952 | bufptr += __small_sprintf (bufptr, "fpu\t\t: %s\n" | |
953 | "fpu_exception\t: %s\n" | |
954 | "cpuid level\t: %d\n" | |
955 | "wp\t\t: yes\n", | |
956 | (features1 & (1 << 0)) ? "yes" : "no", | |
957 | (features1 & (1 << 0)) ? "yes" : "no", | |
958 | maxf); | |
959 | print ("flags\t\t:"); | |
960 | if (features1 & (1 << 0)) | |
961 | print (" fpu"); | |
962 | if (features1 & (1 << 1)) | |
963 | print (" vme"); | |
964 | if (features1 & (1 << 2)) | |
965 | print (" de"); | |
966 | if (features1 & (1 << 3)) | |
967 | print (" pse"); | |
968 | if (features1 & (1 << 4)) | |
969 | print (" tsc"); | |
970 | if (features1 & (1 << 5)) | |
971 | print (" msr"); | |
972 | if (features1 & (1 << 6)) | |
973 | print (" pae"); | |
974 | if (features1 & (1 << 7)) | |
975 | print (" mce"); | |
976 | if (features1 & (1 << 8)) | |
977 | print (" cx8"); | |
978 | if (features1 & (1 << 9)) | |
979 | print (" apic"); | |
980 | if (features1 & (1 << 11)) | |
981 | print (" sep"); | |
982 | if (features1 & (1 << 12)) | |
983 | print (" mtrr"); | |
984 | if (features1 & (1 << 13)) | |
985 | print (" pge"); | |
986 | if (features1 & (1 << 14)) | |
987 | print (" mca"); | |
988 | if (features1 & (1 << 15)) | |
989 | print (" cmov"); | |
990 | if (features1 & (1 << 16)) | |
991 | print (" pat"); | |
992 | if (features1 & (1 << 17)) | |
993 | print (" pse36"); | |
994 | if (features1 & (1 << 18)) | |
995 | print (" pn"); | |
996 | if (features1 & (1 << 19)) | |
997 | print (" clflush"); | |
998 | if (is_intel && features1 & (1 << 21)) | |
999 | print (" dts"); | |
1000 | if (is_intel && features1 & (1 << 22)) | |
1001 | print (" acpi"); | |
1002 | if (features1 & (1 << 23)) | |
1003 | print (" mmx"); | |
1004 | if (features1 & (1 << 24)) | |
1005 | print (" fxsr"); | |
1006 | if (features1 & (1 << 25)) | |
1007 | print (" sse"); | |
1008 | if (features1 & (1 << 26)) | |
1009 | print (" sse2"); | |
1010 | if (is_intel && (features1 & (1 << 27))) | |
1011 | print (" ss"); | |
1012 | if (features1 & (1 << 28)) | |
1013 | print (" ht"); | |
1014 | if (is_intel) | |
1015 | { | |
1016 | if (features1 & (1 << 29)) | |
1017 | print (" tm"); | |
1018 | if (features1 & (1 << 30)) | |
1019 | print (" ia64"); | |
1020 | if (features1 & (1 << 31)) | |
1021 | print (" pbe"); | |
1022 | } | |
1023 | ||
1024 | if (is_amd && maxe >= 0x80000001) | |
1025 | { | |
1026 | cpuid (&unused, &unused, &unused, &features1, 0x80000001); | |
1027 | ||
1028 | if (features1 & (1 << 11)) | |
1029 | print (" syscall"); | |
1030 | if (features1 & (1 << 19)) /* Huh? Not in AMD64 specs. */ | |
1031 | print (" mp"); | |
1032 | if (features1 & (1 << 20)) | |
1033 | print (" nx"); | |
1034 | if (features1 & (1 << 22)) | |
1035 | print (" mmxext"); | |
1036 | if (features1 & (1 << 25)) | |
1037 | print (" fxsr_opt"); | |
1038 | if (features1 & (1 << 26)) | |
1039 | print (" pdpe1gb"); | |
1040 | if (features1 & (1 << 27)) | |
1041 | print (" rdtscp"); | |
1042 | if (features1 & (1 << 29)) | |
1043 | print (" lm"); | |
1044 | if (features1 & (1 << 30)) /* 31th bit is on. */ | |
1045 | print (" 3dnowext"); | |
1046 | if (features1 & (1 << 31)) /* 32th bit (highest) is on. */ | |
1047 | print (" 3dnow"); | |
1048 | } | |
fcdca881 | 1049 | |
e0d48deb CV |
1050 | if (features2 & (1 << 0)) |
1051 | print (" pni"); | |
1052 | if (is_intel) | |
1053 | { | |
1054 | if (features2 & (1 << 2)) | |
1055 | print (" dtes64"); | |
1056 | if (features2 & (1 << 3)) | |
1057 | print (" monitor"); | |
1058 | if (features2 & (1 << 4)) | |
1059 | print (" ds_cpl"); | |
1060 | if (features2 & (1 << 5)) | |
1061 | print (" vmx"); | |
1062 | if (features2 & (1 << 6)) | |
1063 | print (" smx"); | |
1064 | if (features2 & (1 << 7)) | |
1065 | print (" est"); | |
1066 | if (features2 & (1 << 8)) | |
1067 | print (" tm2"); | |
1068 | if (features2 & (1 << 9)) | |
1069 | print (" ssse3"); | |
1070 | if (features2 & (1 << 10)) | |
1071 | print (" cid"); | |
1072 | if (features2 & (1 << 12)) | |
1073 | print (" fma"); | |
1074 | } | |
1075 | if (features2 & (1 << 13)) | |
1076 | print (" cx16"); | |
1077 | if (is_intel) | |
1078 | { | |
1079 | if (features2 & (1 << 14)) | |
1080 | print (" xtpr"); | |
1081 | if (features2 & (1 << 15)) | |
1082 | print (" pdcm"); | |
1083 | if (features2 & (1 << 18)) | |
1084 | print (" dca"); | |
1085 | if (features2 & (1 << 19)) | |
1086 | print (" sse4_1"); | |
1087 | if (features2 & (1 << 20)) | |
1088 | print (" sse4_2"); | |
1089 | if (features2 & (1 << 21)) | |
1090 | print (" x2apic"); | |
1091 | if (features2 & (1 << 22)) | |
1092 | print (" movbe"); | |
1093 | if (features2 & (1 << 23)) | |
1094 | print (" popcnt"); | |
1095 | if (features2 & (1 << 25)) | |
1096 | print (" aes"); | |
1097 | if (features2 & (1 << 26)) | |
1098 | print (" xsave"); | |
1099 | if (features2 & (1 << 27)) | |
1100 | print (" osxsave"); | |
1101 | if (features2 & (1 << 28)) | |
1102 | print (" avx"); | |
1103 | if (features2 & (1 << 29)) | |
1104 | print (" f16c"); | |
1105 | if (features2 & (1 << 30)) | |
1106 | print (" rdrand"); | |
1107 | if (features2 & (1 << 31)) | |
1108 | print (" hypervisor"); | |
1109 | } | |
1110 | ||
1111 | if (maxe >= 0x80000001) | |
1112 | { | |
1113 | cpuid (&unused, &unused, &features1, &unused, 0x80000001); | |
1114 | ||
1115 | if (features1 & (1 << 0)) | |
1116 | print (" lahf_lm"); | |
1117 | if (features1 & (1 << 1)) | |
1118 | print (" cmp_legacy"); | |
1119 | if (is_amd) | |
1120 | { | |
c367dfd0 | 1121 | if (features1 & (1 << 2)) |
e0d48deb | 1122 | print (" svm"); |
c367dfd0 | 1123 | if (features1 & (1 << 3)) |
e0d48deb | 1124 | print (" extapic"); |
c367dfd0 | 1125 | if (features1 & (1 << 4)) |
e0d48deb | 1126 | print (" cr8_legacy"); |
c367dfd0 | 1127 | if (features1 & (1 << 5)) |
e0d48deb | 1128 | print (" abm"); |
c367dfd0 | 1129 | if (features1 & (1 << 6)) |
e0d48deb | 1130 | print (" sse4a"); |
c367dfd0 | 1131 | if (features1 & (1 << 7)) |
e0d48deb | 1132 | print (" misalignsse"); |
c367dfd0 | 1133 | if (features1 & (1 << 8)) |
e0d48deb | 1134 | print (" 3dnowprefetch"); |
c367dfd0 | 1135 | if (features1 & (1 << 9)) |
e0d48deb CV |
1136 | print (" osvw"); |
1137 | } | |
1138 | if (features1 & (1 << 10)) | |
1139 | print (" ibs"); | |
1140 | if (is_amd) | |
1141 | { | |
c367dfd0 | 1142 | if (features1 & (1 << 11)) |
e0d48deb | 1143 | print (" sse5"); |
c367dfd0 | 1144 | if (features1 & (1 << 12)) |
e0d48deb | 1145 | print (" skinit"); |
c367dfd0 | 1146 | if (features1 & (1 << 13)) |
e0d48deb | 1147 | print (" wdt"); |
c367dfd0 | 1148 | if (features1 & (1 << 15)) |
e0d48deb | 1149 | print (" lwp"); |
c367dfd0 | 1150 | if (features1 & (1 << 16)) |
e0d48deb | 1151 | print (" fma4"); |
c367dfd0 | 1152 | if (features1 & (1 << 17)) |
e0d48deb | 1153 | print (" tce"); |
c367dfd0 | 1154 | if (features1 & (1 << 19)) |
e0d48deb CV |
1155 | print (" nodeid_msr"); |
1156 | if (features1 & (1 << 21)) | |
1157 | print (" tbm"); | |
1158 | if (features1 & (1 << 22)) | |
1159 | print (" topoext"); | |
c367dfd0 | 1160 | if (features1 & (1 << 23)) |
e0d48deb | 1161 | print (" perfctr_core"); |
c367dfd0 | 1162 | if (features1 & (1 << 24)) |
e0d48deb | 1163 | print (" perfctr_nb"); |
fcdca881 | 1164 | if (features1 & (1 << 28)) |
e0d48deb CV |
1165 | print (" perfctr_l2"); |
1166 | } | |
1167 | } | |
1168 | if (is_intel) /* features scattered in various CPUID levels. */ | |
1169 | { | |
1170 | cpuid (&features1, &unused, &features2, &unused, 0x06); | |
1171 | ||
1172 | if (features1 & (1 << 1)) | |
1173 | print (" ida"); | |
1174 | if (features1 & (1 << 2)) | |
1175 | print (" arat"); | |
1176 | if (features2 & (1 << 3)) | |
1177 | print (" epb"); | |
1178 | ||
1179 | cpuid (&features2, &unused, &unused, &unused, 0x0d, 1); | |
1180 | if (features2 & (1 << 0)) | |
1181 | print (" xsaveopt"); | |
1182 | ||
1183 | if (features1 & (1 << 4)) | |
1184 | print (" pln"); | |
1185 | if (features1 & (1 << 6)) | |
1186 | print (" pts"); | |
1187 | if (features1 & (1 << 0)) | |
1188 | print (" dtherm"); | |
1189 | } | |
1190 | if (is_intel) /* Extended feature flags */ | |
1191 | { | |
1192 | cpuid (&unused, &features1, &unused, &unused, 0x07, 0); | |
1193 | ||
1194 | if (features1 & (1 << 0)) | |
1195 | print (" fsgsbase"); | |
1196 | if (features1 & (1 << 1)) | |
1197 | print (" tsc_adjust"); | |
1198 | if (features1 & (1 << 3)) | |
1199 | print (" bmi1"); | |
1200 | if (features1 & (1 << 4)) | |
1201 | print (" hle"); | |
1202 | if (features1 & (1 << 5)) | |
1203 | print (" avx2"); | |
1204 | if (features1 & (1 << 7)) | |
1205 | print (" smep"); | |
1206 | if (features1 & (1 << 8)) | |
1207 | print (" bmi2"); | |
1208 | if (features1 & (1 << 9)) | |
1209 | print (" erms"); | |
1210 | if (features1 & (1 << 10)) | |
1211 | print (" invpcid"); | |
1212 | if (features1 & (1 << 11)) | |
1213 | print (" rtm"); | |
1214 | if (features1 & (1 << 14)) | |
1215 | print (" mpx"); | |
1216 | if (features1 & (1 << 16)) | |
1217 | print (" avx512f"); | |
1218 | if (features1 & (1 << 18)) | |
1219 | print (" rdseed"); | |
1220 | if (features1 & (1 << 19)) | |
1221 | print (" adx"); | |
1222 | if (features1 & (1 << 20)) | |
1223 | print (" smap"); | |
1224 | if (features1 & (1 << 23)) | |
1225 | print (" clflushopt"); | |
1226 | if (features1 & (1 << 26)) | |
1227 | print (" avx512pf"); | |
1228 | if (features1 & (1 << 27)) | |
1229 | print (" avx512er"); | |
1230 | if (features1 & (1 << 28)) | |
1231 | print (" avx512cd"); | |
1232 | } | |
fcdca881 | 1233 | |
e0d48deb | 1234 | print ("\n"); |
26462985 | 1235 | |
e0d48deb | 1236 | /* TODO: bogomips */ |
fcdca881 | 1237 | |
e0d48deb CV |
1238 | bufptr += __small_sprintf (bufptr, "clflush size\t: %d\n" |
1239 | "cache_alignment\t: %d\n", | |
1240 | clflush, | |
1241 | cache_alignment); | |
fcdca881 | 1242 | |
e0d48deb CV |
1243 | if (maxe >= 0x80000008) /* Address size. */ |
1244 | { | |
1245 | uint32_t addr_size, phys, virt; | |
1246 | cpuid (&addr_size, &unused, &unused, &unused, 0x80000008); | |
1247 | ||
1248 | phys = addr_size & 0xff; | |
1249 | virt = (addr_size >> 8) & 0xff; | |
1250 | /* Fix an errata on Intel CPUs */ | |
1251 | if (is_intel && family == 15 && model == 3 && stepping == 4) | |
1252 | phys = 36; | |
1253 | bufptr += __small_sprintf (bufptr, "address sizes\t: " | |
1254 | "%u bits physical, " | |
1255 | "%u bits virtual\n", | |
1256 | phys, virt); | |
1257 | } | |
fcdca881 | 1258 | |
e0d48deb CV |
1259 | if (maxe >= 0x80000007) /* Advanced power management. */ |
1260 | { | |
1261 | cpuid (&unused, &unused, &unused, &features1, 0x80000007); | |
1262 | ||
1263 | print ("power management:"); | |
1264 | if (features1 & (1 << 0)) | |
1265 | print (" ts"); | |
1266 | if (features1 & (1 << 1)) | |
1267 | print (" fid"); | |
1268 | if (features1 & (1 << 2)) | |
1269 | print (" vid"); | |
1270 | if (features1 & (1 << 3)) | |
1271 | print (" ttp"); | |
1272 | if (features1 & (1 << 4)) | |
1273 | print (" tm"); | |
1274 | if (features1 & (1 << 5)) | |
1275 | print (" stc"); | |
1276 | if (features1 & (1 << 6)) | |
1277 | print (" 100mhzsteps"); | |
1278 | if (features1 & (1 << 7)) | |
1279 | print (" hwpstate"); | |
861a27db CV |
1280 | if (features1 & (1 << 9)) |
1281 | print (" cpb"); | |
1282 | if (features1 & (1 << 10)) | |
1283 | print (" eff_freq_ro"); | |
e0d48deb | 1284 | } |
fcdca881 | 1285 | |
e0d48deb CV |
1286 | if (orig_affinity_mask != 0) |
1287 | { | |
1288 | if (wincap.has_processor_groups ()) | |
1289 | SetThreadGroupAffinity (GetCurrentThread (), &orig_group_affinity, | |
1290 | NULL); | |
570858c3 | 1291 | else |
e0d48deb | 1292 | SetThreadAffinityMask (GetCurrentThread (), orig_affinity_mask); |
c367dfd0 | 1293 | } |
f5ab5b84 CV |
1294 | print ("\n"); |
1295 | } | |
c367dfd0 | 1296 | |
38f50ae4 CV |
1297 | destbuf = (char *) crealloc_abort (destbuf, bufptr - buf); |
1298 | memcpy (destbuf, buf, bufptr - buf); | |
1299 | return bufptr - buf; | |
c367dfd0 CF |
1300 | } |
1301 | ||
61522196 | 1302 | static off_t |
38f50ae4 | 1303 | format_proc_partitions (void *, char *&destbuf) |
c367dfd0 | 1304 | { |
e9c8cb31 | 1305 | OBJECT_ATTRIBUTES attr; |
e9c8cb31 CV |
1306 | IO_STATUS_BLOCK io; |
1307 | NTSTATUS status; | |
483e9d00 | 1308 | HANDLE dirhdl; |
38f50ae4 CV |
1309 | tmp_pathbuf tp; |
1310 | ||
1311 | char *buf = tp.c_get (); | |
1312 | char *bufptr = buf; | |
483e9d00 | 1313 | char *ioctl_buf = tp.c_get (); |
a3dfd53a CV |
1314 | PWCHAR mp_buf = tp.w_get (); |
1315 | WCHAR fpath[MAX_PATH]; | |
1316 | WCHAR gpath[MAX_PATH]; | |
1317 | DWORD len; | |
e9c8cb31 CV |
1318 | |
1319 | /* Open \Device object directory. */ | |
86a1bb43 | 1320 | wchar_t wpath[MAX_PATH] = L"\\Device"; |
e9c8cb31 CV |
1321 | UNICODE_STRING upath = {14, 16, wpath}; |
1322 | InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL); | |
1323 | status = NtOpenDirectoryObject (&dirhdl, DIRECTORY_QUERY, &attr); | |
1324 | if (!NT_SUCCESS (status)) | |
1325 | { | |
61522196 | 1326 | debug_printf ("NtOpenDirectoryObject, status %y", status); |
483e9d00 | 1327 | __seterrno_from_nt_status (status); |
38f50ae4 | 1328 | return 0; |
e9c8cb31 CV |
1329 | } |
1330 | ||
1331 | /* Traverse \Device directory ... */ | |
1332 | PDIRECTORY_BASIC_INFORMATION dbi = (PDIRECTORY_BASIC_INFORMATION) | |
1333 | alloca (640); | |
1334 | BOOLEAN restart = TRUE; | |
483e9d00 | 1335 | bool got_one = false; |
e9c8cb31 CV |
1336 | ULONG context = 0; |
1337 | while (NT_SUCCESS (NtQueryDirectoryObject (dirhdl, dbi, 640, TRUE, restart, | |
1338 | &context, NULL))) | |
c367dfd0 | 1339 | { |
483e9d00 CV |
1340 | HANDLE devhdl; |
1341 | PARTITION_INFORMATION_EX *pix = NULL; | |
1342 | PARTITION_INFORMATION *pi = NULL; | |
1343 | DWORD bytes_read; | |
fc660168 | 1344 | DWORD part_cnt = 0; |
483e9d00 | 1345 | unsigned long long size; |
483e9d00 | 1346 | |
e9c8cb31 | 1347 | restart = FALSE; |
e9c8cb31 | 1348 | /* ... and check for a "Harddisk[0-9]*" entry. */ |
8a5e2a62 | 1349 | if (dbi->ObjectName.Length < 9 * sizeof (WCHAR) |
483e9d00 CV |
1350 | || wcsncasecmp (dbi->ObjectName.Buffer, L"Harddisk", 8) != 0 |
1351 | || !iswdigit (dbi->ObjectName.Buffer[8])) | |
e9c8cb31 | 1352 | continue; |
483e9d00 CV |
1353 | /* Got it. Now construct the path to the entire disk, which is |
1354 | "\\Device\\HarddiskX\\Partition0", and open the disk with | |
a3dfd53a | 1355 | minimum permissions. */ |
483e9d00 CV |
1356 | unsigned long drive_num = wcstoul (dbi->ObjectName.Buffer + 8, NULL, 10); |
1357 | wcscpy (wpath, dbi->ObjectName.Buffer); | |
1358 | PWCHAR wpart = wpath + dbi->ObjectName.Length / sizeof (WCHAR); | |
a3dfd53a CV |
1359 | wcpcpy (wpart, L"\\Partition0"); |
1360 | upath.Length = dbi->ObjectName.Length + 22; | |
483e9d00 CV |
1361 | upath.MaximumLength = upath.Length + sizeof (WCHAR); |
1362 | InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, | |
1363 | dirhdl, NULL); | |
61522196 CV |
1364 | status = NtOpenFile (&devhdl, READ_CONTROL, &attr, &io, |
1365 | FILE_SHARE_VALID_FLAGS, 0); | |
483e9d00 | 1366 | if (!NT_SUCCESS (status)) |
c367dfd0 | 1367 | { |
61522196 | 1368 | debug_printf ("NtOpenFile(%S), status %y", &upath, status); |
483e9d00 CV |
1369 | __seterrno_from_nt_status (status); |
1370 | continue; | |
1371 | } | |
1372 | if (!got_one) | |
1373 | { | |
a3dfd53a | 1374 | print ("major minor #blocks name win-mounts\n\n"); |
483e9d00 CV |
1375 | got_one = true; |
1376 | } | |
1377 | /* Fetch partition info for the entire disk to get its size. */ | |
61522196 CV |
1378 | if (DeviceIoControl (devhdl, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, |
1379 | ioctl_buf, NT_MAX_PATH, &bytes_read, NULL)) | |
483e9d00 CV |
1380 | { |
1381 | pix = (PARTITION_INFORMATION_EX *) ioctl_buf; | |
1382 | size = pix->PartitionLength.QuadPart; | |
c367dfd0 | 1383 | } |
483e9d00 CV |
1384 | else if (DeviceIoControl (devhdl, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, |
1385 | ioctl_buf, NT_MAX_PATH, &bytes_read, NULL)) | |
1386 | { | |
1387 | pi = (PARTITION_INFORMATION *) ioctl_buf; | |
1388 | size = pi->PartitionLength.QuadPart; | |
1389 | } | |
483e9d00 CV |
1390 | else |
1391 | { | |
1392 | debug_printf ("DeviceIoControl (%S, " | |
1393 | "IOCTL_DISK_GET_PARTITION_INFO{_EX}) %E", &upath); | |
1394 | size = 0; | |
1395 | } | |
b2867a68 | 1396 | device dev (drive_num, 0); |
483e9d00 | 1397 | bufptr += __small_sprintf (bufptr, "%5d %5d %9U %s\n", |
44d2fc0a | 1398 | dev.get_major (), dev.get_minor (), |
b2867a68 | 1399 | size >> 10, dev.name () + 5); |
483e9d00 | 1400 | /* Fetch drive layout info to get size of all partitions on the disk. */ |
61522196 CV |
1401 | if (DeviceIoControl (devhdl, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, |
1402 | NULL, 0, ioctl_buf, NT_MAX_PATH, &bytes_read, NULL)) | |
483e9d00 CV |
1403 | { |
1404 | PDRIVE_LAYOUT_INFORMATION_EX pdlix = (PDRIVE_LAYOUT_INFORMATION_EX) | |
1405 | ioctl_buf; | |
1406 | part_cnt = pdlix->PartitionCount; | |
1407 | pix = pdlix->PartitionEntry; | |
1408 | } | |
1409 | else if (DeviceIoControl (devhdl, IOCTL_DISK_GET_DRIVE_LAYOUT, | |
1410 | NULL, 0, ioctl_buf, NT_MAX_PATH, &bytes_read, NULL)) | |
1411 | { | |
1412 | PDRIVE_LAYOUT_INFORMATION pdli = (PDRIVE_LAYOUT_INFORMATION) ioctl_buf; | |
1413 | part_cnt = pdli->PartitionCount; | |
1414 | pi = pdli->PartitionEntry; | |
1415 | } | |
1416 | else | |
1417 | debug_printf ("DeviceIoControl(%S, " | |
1418 | "IOCTL_DISK_GET_DRIVE_LAYOUT{_EX}): %E", &upath); | |
1419 | /* Loop over partitions. */ | |
1420 | if (pix || pi) | |
b2867a68 | 1421 | for (DWORD i = 0; i < part_cnt && i < 64; ++i) |
483e9d00 CV |
1422 | { |
1423 | DWORD part_num; | |
1424 | ||
1425 | if (pix) | |
1426 | { | |
1427 | size = pix->PartitionLength.QuadPart; | |
1428 | part_num = pix->PartitionNumber; | |
1429 | ++pix; | |
1430 | } | |
1431 | else | |
1432 | { | |
1433 | size = pi->PartitionLength.QuadPart; | |
61522196 | 1434 | part_num = pi->PartitionNumber; |
483e9d00 CV |
1435 | ++pi; |
1436 | } | |
1437 | /* A partition number of 0 denotes an extended partition or a | |
1438 | filler entry as described in fhandler_dev_floppy::lock_partition. | |
1439 | Just skip. */ | |
1440 | if (part_num == 0) | |
1441 | continue; | |
b2867a68 | 1442 | device dev (drive_num, part_num); |
a3dfd53a CV |
1443 | |
1444 | bufptr += __small_sprintf (bufptr, "%5d %5d %9U %s", | |
44d2fc0a | 1445 | dev.get_major (), dev.get_minor (), |
b2867a68 | 1446 | size >> 10, dev.name () + 5); |
a3dfd53a CV |
1447 | /* Check if the partition is mounted in Windows and, if so, |
1448 | print the mount point list. */ | |
1449 | __small_swprintf (fpath, | |
1450 | L"\\\\?\\GLOBALROOT\\Device\\%S\\Partition%u\\", | |
1451 | &dbi->ObjectName, part_num); | |
1452 | if (GetVolumeNameForVolumeMountPointW (fpath, gpath, MAX_PATH) | |
1453 | && GetVolumePathNamesForVolumeNameW (gpath, mp_buf, | |
1454 | NT_MAX_PATH, &len)) | |
1455 | { | |
b2867a68 | 1456 | len = strlen (dev.name () + 5); |
a3dfd53a CV |
1457 | while (len++ < 6) |
1458 | *bufptr++ = ' '; | |
1459 | for (PWCHAR p = mp_buf; *p; p = wcschr (p, L'\0') + 1) | |
1460 | bufptr += __small_sprintf (bufptr, " %W", p); | |
1461 | } | |
1462 | ||
1463 | *bufptr++ = '\n'; | |
483e9d00 CV |
1464 | } |
1465 | NtClose (devhdl); | |
c367dfd0 | 1466 | } |
e9c8cb31 CV |
1467 | NtClose (dirhdl); |
1468 | ||
483e9d00 CV |
1469 | if (!got_one) |
1470 | return 0; | |
1471 | ||
38f50ae4 CV |
1472 | destbuf = (char *) crealloc_abort (destbuf, bufptr - buf); |
1473 | memcpy (destbuf, buf, bufptr - buf); | |
1474 | return bufptr - buf; | |
c367dfd0 CF |
1475 | } |
1476 | ||
61522196 | 1477 | static off_t |
38f50ae4 | 1478 | format_proc_self (void *, char *&destbuf) |
40255b64 | 1479 | { |
38f50ae4 | 1480 | destbuf = (char *) crealloc_abort (destbuf, 16); |
40255b64 CV |
1481 | return __small_sprintf (destbuf, "%d", getpid ()); |
1482 | } | |
1483 | ||
f207699a CV |
1484 | static off_t |
1485 | format_proc_cygdrive (void *, char *&destbuf) | |
1486 | { | |
1487 | destbuf = (char *) crealloc_abort (destbuf, mount_table->cygdrive_len + 1); | |
1488 | char *dend = stpcpy (destbuf, mount_table->cygdrive); | |
e91c2f80 CV |
1489 | if (dend > destbuf + 1) /* cygdrive != "/"? */ |
1490 | *--dend = '\0'; | |
f207699a CV |
1491 | return dend - destbuf; |
1492 | } | |
1493 | ||
61522196 | 1494 | static off_t |
8c71dc58 CV |
1495 | format_proc_mounts (void *, char *&destbuf) |
1496 | { | |
1497 | destbuf = (char *) crealloc_abort (destbuf, sizeof ("self/mounts")); | |
1498 | return __small_sprintf (destbuf, "self/mounts"); | |
1499 | } | |
1500 | ||
61522196 | 1501 | static off_t |
a52993d4 CV |
1502 | format_proc_filesystems (void *, char *&destbuf) |
1503 | { | |
1504 | tmp_pathbuf tp; | |
1505 | char *buf = tp.c_get (); | |
1506 | char *bufptr = buf; | |
1507 | ||
1508 | /* start at 1 to skip type "none" */ | |
1509 | for (int i = 1; fs_names[i].name; i++) | |
1510 | bufptr += __small_sprintf(bufptr, "%s\t%s\n", | |
b86f999a CF |
1511 | fs_names[i].block_device ? "" : "nodev", |
1512 | fs_names[i].name); | |
a52993d4 CV |
1513 | |
1514 | destbuf = (char *) crealloc_abort (destbuf, bufptr - buf); | |
1515 | memcpy (destbuf, buf, bufptr - buf); | |
1516 | return bufptr - buf; | |
1517 | } | |
1518 | ||
61522196 | 1519 | static off_t |
5f6d028d YS |
1520 | format_proc_swaps (void *, char *&destbuf) |
1521 | { | |
205b8208 | 1522 | unsigned long long total = 0ULL, used = 0ULL; |
5f6d028d YS |
1523 | PSYSTEM_PAGEFILE_INFORMATION spi = NULL; |
1524 | ULONG size = 512; | |
177dc6c7 | 1525 | NTSTATUS status = STATUS_SUCCESS; |
5f6d028d YS |
1526 | |
1527 | tmp_pathbuf tp; | |
1528 | char *buf = tp.c_get (); | |
1529 | char *bufptr = buf; | |
1530 | ||
1531 | spi = (PSYSTEM_PAGEFILE_INFORMATION) malloc (size); | |
1532 | if (spi) | |
1533 | { | |
177dc6c7 CV |
1534 | status = NtQuerySystemInformation (SystemPagefileInformation, (PVOID) spi, |
1535 | size, &size); | |
1536 | if (status == STATUS_INFO_LENGTH_MISMATCH) | |
5f6d028d YS |
1537 | { |
1538 | free (spi); | |
1539 | spi = (PSYSTEM_PAGEFILE_INFORMATION) malloc (size); | |
1540 | if (spi) | |
177dc6c7 CV |
1541 | status = NtQuerySystemInformation (SystemPagefileInformation, |
1542 | (PVOID) spi, size, &size); | |
5f6d028d YS |
1543 | } |
1544 | } | |
1545 | ||
1546 | bufptr += __small_sprintf (bufptr, | |
b86f999a | 1547 | "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n"); |
5f6d028d | 1548 | |
177dc6c7 | 1549 | if (spi && NT_SUCCESS (status)) |
5f6d028d YS |
1550 | { |
1551 | PSYSTEM_PAGEFILE_INFORMATION spp = spi; | |
3ccae7b6 | 1552 | char *filename = tp.c_get (); |
5f6d028d YS |
1553 | do |
1554 | { | |
177dc6c7 CV |
1555 | total = (unsigned long long) spp->CurrentSize * wincap.page_size (); |
1556 | used = (unsigned long long) spp->TotalUsed * wincap.page_size (); | |
177dc6c7 | 1557 | cygwin_conv_path (CCP_WIN_W_TO_POSIX, spp->FileName.Buffer, |
3ccae7b6 | 1558 | filename, NT_MAX_PATH); |
205b8208 | 1559 | bufptr += sprintf (bufptr, "%-40s%-16s%-8llu%-8llu%-8d\n", |
b86f999a | 1560 | filename, "file", total >> 10, used >> 10, 0); |
5f6d028d YS |
1561 | } |
1562 | while (spp->NextEntryOffset | |
1563 | && (spp = (PSYSTEM_PAGEFILE_INFORMATION) | |
177dc6c7 | 1564 | ((char *) spp + spp->NextEntryOffset))); |
5f6d028d YS |
1565 | } |
1566 | ||
1567 | if (spi) | |
1568 | free (spi); | |
1569 | ||
1570 | destbuf = (char *) crealloc_abort (destbuf, bufptr - buf); | |
1571 | memcpy (destbuf, buf, bufptr - buf); | |
1572 | return bufptr - buf; | |
1573 | } | |
1574 | ||
61522196 | 1575 | static off_t |
07797cc0 YS |
1576 | format_proc_devices (void *, char *&destbuf) |
1577 | { | |
1578 | tmp_pathbuf tp; | |
1579 | char *buf = tp.c_get (); | |
1580 | char *bufptr = buf; | |
1581 | ||
1582 | bufptr += __small_sprintf (bufptr, | |
1583 | "Character devices:\n" | |
1584 | "%3d mem\n" | |
1585 | "%3d cons\n" | |
1586 | "%3d /dev/tty\n" | |
1587 | "%3d /dev/console\n" | |
1588 | "%3d /dev/ptmx\n" | |
1589 | "%3d st\n" | |
1590 | "%3d misc\n" | |
1591 | "%3d sound\n" | |
1592 | "%3d ttyS\n" | |
1593 | "%3d tty\n" | |
1594 | "\n" | |
1595 | "Block devices:\n" | |
1596 | "%3d fd\n" | |
1597 | "%3d sd\n" | |
1598 | "%3d sr\n" | |
1599 | "%3d sd\n" | |
1600 | "%3d sd\n" | |
1601 | "%3d sd\n" | |
1602 | "%3d sd\n" | |
1603 | "%3d sd\n" | |
1604 | "%3d sd\n" | |
1605 | "%3d sd\n", | |
1606 | DEV_MEM_MAJOR, DEV_CONS_MAJOR, _major (FH_TTY), | |
23771fa1 | 1607 | _major (FH_CONSOLE), _major (FH_PTMX), |
07797cc0 | 1608 | DEV_TAPE_MAJOR, DEV_MISC_MAJOR, DEV_SOUND_MAJOR, |
38d732a1 | 1609 | DEV_SERIAL_MAJOR, DEV_PTYS_MAJOR, DEV_FLOPPY_MAJOR, |
07797cc0 YS |
1610 | DEV_SD_MAJOR, DEV_CDROM_MAJOR, DEV_SD1_MAJOR, |
1611 | DEV_SD2_MAJOR, DEV_SD3_MAJOR, DEV_SD4_MAJOR, | |
1612 | DEV_SD5_MAJOR, DEV_SD6_MAJOR, DEV_SD7_MAJOR); | |
1613 | ||
1614 | destbuf = (char *) crealloc_abort (destbuf, bufptr - buf); | |
1615 | memcpy (destbuf, buf, bufptr - buf); | |
1616 | return bufptr - buf; | |
1617 | } | |
1618 | ||
61522196 | 1619 | static off_t |
07797cc0 YS |
1620 | format_proc_misc (void *, char *&destbuf) |
1621 | { | |
1622 | tmp_pathbuf tp; | |
1623 | char *buf = tp.c_get (); | |
1624 | char *bufptr = buf; | |
1625 | ||
1626 | bufptr += __small_sprintf (bufptr, | |
1627 | "%3d clipboard\n" | |
1628 | "%3d windows\n", | |
1629 | _minor (FH_CLIPBOARD), _minor (FH_WINDOWS)); | |
1630 | ||
1631 | destbuf = (char *) crealloc_abort (destbuf, bufptr - buf); | |
1632 | memcpy (destbuf, buf, bufptr - buf); | |
1633 | return bufptr - buf; | |
1634 | } | |
1635 | ||
c367dfd0 | 1636 | #undef print |