OSDN Git Service

Initial checkin of text Corinna sent to cygwin-announce.
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / fhandler_proc.cc
1 /* fhandler_proc.cc: fhandler for /proc virtual filesystem
2
3    Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011 Red Hat, Inc.
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"
12 #include "miscfuncs.h"
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include "cygerrno.h"
17 #include "security.h"
18 #include "path.h"
19 #include "fhandler.h"
20 #include "fhandler_virtual.h"
21 #include "pinfo.h"
22 #include "dtable.h"
23 #include "cygheap.h"
24 #include "tls_pbuf.h"
25 #include <sys/utsname.h>
26 #include <sys/param.h>
27 #include <sys/sysinfo.h>
28 #include "ntdll.h"
29 #include <winioctl.h>
30 #include <wchar.h>
31 #include <wctype.h>
32 #include "cpuid.h"
33 #include "mount.h"
34
35 #define _COMPILING_NEWLIB
36 #include <dirent.h>
37
38 static _off64_t format_proc_loadavg (void *, char *&);
39 static _off64_t format_proc_meminfo (void *, char *&);
40 static _off64_t format_proc_stat (void *, char *&);
41 static _off64_t format_proc_version (void *, char *&);
42 static _off64_t format_proc_uptime (void *, char *&);
43 static _off64_t format_proc_cpuinfo (void *, char *&);
44 static _off64_t format_proc_partitions (void *, char *&);
45 static _off64_t format_proc_self (void *, char *&);
46 static _off64_t format_proc_mounts (void *, char *&);
47 static _off64_t format_proc_filesystems (void *, char *&);
48 static _off64_t format_proc_swaps (void *, char *&);
49 static _off64_t format_proc_devices (void *, char *&);
50 static _off64_t format_proc_misc (void *, char *&);
51
52 /* names of objects in /proc */
53 static const virt_tab_t proc_tab[] = {
54   { _VN ("."),           FH_PROC,       virt_directory, NULL },
55   { _VN (".."),          FH_PROC,       virt_directory, NULL },
56   { _VN ("cpuinfo"),     FH_PROC,       virt_file,      format_proc_cpuinfo },
57   { _VN ("devices"),     FH_PROC,       virt_file,      format_proc_devices },
58   { _VN ("filesystems"), FH_PROC,       virt_file,      format_proc_filesystems },
59   { _VN ("loadavg"),     FH_PROC,       virt_file,      format_proc_loadavg },
60   { _VN ("meminfo"),     FH_PROC,       virt_file,      format_proc_meminfo },
61   { _VN ("misc"),        FH_PROC,       virt_file,      format_proc_misc },
62   { _VN ("mounts"),      FH_PROC,       virt_symlink,   format_proc_mounts },
63   { _VN ("net"),         FH_PROCNET,    virt_directory, NULL },
64   { _VN ("partitions"),  FH_PROC,       virt_file,      format_proc_partitions },
65   { _VN ("registry"),    FH_REGISTRY,   virt_directory, NULL  },
66   { _VN ("registry32"),  FH_REGISTRY,   virt_directory, NULL },
67   { _VN ("registry64"),  FH_REGISTRY,   virt_directory, NULL },
68   { _VN ("self"),        FH_PROC,       virt_symlink,   format_proc_self },
69   { _VN ("stat"),        FH_PROC,       virt_file,      format_proc_stat },
70   { _VN ("swaps"),       FH_PROC,       virt_file,      format_proc_swaps },
71   { _VN ("sys"),         FH_PROCSYS,    virt_directory, NULL },
72   { _VN ("sysvipc"),     FH_PROCSYSVIPC,        virt_directory, NULL },
73   { _VN ("uptime"),      FH_PROC,       virt_file,      format_proc_uptime },
74   { _VN ("version"),     FH_PROC,       virt_file,      format_proc_version },
75   { NULL, 0,             FH_NADA,       virt_none,      NULL }
76 };
77
78 #define PROC_DIR_COUNT 4
79
80 static const int PROC_LINK_COUNT = (sizeof (proc_tab) / sizeof (virt_tab_t)) - 1;
81
82 /* name of the /proc filesystem */
83 const char proc[] = "/proc";
84 const size_t proc_len = sizeof (proc) - 1;
85
86 /* bsearch compare function. */
87 static int
88 proc_tab_cmp (const void *key, const void *memb)
89 {
90   int ret = strncmp (((virt_tab_t *) key)->name, ((virt_tab_t *) memb)->name,
91                      ((virt_tab_t *) memb)->name_len);
92   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] != '/')
93     return 1;
94   return ret;
95 }
96
97 /* Helper function to perform a binary search of the incoming pathname
98    against the alpha-sorted virtual file table. */
99 virt_tab_t *
100 virt_tab_search (const char *path, bool prefix, const virt_tab_t *table,
101                  size_t nelem)
102 {
103   virt_tab_t key = { path, 0, FH_NADA, virt_none, NULL };
104   virt_tab_t *entry = (virt_tab_t *) bsearch (&key, table, nelem,
105                                               sizeof (virt_tab_t),
106                                               proc_tab_cmp);
107   if (entry && (path[entry->name_len] == '\0'
108                 || (prefix && path[entry->name_len] == '/')))
109     return entry;
110   return NULL;
111 }
112
113 /* Auxillary function that returns the fhandler associated with the given
114    path. */
115 fh_devices
116 fhandler_proc::get_proc_fhandler (const char *path)
117 {
118   debug_printf ("get_proc_fhandler(%s)", path);
119   path += proc_len;
120   /* Since this method is called from path_conv::check we can't rely on
121      it being normalised and therefore the path may have runs of slashes
122      in it.  */
123   while (isdirsep (*path))
124     path++;
125
126   /* Check if this is the root of the virtual filesystem (i.e. /proc).  */
127   if (*path == 0)
128     return FH_PROC;
129
130   virt_tab_t *entry = virt_tab_search (path, true, proc_tab,
131                                        PROC_LINK_COUNT);
132   if (entry)
133     return entry->fhandler;
134
135   int pid = atoi (path);
136   pinfo p (pid);
137   /* If p->pid != pid, then pid is actually the Windows PID for an execed
138      Cygwin process, and the pinfo entry is the additional entry created
139      at exec time.  We don't want to enable the user to access a process
140      entry by using the Win32 PID, though. */
141   if (p && p->pid == pid)
142     return FH_PROCESS;
143
144   bool has_subdir = false;
145   while (*path)
146     if (isdirsep (*path++))
147       {
148         has_subdir = true;
149         break;
150       }
151
152   if (has_subdir)
153     /* The user is trying to access a non-existent subdirectory of /proc. */
154     return FH_NADA;
155   else
156     /* Return FH_PROC so that we can return EROFS if the user is trying to
157        create a file. */
158     return FH_PROC;
159 }
160
161 /* Returns 0 if path doesn't exist, >0 if path is a directory,
162    -1 if path is a file, -2 if it's a symlink.  */
163 virtual_ftype_t
164 fhandler_proc::exists ()
165 {
166   const char *path = get_name ();
167   debug_printf ("exists (%s)", path);
168   path += proc_len;
169   if (*path == 0)
170     return virt_rootdir;
171   virt_tab_t *entry = virt_tab_search (path + 1, false, proc_tab,
172                                        PROC_LINK_COUNT);
173   if (entry)
174     {
175       fileid = entry - proc_tab;
176       return entry->type;
177     }
178   return virt_none;
179 }
180
181 fhandler_proc::fhandler_proc ():
182   fhandler_virtual ()
183 {
184 }
185
186 int
187 fhandler_proc::fstat (struct __stat64 *buf)
188 {
189   const char *path = get_name ();
190   debug_printf ("fstat (%s)", path);
191
192   path += proc_len;
193   fhandler_base::fstat (buf);
194
195   buf->st_mode &= ~_IFMT & NO_W;
196
197   if (!*path)
198     {
199       winpids pids ((DWORD) 0);
200       buf->st_ino = 2;
201       buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
202       buf->st_nlink = PROC_DIR_COUNT + 2 + pids.npids;
203       return 0;
204     }
205   else
206     {
207       virt_tab_t *entry = virt_tab_search (path + 1, false, proc_tab,
208                                            PROC_LINK_COUNT);
209       if (entry)
210         {
211           if (entry->type == virt_directory)
212             buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
213           else if (entry->type == virt_symlink)
214             buf->st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
215           else
216             {
217               buf->st_mode &= NO_X;
218               buf->st_mode |= S_IFREG;
219             }
220           return 0;
221         }
222     }
223   set_errno (ENOENT);
224   return -1;
225 }
226
227 DIR *
228 fhandler_proc::opendir (int fd)
229 {
230   DIR *dir = fhandler_virtual::opendir (fd);
231   if (dir && !(dir->__handle = (void *) new winpids ((DWORD) 0)))
232     {
233       free (dir);
234       dir = NULL;
235       set_errno (ENOMEM);
236     }
237   return dir;
238 }
239
240 int
241 fhandler_proc::closedir (DIR *dir)
242 {
243   delete (winpids *) dir->__handle;
244   return fhandler_virtual::closedir (dir);
245 }
246
247 int
248 fhandler_proc::readdir (DIR *dir, dirent *de)
249 {
250   int res;
251   if (dir->__d_position < PROC_LINK_COUNT)
252     {
253       strcpy (de->d_name, proc_tab[dir->__d_position++].name);
254       dir->__flags |= dirent_saw_dot | dirent_saw_dot_dot;
255       res = 0;
256     }
257   else
258     {
259       winpids &pids = *(winpids *) dir->__handle;
260       int found = 0;
261       res = ENMFILE;
262       for (unsigned i = 0; i < pids.npids; i++)
263         if (found++ == dir->__d_position - PROC_LINK_COUNT)
264           {
265             __small_sprintf (de->d_name, "%d", pids[i]->pid);
266             dir->__d_position++;
267             res = 0;
268             break;
269           }
270     }
271
272   syscall_printf ("%d = readdir(%p, %p) (%s)", res, dir, de, de->d_name);
273   return res;
274 }
275
276 int
277 fhandler_proc::open (int flags, mode_t mode)
278 {
279   int proc_file_no = -1;
280
281   int res = fhandler_virtual::open (flags, mode);
282   if (!res)
283     goto out;
284
285   nohandle (true);
286
287   const char *path;
288
289   path = get_name () + proc_len;
290
291   if (!*path)
292     {
293       if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
294         {
295           set_errno (EEXIST);
296           res = 0;
297           goto out;
298         }
299       else if (flags & O_WRONLY)
300         {
301           set_errno (EISDIR);
302           res = 0;
303           goto out;
304         }
305       else
306         {
307           flags |= O_DIROPEN;
308           goto success;
309         }
310     }
311
312   proc_file_no = -1;
313   for (int i = 0; proc_tab[i].name; i++)
314     if (path_prefix_p (proc_tab[i].name, path + 1, strlen (proc_tab[i].name),
315                        false))
316       {
317         proc_file_no = i;
318         if (proc_tab[i].fhandler != FH_PROC)
319           {
320             if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
321               {
322                 set_errno (EEXIST);
323                 res = 0;
324                 goto out;
325               }
326             else if (flags & O_WRONLY)
327               {
328                 set_errno (EISDIR);
329                 res = 0;
330                 goto out;
331               }
332             else
333               {
334                 flags |= O_DIROPEN;
335                 goto success;
336               }
337           }
338       }
339
340   if (proc_file_no == -1)
341     {
342       if (flags & O_CREAT)
343         {
344           set_errno (EROFS);
345           res = 0;
346           goto out;
347         }
348       else
349         {
350           set_errno (ENOENT);
351           res = 0;
352           goto out;
353         }
354     }
355   if (flags & O_WRONLY)
356     {
357       set_errno (EROFS);
358       res = 0;
359       goto out;
360     }
361
362   fileid = proc_file_no;
363   if (!fill_filebuf ())
364     {
365       res = 0;
366       goto out;
367     }
368
369   if (flags & O_APPEND)
370     position = filesize;
371   else
372     position = 0;
373
374 success:
375   res = 1;
376   set_flags ((flags & ~O_TEXT) | O_BINARY);
377   set_open_status ();
378 out:
379   syscall_printf ("%d = fhandler_proc::open(%p, %d)", res, flags, mode);
380   return res;
381 }
382
383 bool
384 fhandler_proc::fill_filebuf ()
385 {
386   if (fileid < PROC_LINK_COUNT && proc_tab[fileid].format_func)
387     {
388       filesize = proc_tab[fileid].format_func (NULL, filebuf);
389       if (filesize > 0)
390         return true;
391     }
392   return false;
393 }
394
395 static _off64_t
396 format_proc_version (void *, char *&destbuf)
397 {
398   tmp_pathbuf tp;
399   char *buf = tp.c_get ();
400   char *bufptr = buf;
401   struct utsname uts_name;
402
403   uname (&uts_name);
404   bufptr += __small_sprintf (bufptr, "%s version %s (%s@%s) (%s) %s\n",
405                           uts_name.sysname, uts_name.release, USERNAME, HOSTNAME,
406                           GCC_VERSION, uts_name.version);
407
408   destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
409   memcpy (destbuf, buf, bufptr - buf);
410   return bufptr - buf;
411 }
412
413 static _off64_t
414 format_proc_loadavg (void *, char *&destbuf)
415 {
416   extern int get_process_state (DWORD dwProcessId);
417   unsigned running = 0;
418   winpids pids ((DWORD) 0);
419
420   for (unsigned i = 0; i < pids.npids; i++)
421     switch (get_process_state (i)) {
422       case 'O':
423       case 'R':
424         running++;
425         break;
426     }
427
428   destbuf = (char *) crealloc_abort (destbuf, 16);
429   return __small_sprintf (destbuf, "%u.%02u %u.%02u %u.%02u %u/%u\n",
430                                     0, 0, 0, 0, 0, 0, running, pids.npids);
431 }
432
433 static _off64_t
434 format_proc_meminfo (void *, char *&destbuf)
435 {
436   unsigned long long mem_total, mem_free, swap_total, swap_free;
437   struct sysinfo info;
438
439   sysinfo (&info);
440   mem_total = (unsigned long long) info.totalram * info.mem_unit;
441   mem_free = (unsigned long long) info.freeram * info.mem_unit;
442   swap_total = (unsigned long long) info.totalswap * info.mem_unit;
443   swap_free = (unsigned long long) info.freeswap * info.mem_unit;
444
445   destbuf = (char *) crealloc_abort (destbuf, 512);
446   return sprintf (destbuf, "MemTotal:     %10llu kB\n"
447                            "MemFree:      %10llu kB\n"
448                            "HighTotal:             0 kB\n"
449                            "HighFree:              0 kB\n"
450                            "LowTotal:     %10llu kB\n"
451                            "LowFree:      %10llu kB\n"
452                            "SwapTotal:    %10llu kB\n"
453                            "SwapFree:     %10llu kB\n",
454                            mem_total >> 10, mem_free >> 10,
455                            mem_total >> 10, mem_free >> 10,
456                            swap_total >> 10, swap_free >> 10);
457 }
458
459 static _off64_t
460 format_proc_uptime (void *, char *&destbuf)
461 {
462   unsigned long long uptime = 0ULL, idle_time = 0ULL;
463   NTSTATUS status;
464   SYSTEM_TIME_OF_DAY_INFORMATION stodi;
465   /* Sizeof SYSTEM_PERFORMANCE_INFORMATION on 64 bit systems.  It
466      appears to contain some trailing additional information from
467      what I can tell after examining the content.
468      FIXME: It would be nice if this could be verified somehow. */
469   const size_t sizeof_spi = sizeof (SYSTEM_PERFORMANCE_INFORMATION) + 16;
470   PSYSTEM_PERFORMANCE_INFORMATION spi = (PSYSTEM_PERFORMANCE_INFORMATION)
471                                         alloca (sizeof_spi);
472
473   status = NtQuerySystemInformation (SystemTimeOfDayInformation, &stodi,
474                                      sizeof stodi, NULL);
475   if (NT_SUCCESS (status))
476     uptime = (stodi.CurrentTime.QuadPart - stodi.BootTime.QuadPart) / 100000ULL;
477   else
478     debug_printf ("NtQuerySystemInformation(SystemTimeOfDayInformation), "
479                   "status %p", status);
480
481   if (NT_SUCCESS (NtQuerySystemInformation (SystemPerformanceInformation,
482                                                  spi, sizeof_spi, NULL)))
483     idle_time = (spi->IdleTime.QuadPart / wincap.cpu_count ())
484                 / 100000ULL;
485
486   destbuf = (char *) crealloc_abort (destbuf, 80);
487   return __small_sprintf (destbuf, "%U.%02u %U.%02u\n",
488                           uptime / 100, long (uptime % 100),
489                           idle_time / 100, long (idle_time % 100));
490 }
491
492 static _off64_t
493 format_proc_stat (void *, char *&destbuf)
494 {
495   unsigned long pages_in = 0UL, pages_out = 0UL, interrupt_count = 0UL,
496                 context_switches = 0UL, swap_in = 0UL, swap_out = 0UL;
497   time_t boot_time = 0;
498   NTSTATUS status;
499   /* Sizeof SYSTEM_PERFORMANCE_INFORMATION on 64 bit systems.  It
500      appears to contain some trailing additional information from
501      what I can tell after examining the content.
502      FIXME: It would be nice if this could be verified somehow. */
503   const size_t sizeof_spi = sizeof (SYSTEM_PERFORMANCE_INFORMATION) + 16;
504   PSYSTEM_PERFORMANCE_INFORMATION spi = (PSYSTEM_PERFORMANCE_INFORMATION)
505                                         alloca (sizeof_spi);
506   SYSTEM_TIME_OF_DAY_INFORMATION stodi;
507   tmp_pathbuf tp;
508
509   char *buf = tp.c_get ();
510   char *eobuf = buf;
511
512   SYSTEM_PROCESSOR_TIMES spt[wincap.cpu_count ()];
513   status = NtQuerySystemInformation (SystemProcessorTimes, (PVOID) spt,
514                                      sizeof spt[0] * wincap.cpu_count (), NULL);
515   if (!NT_SUCCESS (status))
516     debug_printf ("NtQuerySystemInformation(SystemProcessorTimes), "
517                   "status %p", status);
518   else
519     {
520       unsigned long long user_time = 0ULL, kernel_time = 0ULL, idle_time = 0ULL;
521       for (unsigned long i = 0; i < wincap.cpu_count (); i++)
522         {
523           kernel_time += (spt[i].KernelTime.QuadPart - spt[i].IdleTime.QuadPart)
524                          * HZ / 10000000ULL;
525           user_time += spt[i].UserTime.QuadPart * HZ / 10000000ULL;
526           idle_time += spt[i].IdleTime.QuadPart * HZ / 10000000ULL;
527         }
528
529       eobuf += __small_sprintf (eobuf, "cpu %U %U %U %U\n",
530                                 user_time, 0ULL, kernel_time, idle_time);
531       user_time = 0ULL, kernel_time = 0ULL, idle_time = 0ULL;
532       for (unsigned long i = 0; i < wincap.cpu_count (); i++)
533         {
534           interrupt_count += spt[i].InterruptCount;
535           kernel_time = (spt[i].KernelTime.QuadPart - spt[i].IdleTime.QuadPart) * HZ / 10000000ULL;
536           user_time = spt[i].UserTime.QuadPart * HZ / 10000000ULL;
537           idle_time = spt[i].IdleTime.QuadPart * HZ / 10000000ULL;
538           eobuf += __small_sprintf (eobuf, "cpu%d %U %U %U %U\n", i,
539                                     user_time, 0ULL, kernel_time, idle_time);
540         }
541
542       status = NtQuerySystemInformation (SystemPerformanceInformation,
543                                          (PVOID) spi, sizeof_spi, NULL);
544       if (!NT_SUCCESS (status))
545         {
546           debug_printf ("NtQuerySystemInformation(SystemPerformanceInformation)"
547                         ", status %p", status);
548           memset (spi, 0, sizeof_spi);
549         }
550       status = NtQuerySystemInformation (SystemTimeOfDayInformation,
551                                          (PVOID) &stodi, sizeof stodi, NULL);
552       if (!NT_SUCCESS (status))
553         debug_printf ("NtQuerySystemInformation(SystemTimeOfDayInformation), "
554                       "status %p", status);
555     }
556   if (!NT_SUCCESS (status))
557     {
558       __seterrno_from_nt_status (status);
559       return 0;
560     }
561
562   pages_in = spi->PagesRead;
563   pages_out = spi->PagefilePagesWritten + spi->MappedFilePagesWritten;
564   /* Note: there is no distinction made in this structure between pages read
565      from the page file and pages read from mapped files, but there is such
566      a distinction made when it comes to writing.  Goodness knows why.  The
567      value of swap_in, then, will obviously be wrong but its our best guess. */
568   swap_in = spi->PagesRead;
569   swap_out = spi->PagefilePagesWritten;
570   context_switches = spi->ContextSwitches;
571   boot_time = to_time_t ((FILETIME *) &stodi.BootTime.QuadPart);
572
573   eobuf += __small_sprintf (eobuf, "page %u %u\n"
574                                    "swap %u %u\n"
575                                    "intr %u\n"
576                                    "ctxt %u\n"
577                                    "btime %u\n",
578                                    pages_in, pages_out,
579                                    swap_in, swap_out,
580                                    interrupt_count,
581                                    context_switches,
582                                    boot_time);
583   destbuf = (char *) crealloc_abort (destbuf, eobuf - buf);
584   memcpy (destbuf, buf, eobuf - buf);
585   return eobuf - buf;
586 }
587
588 #define print(x) { bufptr = stpcpy (bufptr, (x)); }
589
590 static _off64_t
591 format_proc_cpuinfo (void *, char *&destbuf)
592 {
593   DWORD orig_affinity_mask;
594   int cpu_number;
595   const int BUFSIZE = 256;
596   union
597   {
598     BYTE b[BUFSIZE];
599     char s[BUFSIZE];
600     WCHAR w[BUFSIZE / sizeof (WCHAR)];
601     DWORD d;
602     unsigned m[13];
603   } in_buf;
604   tmp_pathbuf tp;
605
606   char *buf = tp.c_get ();
607   char *bufptr = buf;
608
609   for (cpu_number = 0; ; cpu_number++)
610     {
611       WCHAR cpu_key[128];
612       __small_swprintf (cpu_key, L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION"
613                                   "\\System\\CentralProcessor\\%d", cpu_number);
614       if (!NT_SUCCESS (RtlCheckRegistryKey (RTL_REGISTRY_ABSOLUTE, cpu_key)))
615         break;
616       if (cpu_number)
617         print ("\n");
618
619       orig_affinity_mask = SetThreadAffinityMask (GetCurrentThread (),
620                                                   1 << cpu_number);
621       if (orig_affinity_mask == 0)
622         debug_printf ("SetThreadAffinityMask failed %E");
623       /* I'm not sure whether the thread changes processor immediately
624          and I'm not sure whether this function will cause the thread
625          to be rescheduled */
626       yield ();
627
628       bool has_cpuid = false;
629
630       if (!can_set_flag (0x00040000))
631         debug_printf ("386 processor - no cpuid");
632       else
633         {
634           debug_printf ("486 processor");
635           if (can_set_flag (0x00200000))
636             {
637               debug_printf ("processor supports CPUID instruction");
638               has_cpuid = true;
639             }
640           else
641             debug_printf ("processor does not support CPUID instruction");
642         }
643
644       if (!has_cpuid)
645         {
646           WCHAR vendor[64], id[64];
647           UNICODE_STRING uvendor, uid;
648           RtlInitEmptyUnicodeString (&uvendor, vendor, sizeof (vendor));
649           RtlInitEmptyUnicodeString (&uid, id, sizeof (id));
650           DWORD cpu_mhz = 0;
651           RTL_QUERY_REGISTRY_TABLE tab[4] = {
652            { NULL, RTL_QUERY_REGISTRY_NOEXPAND | RTL_QUERY_REGISTRY_DIRECT,
653              L"VendorIdentifier", &uvendor, REG_NONE, NULL, 0 },
654            { NULL, RTL_QUERY_REGISTRY_NOEXPAND | RTL_QUERY_REGISTRY_DIRECT,
655              L"Identifier", &uid, REG_NONE, NULL, 0 },
656            { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOSTRING,
657              L"~Mhz", &cpu_mhz, REG_NONE, NULL, 0 },
658            { NULL, 0, NULL, NULL, 0, NULL, 0 }
659           };
660
661           RtlQueryRegistryValues (RTL_REGISTRY_ABSOLUTE, cpu_key, tab,
662                                   NULL, NULL);
663           bufptr += __small_sprintf (bufptr,
664                                      "processor       : %d\n"
665                                      "vendor_id       : %S\n"
666                                      "identifier      : %S\n"
667                                      "cpu MHz         : %u\n",
668                                      cpu_number, &uvendor, &uid, cpu_mhz);
669           print ("flags           :");
670           if (IsProcessorFeaturePresent (PF_3DNOW_INSTRUCTIONS_AVAILABLE))
671             print (" 3dnow");
672           if (IsProcessorFeaturePresent (PF_COMPARE_EXCHANGE_DOUBLE))
673             print (" cx8");
674           if (!IsProcessorFeaturePresent (PF_FLOATING_POINT_EMULATED))
675             print (" fpu");
676           if (IsProcessorFeaturePresent (PF_MMX_INSTRUCTIONS_AVAILABLE))
677             print (" mmx");
678           if (IsProcessorFeaturePresent (PF_PAE_ENABLED))
679             print (" pae");
680           if (IsProcessorFeaturePresent (PF_RDTSC_INSTRUCTION_AVAILABLE))
681             print (" tsc");
682           if (IsProcessorFeaturePresent (PF_XMMI_INSTRUCTIONS_AVAILABLE))
683             print (" sse");
684           if (IsProcessorFeaturePresent (PF_XMMI64_INSTRUCTIONS_AVAILABLE))
685             print (" sse2");
686         }
687       else
688         {
689           DWORD cpu_mhz = 0;
690           RTL_QUERY_REGISTRY_TABLE tab[2] = {
691             { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOSTRING,
692               L"~Mhz", &cpu_mhz, REG_NONE, NULL, 0 },
693             { NULL, 0, NULL, NULL, 0, NULL, 0 }
694           };
695
696           RtlQueryRegistryValues (RTL_REGISTRY_ABSOLUTE, cpu_key, tab,
697                                   NULL, NULL);
698           bufptr += __small_sprintf (bufptr, "processor\t: %d\n", cpu_number);
699           unsigned maxf, vendor_id[4], unused;
700           cpuid (&maxf, &vendor_id[0], &vendor_id[2], &vendor_id[1], 0);
701           maxf &= 0xffff;
702           vendor_id[3] = 0;
703
704           /* Vendor identification. */
705           bool is_amd = false, is_intel = false;
706           if (!strcmp ((char*)vendor_id, "AuthenticAMD"))
707             is_amd = true;
708           else if (!strcmp ((char*)vendor_id, "GenuineIntel"))
709             is_intel = true;
710
711           bufptr += __small_sprintf (bufptr, "vendor_id\t: %s\n",
712                                      (char *)vendor_id);
713           if (maxf >= 1)
714             {
715               unsigned features2, features1, extra_info, cpuid_sig;
716               cpuid (&cpuid_sig, &extra_info, &features2, &features1, 1);
717               /* unsigned extended_family = (cpuid_sig & 0x0ff00000) >> 20,
718                           extended_model  = (cpuid_sig & 0x000f0000) >> 16,
719                           type            = (cpuid_sig & 0x00003000) >> 12; */
720               unsigned family           = (cpuid_sig & 0x00000f00) >> 8,
721                        model            = (cpuid_sig & 0x000000f0) >> 4,
722                        stepping         = cpuid_sig & 0x0000000f;
723               /* Not printed on Linux */
724               //unsigned brand_id               = extra_info & 0x0000000f;
725               //unsigned cpu_count      = (extra_info & 0x00ff0000) >> 16;
726               unsigned apic_id          = (extra_info & 0xff000000) >> 24;
727               if (family == 15)
728                 family += (cpuid_sig >> 20) & 0xff;
729               if (family >= 6)
730                 model += ((cpuid_sig >> 16) & 0x0f) << 4;
731               unsigned maxe = 0;
732               cpuid (&maxe, &unused, &unused, &unused, 0x80000000);
733               if (maxe >= 0x80000004)
734                 {
735                   cpuid (&in_buf.m[0], &in_buf.m[1], &in_buf.m[2],
736                          &in_buf.m[3], 0x80000002);
737                   cpuid (&in_buf.m[4], &in_buf.m[5], &in_buf.m[6],
738                          &in_buf.m[7], 0x80000003);
739                   cpuid (&in_buf.m[8], &in_buf.m[9], &in_buf.m[10],
740                          &in_buf.m[11], 0x80000004);
741                   in_buf.m[12] = 0;
742                 }
743               else
744                 {
745                   /* Could implement a lookup table here if someone needs it. */
746                   strcpy (in_buf.s, "unknown");
747                 }
748               int cache_size = -1,
749                   tlb_size = -1,
750                   clflush = 64,
751                   cache_alignment = 64;
752               if (features1 & (1 << 19)) /* CLFSH */
753                 clflush = ((extra_info >> 8) & 0xff) << 3;
754               if (is_intel && family == 15)
755                 cache_alignment = clflush * 2;
756               if (maxe >= 0x80000005) /* L1 Cache and TLB Identifiers. */
757                 {
758                   unsigned data_cache, inst_cache;
759                   cpuid (&unused, &unused, &data_cache, &inst_cache,
760                          0x80000005);
761
762                   cache_size = (inst_cache >> 24) + (data_cache >> 24);
763                   tlb_size = 0;
764                 }
765               if (maxe >= 0x80000006) /* L2 Cache and L2 TLB Identifiers. */
766                 {
767                   unsigned tlb, l2;
768                   cpuid (&unused, &tlb, &l2, &unused, 0x80000006);
769
770                   cache_size = l2 >> 16;
771                   tlb_size = ((tlb >> 16) & 0xfff) + (tlb & 0xfff);
772                 }
773               bufptr += __small_sprintf (bufptr, "cpu family\t: %d\n"
774                                                  "model\t\t: %d\n"
775                                                  "model name\t: %s\n"
776                                                  "stepping\t: %d\n"
777                                                  "cpu MHz\t\t: %d\n",
778                                          family,
779                                          model,
780                                          in_buf.s + strspn (in_buf.s, "         "),
781                                          stepping,
782                                          cpu_mhz);
783               if (cache_size >= 0)
784                 bufptr += __small_sprintf (bufptr, "cache size\t: %d KB\n",
785                                            cache_size);
786
787               /* Recognize multi-core CPUs. */
788               if (is_amd && maxe >= 0x80000008)
789                 {
790                   unsigned core_info;
791                   cpuid (&unused, &unused, &core_info, &unused, 0x80000008);
792
793                   int max_cores = 1 + (core_info & 0xff);
794                   if (max_cores > 1)
795                     {
796                       int shift = (core_info >> 12) & 0x0f;
797                       if (!shift)
798                         while ((1 << shift) < max_cores)
799                           ++shift;
800                       int core_id = apic_id & ((1 << shift) - 1);
801                       apic_id >>= shift;
802
803                       bufptr += __small_sprintf (bufptr, "physical id\t: %d\n"
804                                                          "core id\t\t: %d\n"
805                                                          "cpu cores\t: %d\n",
806                                                  apic_id, core_id, max_cores);
807                     }
808                 }
809               /* Recognize Intel Hyper-Transport CPUs. */
810               else if (is_intel && (features1 & (1 << 28)) && maxf >= 4)
811                 {
812                   /* TODO */
813                 }
814
815               bufptr += __small_sprintf (bufptr, "fpu\t\t: %s\n"
816                                                  "fpu_exception\t: %s\n"
817                                                  "cpuid level\t: %d\n"
818                                                  "wp\t\t: yes\n",
819                                          (features1 & (1 << 0)) ? "yes" : "no",
820                                          (features1 & (1 << 0)) ? "yes" : "no",
821                                          maxf);
822               print ("flags\t\t:");
823               if (features1 & (1 << 0))
824                 print (" fpu");
825               if (features1 & (1 << 1))
826                 print (" vme");
827               if (features1 & (1 << 2))
828                 print (" de");
829               if (features1 & (1 << 3))
830                 print (" pse");
831               if (features1 & (1 << 4))
832                 print (" tsc");
833               if (features1 & (1 << 5))
834                 print (" msr");
835               if (features1 & (1 << 6))
836                 print (" pae");
837               if (features1 & (1 << 7))
838                 print (" mce");
839               if (features1 & (1 << 8))
840                 print (" cx8");
841               if (features1 & (1 << 9))
842                 print (" apic");
843               if (features1 & (1 << 11))
844                 print (" sep");
845               if (features1 & (1 << 12))
846                 print (" mtrr");
847               if (features1 & (1 << 13))
848                 print (" pge");
849               if (features1 & (1 << 14))
850                 print (" mca");
851               if (features1 & (1 << 15))
852                 print (" cmov");
853               if (features1 & (1 << 16))
854                 print (" pat");
855               if (features1 & (1 << 17))
856                 print (" pse36");
857               if (features1 & (1 << 18))
858                 print (" pn");
859               if (features1 & (1 << 19))
860                 print (" clflush");
861               if (is_intel && features1 & (1 << 21))
862                 print (" dts");
863               if (is_intel && features1 & (1 << 22))
864                 print (" acpi");
865               if (features1 & (1 << 23))
866                 print (" mmx");
867               if (features1 & (1 << 24))
868                 print (" fxsr");
869               if (features1 & (1 << 25))
870                 print (" sse");
871               if (features1 & (1 << 26))
872                 print (" sse2");
873               if (is_intel && (features1 & (1 << 27)))
874                 print (" ss");
875               if (features1 & (1 << 28))
876                 print (" ht");
877               if (is_intel)
878                 {
879                   if (features1 & (1 << 29))
880                     print (" tm");
881                   if (features1 & (1 << 30))
882                     print (" ia64");
883                   if (features1 & (1 << 31))
884                     print (" pbe");
885                 }
886
887               if (is_amd && maxe >= 0x80000001)
888                 {
889                   unsigned features;
890                   cpuid (&unused, &unused, &unused, &features, 0x80000001);
891
892                   if (features & (1 << 11))
893                     print (" syscall");
894                   if (features & (1 << 19)) /* Huh?  Not in AMD64 specs. */
895                     print (" mp");
896                   if (features & (1 << 20))
897                     print (" nx");
898                   if (features & (1 << 22))
899                     print (" mmxext");
900                   if (features & (1 << 25))
901                     print (" fxsr_opt");
902                   if (features & (1 << 26))
903                     print (" pdpe1gb");
904                   if (features & (1 << 27))
905                     print (" rdtscp");
906                   if (features & (1 << 29))
907                     print (" lm");
908                   if (features & (1 << 30)) /* 31th bit is on. */
909                     print (" 3dnowext");
910                   if (features & (1 << 31)) /* 32th bit (highest) is on. */
911                     print (" 3dnow");
912                 }
913
914               if (features2 & (1 << 0))
915                 print (" pni");
916               if (is_intel)
917                 {
918                   if (features2 & (1 << 2))
919                     print (" dtes64");
920                   if (features2 & (1 << 3))
921                     print (" monitor");
922                   if (features2 & (1 << 4))
923                     print (" ds_cpl");
924                   if (features2 & (1 << 5))
925                     print (" vmx");
926                   if (features2 & (1 << 6))
927                     print (" smx");
928                   if (features2 & (1 << 7))
929                     print (" est");
930                   if (features2 & (1 << 8))
931                     print (" tm2");
932                   if (features2 & (1 << 9))
933                     print (" ssse3");
934                   if (features2 & (1 << 10))
935                     print (" cid");
936                   if (features2 & (1 << 12))
937                     print (" fma");
938                 }
939               if (features2 & (1 << 13))
940                 print (" cx16");
941               if (is_intel)
942                 {
943                   if (features2 & (1 << 14))
944                     print (" xtpr");
945                   if (features2 & (1 << 15))
946                     print (" pdcm");
947                   if (features2 & (1 << 18))
948                     print (" dca");
949                   if (features2 & (1 << 19))
950                     print (" sse4_1");
951                   if (features2 & (1 << 20))
952                     print (" sse4_2");
953                   if (features2 & (1 << 21))
954                     print (" x2apic");
955                   if (features2 & (1 << 22))
956                     print (" movbe");
957                   if (features2 & (1 << 23))
958                     print (" popcnt");
959                   if (features2 & (1 << 25))
960                     print (" aes");
961                   if (features2 & (1 << 26))
962                     print (" xsave");
963                   if (features2 & (1 << 27))
964                     print (" osxsave");
965                   if (features2 & (1 << 28))
966                     print (" avx");
967                 }
968
969               if (maxe >= 0x80000001)
970                 {
971                   unsigned features;
972                   cpuid (&unused, &unused, &features, &unused, 0x80000001);
973
974                   if (features & (1 << 0))
975                     print (" lahf_lm");
976                   if (features & (1 << 1))
977                     print (" cmp_legacy");
978                   if (is_amd)
979                     {
980                       if (features & (1 << 2))
981                         print (" svm");
982                       if (features & (1 << 3))
983                         print (" extapic");
984                       if (features & (1 << 4))
985                         print (" cr8_legacy");
986                       if (features & (1 << 5))
987                         print (" abm");
988                       if (features & (1 << 6))
989                         print (" sse4a");
990                       if (features & (1 << 7))
991                         print (" misalignsse");
992                       if (features & (1 << 8))
993                         print (" 3dnowprefetch");
994                       if (features & (1 << 9))
995                         print (" osvw");
996                     }
997                   if (features & (1 << 10))
998                     print (" ibs");
999                   if (is_amd)
1000                     {
1001                       if (features & (1 << 11))
1002                         print (" sse5");
1003                       if (features & (1 << 12))
1004                         print (" skinit");
1005                       if (features & (1 << 13))
1006                         print (" wdt");
1007                     }
1008                 }
1009
1010               print ("\n");
1011
1012               /* TODO: bogomips */
1013
1014               if (tlb_size >= 0)
1015                 bufptr += __small_sprintf (bufptr,
1016                                            "TLB size\t: %d 4K pages\n",
1017                                            tlb_size);
1018               bufptr += __small_sprintf (bufptr, "clflush size\t: %d\n"
1019                                                  "cache_alignment\t: %d\n",
1020                                          clflush,
1021                                          cache_alignment);
1022
1023               if (maxe >= 0x80000008) /* Address size. */
1024                 {
1025                   unsigned addr_size, phys, virt;
1026                   cpuid (&addr_size, &unused, &unused, &unused, 0x80000008);
1027
1028                   phys = addr_size & 0xff;
1029                   virt = (addr_size >> 8) & 0xff;
1030                   /* Fix an errata on Intel CPUs */
1031                   if (is_intel && family == 15 && model == 3 && stepping == 4)
1032                     phys = 36;
1033                   bufptr += __small_sprintf (bufptr, "address sizes\t: "
1034                                                      "%u bits physical, "
1035                                                      "%u bits virtual\n",
1036                                              phys, virt);
1037                 }
1038
1039               if (maxe >= 0x80000007) /* Advanced power management. */
1040                 {
1041                   cpuid (&unused, &unused, &unused, &features2, 0x80000007);
1042
1043                   print ("power management:");
1044                   if (features2 & (1 << 0))
1045                     print (" ts");
1046                   if (features2 & (1 << 1))
1047                     print (" fid");
1048                   if (features2 & (1 << 2))
1049                     print (" vid");
1050                   if (features2 & (1 << 3))
1051                     print (" ttp");
1052                   if (features2 & (1 << 4))
1053                     print (" tm");
1054                   if (features2 & (1 << 5))
1055                     print (" stc");
1056                   if (features2 & (1 << 6))
1057                     print (" 100mhzsteps");
1058                   if (features2 & (1 << 7))
1059                     print (" hwpstate");
1060                 }
1061             }
1062           else
1063             {
1064               bufptr += __small_sprintf (bufptr, "cpu MHz         : %d\n"
1065                                                  "fpu             : %s\n",
1066                                                  cpu_mhz,
1067                                                  IsProcessorFeaturePresent (PF_FLOATING_POINT_EMULATED) ? "no" : "yes");
1068             }
1069         }
1070       if (orig_affinity_mask != 0)
1071         SetThreadAffinityMask (GetCurrentThread (), orig_affinity_mask);
1072       print ("\n");
1073     }
1074
1075   destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1076   memcpy (destbuf, buf, bufptr - buf);
1077   return bufptr - buf;
1078 }
1079
1080 static _off64_t
1081 format_proc_partitions (void *, char *&destbuf)
1082 {
1083   OBJECT_ATTRIBUTES attr;
1084   IO_STATUS_BLOCK io;
1085   NTSTATUS status;
1086   HANDLE dirhdl;
1087   tmp_pathbuf tp;
1088
1089   char *buf = tp.c_get ();
1090   char *bufptr = buf;
1091   char *ioctl_buf = tp.c_get ();
1092
1093   /* Open \Device object directory. */
1094   wchar_t wpath[MAX_PATH] = L"\\Device";
1095   UNICODE_STRING upath = {14, 16, wpath};
1096   InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL);
1097   status = NtOpenDirectoryObject (&dirhdl, DIRECTORY_QUERY, &attr);
1098   if (!NT_SUCCESS (status))
1099     {
1100       debug_printf ("NtOpenDirectoryObject, status %p", status);
1101       __seterrno_from_nt_status (status);
1102       return 0;
1103     }
1104
1105   /* Traverse \Device directory ... */
1106   PDIRECTORY_BASIC_INFORMATION dbi = (PDIRECTORY_BASIC_INFORMATION)
1107                                      alloca (640);
1108   BOOLEAN restart = TRUE;
1109   bool got_one = false;
1110   ULONG context = 0;
1111   while (NT_SUCCESS (NtQueryDirectoryObject (dirhdl, dbi, 640, TRUE, restart,
1112                                              &context, NULL)))
1113     {
1114       HANDLE devhdl;
1115       PARTITION_INFORMATION_EX *pix = NULL;
1116       PARTITION_INFORMATION *pi = NULL;
1117       DWORD bytes_read;
1118       DWORD part_cnt = 0;
1119       unsigned long long size;
1120       device dev;
1121
1122       restart = FALSE;
1123       /* ... and check for a "Harddisk[0-9]*" entry. */
1124       if (dbi->ObjectName.Length < 9 * sizeof (WCHAR)
1125           || wcsncasecmp (dbi->ObjectName.Buffer, L"Harddisk", 8) != 0
1126           || !iswdigit (dbi->ObjectName.Buffer[8]))
1127         continue;
1128       /* Got it.  Now construct the path to the entire disk, which is
1129          "\\Device\\HarddiskX\\Partition0", and open the disk with
1130          minimum permssions. */
1131       unsigned long drive_num = wcstoul (dbi->ObjectName.Buffer + 8, NULL, 10);
1132       wcscpy (wpath, dbi->ObjectName.Buffer);
1133       PWCHAR wpart = wpath + dbi->ObjectName.Length / sizeof (WCHAR);
1134       __small_swprintf (wpart, L"\\Partition0");
1135       upath.Length = dbi->ObjectName.Length
1136                      + wcslen (wpart) * sizeof (WCHAR);
1137       upath.MaximumLength = upath.Length + sizeof (WCHAR);
1138       InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE,
1139                                   dirhdl, NULL);
1140       /* Up to W2K the handle needs read access to fetch the partition info. */
1141       status = NtOpenFile (&devhdl, wincap.has_disk_ex_ioctls ()
1142                                     ? READ_CONTROL
1143                                     : READ_CONTROL | FILE_READ_DATA,
1144                            &attr, &io, FILE_SHARE_VALID_FLAGS, 0);
1145       if (!NT_SUCCESS (status))
1146         {
1147           debug_printf ("NtOpenFile(%S), status %p", &upath, status);
1148           __seterrno_from_nt_status (status);
1149           continue;
1150         }
1151       if (!got_one)
1152         {
1153           print ("major minor  #blocks  name\n\n");
1154           got_one = true;
1155         }
1156       /* Fetch partition info for the entire disk to get its size. */
1157       if (wincap.has_disk_ex_ioctls ()
1158           && DeviceIoControl (devhdl, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0,
1159                               ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
1160         {
1161           pix = (PARTITION_INFORMATION_EX *) ioctl_buf;
1162           size = pix->PartitionLength.QuadPart;
1163         }
1164       else if (DeviceIoControl (devhdl, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0,
1165                                 ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
1166         {
1167           pi = (PARTITION_INFORMATION *) ioctl_buf;
1168           size = pi->PartitionLength.QuadPart;
1169         }
1170       else
1171         {
1172           debug_printf ("DeviceIoControl (%S, "
1173                          "IOCTL_DISK_GET_PARTITION_INFO{_EX}) %E", &upath);
1174           size = 0;
1175         }
1176       dev.parsedisk (drive_num, 0);
1177       bufptr += __small_sprintf (bufptr, "%5d %5d %9U %s\n",
1178                                  dev.get_major (), dev.get_minor (),
1179                                  size >> 10, dev.name + 5);
1180       /* Fetch drive layout info to get size of all partitions on the disk. */
1181       if (wincap.has_disk_ex_ioctls ()
1182           && DeviceIoControl (devhdl, IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
1183                               NULL, 0, ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
1184         {
1185           PDRIVE_LAYOUT_INFORMATION_EX pdlix = (PDRIVE_LAYOUT_INFORMATION_EX)
1186                                                ioctl_buf;
1187           part_cnt = pdlix->PartitionCount;
1188           pix = pdlix->PartitionEntry;
1189         }
1190       else if (DeviceIoControl (devhdl, IOCTL_DISK_GET_DRIVE_LAYOUT,
1191                                 NULL, 0, ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
1192         {
1193           PDRIVE_LAYOUT_INFORMATION pdli = (PDRIVE_LAYOUT_INFORMATION) ioctl_buf;
1194           part_cnt = pdli->PartitionCount;
1195           pi = pdli->PartitionEntry;
1196         }
1197       else
1198         debug_printf ("DeviceIoControl(%S, "
1199                       "IOCTL_DISK_GET_DRIVE_LAYOUT{_EX}): %E", &upath);
1200       /* Loop over partitions. */
1201       if (pix || pi)
1202         for (DWORD i = 0; i < part_cnt; ++i)
1203           {
1204             DWORD part_num;
1205
1206             if (pix)
1207               {
1208                 size = pix->PartitionLength.QuadPart;
1209                 part_num = pix->PartitionNumber;
1210                 ++pix;
1211               }
1212             else
1213               {
1214                 size = pi->PartitionLength.QuadPart;
1215                 /* Pre-W2K you can't rely on the partition number info for
1216                    unused partitions. */
1217                 if (pi->PartitionType == PARTITION_ENTRY_UNUSED
1218                     || pi->PartitionType == PARTITION_EXTENDED)
1219                   part_num = 0;
1220                 else
1221                   part_num = pi->PartitionNumber;
1222                 ++pi;
1223               }
1224             /* A partition number of 0 denotes an extended partition or a
1225                filler entry as described in fhandler_dev_floppy::lock_partition.
1226                Just skip. */
1227             if (part_num == 0)
1228               continue;
1229             dev.parsedisk (drive_num, part_num);
1230             bufptr += __small_sprintf (bufptr, "%5d %5d %9U %s\n",
1231                                        dev.get_major (), dev.get_minor (),
1232                                        size >> 10, dev.name + 5);
1233           }
1234       NtClose (devhdl);
1235     }
1236   NtClose (dirhdl);
1237
1238   if (!got_one)
1239     return 0;
1240
1241   destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1242   memcpy (destbuf, buf, bufptr - buf);
1243   return bufptr - buf;
1244 }
1245
1246 static _off64_t
1247 format_proc_self (void *, char *&destbuf)
1248 {
1249   destbuf = (char *) crealloc_abort (destbuf, 16);
1250   return __small_sprintf (destbuf, "%d", getpid ());
1251 }
1252
1253 static _off64_t
1254 format_proc_mounts (void *, char *&destbuf)
1255 {
1256   destbuf = (char *) crealloc_abort (destbuf, sizeof ("self/mounts"));
1257   return __small_sprintf (destbuf, "self/mounts");
1258 }
1259
1260 static _off64_t
1261 format_proc_filesystems (void *, char *&destbuf)
1262 {
1263   tmp_pathbuf tp;
1264   char *buf = tp.c_get ();
1265   char *bufptr = buf;
1266
1267   /* start at 1 to skip type "none" */
1268   for (int i = 1; fs_names[i].name; i++)
1269     bufptr += __small_sprintf(bufptr, "%s\t%s\n",
1270                               fs_names[i].block_device ? "" : "nodev",
1271                               fs_names[i].name);
1272
1273   destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1274   memcpy (destbuf, buf, bufptr - buf);
1275   return bufptr - buf;
1276 }
1277
1278 static _off64_t
1279 format_proc_swaps (void *, char *&destbuf)
1280 {
1281   unsigned long long total = 0ULL, used = 0ULL;
1282   char *filename = NULL;
1283   ssize_t filename_len;
1284   PSYSTEM_PAGEFILE_INFORMATION spi = NULL;
1285   ULONG size = 512;
1286   NTSTATUS status = STATUS_SUCCESS;
1287
1288   tmp_pathbuf tp;
1289   char *buf = tp.c_get ();
1290   char *bufptr = buf;
1291
1292   spi = (PSYSTEM_PAGEFILE_INFORMATION) malloc (size);
1293   if (spi)
1294     {
1295       status = NtQuerySystemInformation (SystemPagefileInformation, (PVOID) spi,
1296                                          size, &size);
1297       if (status == STATUS_INFO_LENGTH_MISMATCH)
1298         {
1299           free (spi);
1300           spi = (PSYSTEM_PAGEFILE_INFORMATION) malloc (size);
1301           if (spi)
1302             status = NtQuerySystemInformation (SystemPagefileInformation,
1303                                                (PVOID) spi, size, &size);
1304         }
1305     }
1306
1307   bufptr += __small_sprintf (bufptr,
1308                              "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
1309
1310   if (spi && NT_SUCCESS (status))
1311     {
1312       PSYSTEM_PAGEFILE_INFORMATION spp = spi;
1313       do
1314         {
1315           total = (unsigned long long) spp->CurrentSize * wincap.page_size ();
1316           used = (unsigned long long) spp->TotalUsed * wincap.page_size ();
1317
1318           filename_len = cygwin_conv_path (CCP_WIN_W_TO_POSIX,
1319                                            spp->FileName.Buffer, filename, 0);
1320           filename = (char *) malloc (filename_len);
1321           cygwin_conv_path (CCP_WIN_W_TO_POSIX, spp->FileName.Buffer,
1322                             filename, filename_len);
1323
1324           bufptr += sprintf (bufptr, "%-40s%-16s%-8llu%-8llu%-8d\n",
1325                              filename, "file", total >> 10, used >> 10, 0);
1326         }
1327       while (spp->NextEntryOffset
1328              && (spp = (PSYSTEM_PAGEFILE_INFORMATION)
1329                        ((char *) spp + spp->NextEntryOffset)));
1330     }
1331
1332   if (spi)
1333     free (spi);
1334
1335   destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1336   memcpy (destbuf, buf, bufptr - buf);
1337   return bufptr - buf;
1338 }
1339
1340 static _off64_t
1341 format_proc_devices (void *, char *&destbuf)
1342 {
1343   tmp_pathbuf tp;
1344   char *buf = tp.c_get ();
1345   char *bufptr = buf;
1346
1347   bufptr += __small_sprintf (bufptr,
1348                              "Character devices:\n"
1349                              "%3d mem\n"
1350                              "%3d cons\n"
1351                              "%3d /dev/tty\n"
1352                              "%3d /dev/console\n"
1353                              "%3d /dev/ptmx\n"
1354                              "%3d st\n"
1355                              "%3d misc\n"
1356                              "%3d sound\n"
1357                              "%3d ttyS\n"
1358                              "%3d tty\n"
1359                              "\n"
1360                              "Block devices:\n"
1361                              "%3d fd\n"
1362                              "%3d sd\n"
1363                              "%3d sr\n"
1364                              "%3d sd\n"
1365                              "%3d sd\n"
1366                              "%3d sd\n"
1367                              "%3d sd\n"
1368                              "%3d sd\n"
1369                              "%3d sd\n"
1370                              "%3d sd\n",
1371                              DEV_MEM_MAJOR, DEV_CONS_MAJOR, _major (FH_TTY),
1372                              _major (FH_CONSOLE), _major (FH_PTMX),
1373                              DEV_TAPE_MAJOR, DEV_MISC_MAJOR, DEV_SOUND_MAJOR,
1374                              DEV_SERIAL_MAJOR, DEV_PTYS_MAJOR, DEV_FLOPPY_MAJOR,
1375                              DEV_SD_MAJOR, DEV_CDROM_MAJOR, DEV_SD1_MAJOR,
1376                              DEV_SD2_MAJOR, DEV_SD3_MAJOR, DEV_SD4_MAJOR,
1377                              DEV_SD5_MAJOR, DEV_SD6_MAJOR, DEV_SD7_MAJOR);
1378
1379   destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1380   memcpy (destbuf, buf, bufptr - buf);
1381   return bufptr - buf;
1382 }
1383
1384 static _off64_t
1385 format_proc_misc (void *, char *&destbuf)
1386 {
1387   tmp_pathbuf tp;
1388   char *buf = tp.c_get ();
1389   char *bufptr = buf;
1390
1391   bufptr += __small_sprintf (bufptr,
1392                              "%3d clipboard\n"
1393                              "%3d windows\n",
1394                              _minor (FH_CLIPBOARD), _minor (FH_WINDOWS));
1395
1396   destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1397   memcpy (destbuf, buf, bufptr - buf);
1398   return bufptr - buf;
1399 }
1400
1401 #undef print