Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcvs2svn <>2002-06-06 19:35:10 +0400
committercvs2svn <>2002-06-06 19:35:10 +0400
commit5eea0254c7a10b31f9c9b3f6339ce454d1d0a27c (patch)
tree9d814e53920ccebd0e41fea9121bd22254a654e8
parent2c9004bfe2b24b6f8337c6730eadc295181ed69b (diff)
This commit was manufactured by cvs2svn to create branch 'cygwin_daemon'.
Cherrypick from master 2002-06-06 15:35:09 UTC Corinna Vinschen <corinna@vinschen.de> ' * fhandler.cc (fhandler_base::fstat): Initialise tv_nsec member of': winsup/cygwin/fhandler_proc.cc winsup/cygwin/fhandler_process.cc winsup/cygwin/fhandler_registry.cc winsup/cygwin/fhandler_virtual.cc winsup/cygwin/include/netinet/udp.h winsup/cygwin/stackdump.sgml
-rw-r--r--winsup/cygwin/fhandler_proc.cc502
-rw-r--r--winsup/cygwin/fhandler_process.cc736
-rw-r--r--winsup/cygwin/fhandler_registry.cc544
-rw-r--r--winsup/cygwin/fhandler_virtual.cc226
-rw-r--r--winsup/cygwin/include/netinet/udp.h51
-rw-r--r--winsup/cygwin/stackdump.sgml13
6 files changed, 2072 insertions, 0 deletions
diff --git a/winsup/cygwin/fhandler_proc.cc b/winsup/cygwin/fhandler_proc.cc
new file mode 100644
index 000000000..65accd2e1
--- /dev/null
+++ b/winsup/cygwin/fhandler_proc.cc
@@ -0,0 +1,502 @@
+/* fhandler_proc.cc: fhandler for /proc virtual filesystem
+
+ Copyright 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/cygwin.h>
+#include <ntdef.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "fhandler.h"
+#include "path.h"
+#include "pinfo.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include <assert.h>
+#include <sys/utsname.h>
+#include "ntdll.h"
+
+#define _COMPILING_NEWLIB
+#include <dirent.h>
+
+/* offsets in proc_listing */
+static const int PROC_LOADAVG = 2; // /proc/loadavg
+static const int PROC_MEMINFO = 3; // /proc/meminfo
+static const int PROC_REGISTRY = 4; // /proc/registry
+static const int PROC_STAT = 5; // /proc/stat
+static const int PROC_VERSION = 6; // /proc/version
+static const int PROC_UPTIME = 7; // /proc/uptime
+
+/* names of objects in /proc */
+static const char *proc_listing[] = {
+ ".",
+ "..",
+ "loadavg",
+ "meminfo",
+ "registry",
+ "stat",
+ "version",
+ "uptime",
+ NULL
+};
+
+static const int PROC_LINK_COUNT = (sizeof(proc_listing) / sizeof(const char *)) - 1;
+
+/* FH_PROC in the table below means the file/directory is handles by
+ * fhandler_proc.
+ */
+static const DWORD proc_fhandlers[PROC_LINK_COUNT] = {
+ FH_PROC,
+ FH_PROC,
+ FH_PROC,
+ FH_PROC,
+ FH_REGISTRY,
+ FH_PROC,
+ FH_PROC,
+ FH_PROC
+};
+
+/* name of the /proc filesystem */
+const char proc[] = "/proc";
+const int proc_len = sizeof (proc) - 1;
+
+static off_t format_proc_meminfo (char *destbuf, size_t maxsize);
+static off_t format_proc_stat (char *destbuf, size_t maxsize);
+static off_t format_proc_uptime (char *destbuf, size_t maxsize);
+
+/* auxillary function that returns the fhandler associated with the given path
+ * this is where it would be nice to have pattern matching in C - polymorphism
+ * just doesn't cut it
+ */
+DWORD
+fhandler_proc::get_proc_fhandler (const char *path)
+{
+ debug_printf ("get_proc_fhandler(%s)", path);
+ path += proc_len;
+ /* Since this method is called from path_conv::check we can't rely on
+ * it being normalised and therefore the path may have runs of slashes
+ * in it.
+ */
+ while (SLASH_P (*path))
+ path++;
+
+ /* Check if this is the root of the virtual filesystem (i.e. /proc). */
+ if (*path == 0)
+ return FH_PROC;
+
+ for (int i = 0; proc_listing[i]; i++)
+ {
+ if (path_prefix_p (proc_listing[i], path, strlen (proc_listing[i])))
+ return proc_fhandlers[i];
+ }
+
+ if (pinfo (atoi (path)))
+ return FH_PROCESS;
+
+ bool has_subdir = false;
+ while (*path)
+ if (SLASH_P (*path++))
+ {
+ has_subdir = true;
+ break;
+ }
+
+ if (has_subdir)
+ /* The user is trying to access a non-existent subdirectory of /proc. */
+ return FH_BAD;
+ else
+ /* Return FH_PROC so that we can return EROFS if the user is trying to create
+ a file. */
+ return FH_PROC;
+}
+
+/* Returns 0 if path doesn't exist, >0 if path is a directory,
+ * <0 if path is a file.
+ */
+int
+fhandler_proc::exists ()
+{
+ const char *path = get_name ();
+ debug_printf ("exists (%s)", path);
+ path += proc_len;
+ if (*path == 0)
+ return 2;
+ for (int i = 0; proc_listing[i]; i++)
+ if (pathmatch (path + 1, proc_listing[i]))
+ return (proc_fhandlers[i] == FH_PROC) ? -1 : 1;
+ return 0;
+}
+
+fhandler_proc::fhandler_proc ():
+ fhandler_virtual (FH_PROC)
+{
+}
+
+fhandler_proc::fhandler_proc (DWORD devtype):
+ fhandler_virtual (devtype)
+{
+}
+
+int
+fhandler_proc::fstat (struct __stat64 *buf, path_conv *pc)
+{
+ const char *path = get_name ();
+ debug_printf ("fstat (%s)", path);
+
+ path += proc_len;
+ (void) fhandler_base::fstat (buf, pc);
+
+ buf->st_mode &= ~_IFMT & NO_W;
+
+ if (!*path)
+ {
+ buf->st_nlink = PROC_LINK_COUNT;
+ buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+ return 0;
+ }
+ else
+ {
+ path++;
+ for (int i = 0; proc_listing[i]; i++)
+ if (pathmatch (path, proc_listing[i]))
+ {
+ if (proc_fhandlers[i] != FH_PROC)
+ buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+ else
+ {
+ buf->st_mode &= NO_X;
+ buf->st_mode |= S_IFREG;
+ }
+ return 0;
+ }
+ }
+ set_errno (ENOENT);
+ return -1;
+}
+
+struct dirent *
+fhandler_proc::readdir (DIR * dir)
+{
+ if (dir->__d_position >= PROC_LINK_COUNT)
+ {
+ winpids pids;
+ int found = 0;
+ for (unsigned i = 0; i < pids.npids; i++)
+ if (found++ == dir->__d_position - PROC_LINK_COUNT)
+ {
+ __small_sprintf (dir->__d_dirent->d_name, "%d", pids[i]->pid);
+ dir->__d_position++;
+ return dir->__d_dirent;
+ }
+ set_errno (ENMFILE);
+ return NULL;
+ }
+
+ strcpy (dir->__d_dirent->d_name, proc_listing[dir->__d_position++]);
+ syscall_printf ("%p = readdir (%p) (%s)", &dir->__d_dirent, dir,
+ dir->__d_dirent->d_name);
+ return dir->__d_dirent;
+}
+
+int
+fhandler_proc::open (path_conv *pc, int flags, mode_t mode)
+{
+ int proc_file_no = -1;
+
+ int res = fhandler_virtual::open (pc, flags, mode);
+ if (!res)
+ goto out;
+
+ const char *path;
+
+ path = get_name () + proc_len;
+
+ if (!*path)
+ {
+ if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+ {
+ set_errno (EEXIST);
+ res = 0;
+ goto out;
+ }
+ else if (flags & O_WRONLY)
+ {
+ set_errno (EISDIR);
+ res = 0;
+ goto out;
+ }
+ else
+ {
+ flags |= O_DIROPEN;
+ goto success;
+ }
+ }
+
+ proc_file_no = -1;
+ for (int i = 0; proc_listing[i]; i++)
+ if (path_prefix_p (proc_listing[i], path + 1, strlen (proc_listing[i])))
+ {
+ proc_file_no = i;
+ if (proc_fhandlers[i] != FH_PROC)
+ {
+ if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+ {
+ set_errno (EEXIST);
+ res = 0;
+ goto out;
+ }
+ else if (flags & O_WRONLY)
+ {
+ set_errno (EISDIR);
+ res = 0;
+ goto out;
+ }
+ else
+ {
+ flags |= O_DIROPEN;
+ goto success;
+ }
+ }
+ }
+
+ if (proc_file_no == -1)
+ {
+ if (flags & O_CREAT)
+ {
+ set_errno (EROFS);
+ res = 0;
+ goto out;
+ }
+ else
+ {
+ set_errno (ENOENT);
+ res = 0;
+ goto out;
+ }
+ }
+ if (flags & O_WRONLY)
+ {
+ set_errno (EROFS);
+ res = 0;
+ goto out;
+ }
+
+ fileid = proc_file_no;
+ fill_filebuf ();
+
+ if (flags & O_APPEND)
+ position = filesize;
+ else
+ position = 0;
+
+success:
+ res = 1;
+ set_flags (flags & ~O_TEXT, O_BINARY);
+ set_open_status ();
+out:
+ syscall_printf ("%d = fhandler_proc::open (%p, %d)", res, flags, mode);
+ return res;
+}
+
+void
+fhandler_proc::fill_filebuf ()
+{
+ switch (fileid)
+ {
+ case PROC_VERSION:
+ {
+ if (!filebuf)
+ {
+ struct utsname uts_name;
+ uname (&uts_name);
+ bufalloc = strlen (uts_name.sysname) + 1 + strlen (uts_name.release) +
+ 1 + strlen (uts_name.version) + 2;
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc);
+ filesize = __small_sprintf (filebuf, "%s %s %s\n", uts_name.sysname,
+ uts_name.release, uts_name.version);
+ }
+ break;
+ }
+ case PROC_UPTIME:
+ {
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 80);
+ filesize = format_proc_uptime (filebuf, bufalloc);
+ break;
+ }
+ case PROC_STAT:
+ {
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 2048);
+ filesize = format_proc_stat (filebuf, bufalloc);
+ break;
+ }
+ case PROC_LOADAVG:
+ {
+ /*
+ * not really supported - Windows doesn't keep track of these values
+ * Windows 95/98/me does have the KERNEL/CPUUsage performance counter
+ * which is similar.
+ */
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 16);
+ filesize = __small_sprintf (filebuf, "%u.%02u %u.%02u %u.%02u\n",
+ 0, 0, 0, 0, 0, 0);
+ break;
+ }
+ case PROC_MEMINFO:
+ {
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 2048);
+ filesize = format_proc_meminfo (filebuf, bufalloc);
+ break;
+ }
+ }
+}
+
+static
+off_t
+format_proc_meminfo (char *destbuf, size_t maxsize)
+{
+ unsigned long mem_total = 0UL, mem_free = 0UL, swap_total = 0UL,
+ swap_free = 0UL;
+ MEMORYSTATUS memory_status;
+ GlobalMemoryStatus (&memory_status);
+ mem_total = memory_status.dwTotalPhys;
+ mem_free = memory_status.dwAvailPhys;
+ swap_total = memory_status.dwTotalPageFile;
+ swap_free = memory_status.dwAvailPageFile;
+ return __small_sprintf (destbuf, " total: used: free:\n"
+ "Mem: %10lu %10lu %10lu\n"
+ "Swap: %10lu %10lu %10lu\n"
+ "MemTotal: %10lu kB\n"
+ "MemFree: %10lu kB\n"
+ "MemShared: 0 kB\n"
+ "HighTotal: 0 kB\n"
+ "HighFree: 0 kB\n"
+ "LowTotal: %10lu kB\n"
+ "LowFree: %10lu kB\n"
+ "SwapTotal: %10lu kB\n"
+ "SwapFree: %10lu kB\n",
+ mem_total, mem_total - mem_free, mem_free,
+ swap_total, swap_total - swap_free, swap_free,
+ mem_total >> 10, mem_free >> 10,
+ mem_total >> 10, mem_free >> 10,
+ swap_total >> 10, swap_free >> 10);
+}
+
+static
+off_t
+format_proc_uptime (char *destbuf, size_t maxsize)
+{
+ unsigned long long uptime = 0ULL, idle_time = 0ULL;
+ SYSTEM_PROCESSOR_TIMES spt;
+
+ NTSTATUS ret = NtQuerySystemInformation (SystemProcessorTimes, (PVOID) &spt,
+ sizeof spt, NULL);
+ if (!ret && GetLastError () == ERROR_PROC_NOT_FOUND)
+ uptime = GetTickCount() / 10;
+ else if (ret != STATUS_SUCCESS)
+ {
+ __seterrno_from_win_error (RtlNtStatusToDosError (ret));
+ debug_printf("NtQuerySystemInformation: ret = %d, "
+ "Dos(ret) = %d",
+ ret, RtlNtStatusToDosError (ret));
+ return 0;
+ }
+ else
+ {
+ idle_time = spt.IdleTime.QuadPart / 100000ULL;
+ uptime = (spt.InterruptTime.QuadPart + spt.KernelTime.QuadPart +
+ spt.IdleTime.QuadPart + spt.UserTime.QuadPart +
+ spt.DpcTime.QuadPart) / 100000ULL;
+ }
+
+ return __small_sprintf (destbuf, "%U.%02u %U.%02u\n",
+ uptime / 100, long (uptime % 100),
+ idle_time / 100, long (idle_time % 100));
+}
+
+static
+off_t
+format_proc_stat (char *destbuf, size_t maxsize)
+{
+ unsigned long long user_time = 0ULL, kernel_time = 0ULL, idle_time = 0ULL;
+ unsigned long pages_in = 0UL, pages_out = 0UL, interrupt_count = 0UL,
+ context_switches = 0UL, swap_in = 0UL, swap_out = 0UL;
+ time_t boot_time = 0;
+
+ if (wincap.is_winnt ())
+ {
+ NTSTATUS ret;
+ SYSTEM_PROCESSOR_TIMES spt;
+ SYSTEM_PERFORMANCE_INFORMATION spi;
+ SYSTEM_TIME_OF_DAY_INFORMATION stodi;
+ ret = NtQuerySystemInformation (SystemProcessorTimes,
+ (PVOID) &spt,
+ sizeof spt, NULL);
+ if (ret == STATUS_SUCCESS)
+ ret = NtQuerySystemInformation (SystemPerformanceInformation,
+ (PVOID) &spi,
+ sizeof spi, NULL);
+ if (ret == STATUS_SUCCESS)
+ ret = NtQuerySystemInformation (SystemTimeOfDayInformation,
+ (PVOID) &stodi,
+ sizeof stodi, NULL);
+ if (ret != STATUS_SUCCESS)
+ {
+ __seterrno_from_win_error (RtlNtStatusToDosError (ret));
+ debug_printf("NtQuerySystemInformation: ret = %d, "
+ "Dos(ret) = %d",
+ ret, RtlNtStatusToDosError (ret));
+ return 0;
+ }
+ kernel_time = (spt.KernelTime.QuadPart + spt.InterruptTime.QuadPart + spt.DpcTime.QuadPart) / 100000ULL;
+ user_time = spt.UserTime.QuadPart / 100000ULL;
+ idle_time = spt.IdleTime.QuadPart / 100000ULL;
+ interrupt_count = spt.InterruptCount;
+ pages_in = spi.PagesRead;
+ pages_out = spi.PagefilePagesWritten + spi.MappedFilePagesWritten;
+ /*
+ * Note: there is no distinction made in this structure between pages
+ * read from the page file and pages read from mapped files, but there
+ * is such a distinction made when it comes to writing. Goodness knows
+ * why. The value of swap_in, then, will obviously be wrong but its our
+ * best guess.
+ */
+ swap_in = spi.PagesRead;
+ swap_out = spi.PagefilePagesWritten;
+ context_switches = spi.ContextSwitches;
+ boot_time = to_time_t ((FILETIME *) &stodi.BootTime.QuadPart);
+ }
+ /*
+ * else
+ * {
+ * There are only two relevant performance counters on Windows 95/98/me,
+ * VMM/cPageIns and VMM/cPageOuts. The extra effort needed to read these
+ * counters is by no means worth it.
+ * }
+ */
+ return __small_sprintf (destbuf, "cpu %U %U %U %U\n"
+ "page %u %u\n"
+ "swap %u %u\n"
+ "intr %u\n"
+ "ctxt %u\n"
+ "btime %u\n",
+ user_time, 0ULL,
+ kernel_time, idle_time,
+ pages_in, pages_out,
+ swap_in, swap_out,
+ interrupt_count,
+ context_switches,
+ boot_time);
+}
diff --git a/winsup/cygwin/fhandler_process.cc b/winsup/cygwin/fhandler_process.cc
new file mode 100644
index 000000000..86393db05
--- /dev/null
+++ b/winsup/cygwin/fhandler_process.cc
@@ -0,0 +1,736 @@
+/* fhandler_process.cc: fhandler for /proc/<pid> virtual filesystem
+
+ Copyright 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/cygwin.h>
+#include <ntdef.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "fhandler.h"
+#include "pinfo.h"
+#include "path.h"
+#include "shared_info.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include "ntdll.h"
+#include <assert.h>
+
+#define _COMPILING_NEWLIB
+#include <dirent.h>
+
+static const int PROCESS_PPID = 2;
+static const int PROCESS_EXENAME = 3;
+static const int PROCESS_WINPID = 4;
+static const int PROCESS_WINEXENAME = 5;
+static const int PROCESS_STATUS = 6;
+static const int PROCESS_UID = 7;
+static const int PROCESS_GID = 8;
+static const int PROCESS_PGID = 9;
+static const int PROCESS_SID = 10;
+static const int PROCESS_CTTY = 11;
+static const int PROCESS_STAT = 12;
+static const int PROCESS_STATM = 13;
+
+static const char *process_listing[] = {
+ ".",
+ "..",
+ "ppid",
+ "exename",
+ "winpid",
+ "winexename",
+ "status",
+ "uid",
+ "gid",
+ "pgid",
+ "sid",
+ "ctty",
+ "stat",
+ "statm",
+ NULL
+};
+
+static const int PROCESS_LINK_COUNT = (sizeof(process_listing) / sizeof(const char *)) - 1;
+
+static off_t format_process_stat (_pinfo *p, char *destbuf, size_t maxsize);
+static off_t format_process_status (_pinfo *p, char *destbuf, size_t maxsize);
+static off_t format_process_statm (_pinfo *p, char *destbuf, size_t maxsize);
+static int get_process_state (DWORD dwProcessId);
+static bool get_mem_values(DWORD dwProcessId, unsigned long *vmsize, unsigned long *vmrss, unsigned long *vmtext,
+ unsigned long *vmdata, unsigned long *vmlib, unsigned long *vmshare);
+
+/* Returns 0 if path doesn't exist, >0 if path is a directory,
+ * <0 if path is a file.
+ */
+int
+fhandler_process::exists ()
+{
+ const char *path = get_name ();
+ debug_printf ("exists (%s)", path);
+ path += proc_len + 1;
+ while (*path != 0 && !SLASH_P (*path))
+ path++;
+ if (*path == 0)
+ return 2;
+
+ for (int i = 0; process_listing[i]; i++)
+ if (pathmatch (path + 1, process_listing[i]))
+ return -1;
+ return 0;
+}
+
+fhandler_process::fhandler_process ():
+ fhandler_proc (FH_PROCESS)
+{
+}
+
+int
+fhandler_process::fstat (struct __stat64 *buf, path_conv *pc)
+{
+ const char *path = get_name ();
+ int file_type = exists ();
+ (void) fhandler_base::fstat (buf, pc);
+ path += proc_len + 1;
+ int pid = atoi (path);
+ winpids pids;
+ pinfo p (pid);
+ if (!p)
+ {
+ set_errno(ENOENT);
+ return -1;
+ }
+
+ buf->st_mode &= ~_IFMT & NO_W;
+
+ switch (file_type)
+ {
+ case 0:
+ set_errno (ENOENT);
+ return -1;
+ case 1:
+ buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+ return 0;
+ case 2:
+ buf->st_ctime = buf->st_mtime = p->start_time;
+ buf->st_ctim.tv_nsec = buf->st_mtim.tv_nsec = 0;
+ time_as_timestruc_t(&buf->st_atim);
+ buf->st_uid = p->uid;
+ buf->st_gid = p->gid;
+ buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+ buf->st_nlink = PROCESS_LINK_COUNT;
+ return 0;
+ default:
+ case -1:
+ buf->st_uid = p->uid;
+ buf->st_gid = p->gid;
+ buf->st_mode |= S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
+ return 0;
+ }
+}
+
+struct dirent *
+fhandler_process::readdir (DIR * dir)
+{
+ if (dir->__d_position >= PROCESS_LINK_COUNT)
+ {
+ set_errno (ENMFILE);
+ return NULL;
+ }
+ strcpy (dir->__d_dirent->d_name, process_listing[dir->__d_position++]);
+ syscall_printf ("%p = readdir (%p) (%s)", &dir->__d_dirent, dir,
+ dir->__d_dirent->d_name);
+ return dir->__d_dirent;
+}
+
+int
+fhandler_process::open (path_conv *pc, int flags, mode_t mode)
+{
+ int process_file_no = -1, pid;
+ winpids pids;
+
+ int res = fhandler_virtual::open (pc, flags, mode);
+ if (!res)
+ goto out;
+
+ const char *path;
+ path = get_name () + proc_len + 1;
+ pid = atoi (path);
+ while (*path != 0 && !SLASH_P (*path))
+ path++;
+
+ if (*path == 0)
+ {
+ if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+ {
+ set_errno (EEXIST);
+ res = 0;
+ goto out;
+ }
+ else if (flags & O_WRONLY)
+ {
+ set_errno (EISDIR);
+ res = 0;
+ goto out;
+ }
+ else
+ {
+ flags |= O_DIROPEN;
+ goto success;
+ }
+ }
+
+ process_file_no = -1;
+ for (int i = 0; process_listing[i]; i++)
+ {
+ if (path_prefix_p
+ (process_listing[i], path + 1, strlen (process_listing[i])))
+ process_file_no = i;
+ }
+ if (process_file_no == -1)
+ {
+ if (flags & O_CREAT)
+ {
+ set_errno (EROFS);
+ res = 0;
+ goto out;
+ }
+ else
+ {
+ set_errno (ENOENT);
+ res = 0;
+ goto out;
+ }
+ }
+ if (flags & O_WRONLY)
+ {
+ set_errno (EROFS);
+ res = 0;
+ goto out;
+ }
+
+ {
+ pinfo p (pid);
+ if (!p)
+ {
+ set_errno (ENOENT);
+ res = 0;
+ goto out;
+ }
+
+ fileid = process_file_no;
+ fill_filebuf (p);
+
+ if (flags & O_APPEND)
+ position = filesize;
+ else
+ position = 0;
+ }
+
+success:
+ res = 1;
+ set_flags (flags & ~O_TEXT, O_BINARY);
+ set_open_status ();
+out:
+ syscall_printf ("%d = fhandler_proc::open (%p, %d)", res, flags, mode);
+ return res;
+}
+
+void
+fhandler_process::fill_filebuf (pinfo& p)
+{
+ switch (fileid)
+ {
+ case PROCESS_UID:
+ case PROCESS_GID:
+ case PROCESS_PGID:
+ case PROCESS_SID:
+ case PROCESS_CTTY:
+ case PROCESS_PPID:
+ {
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 40);
+ int num;
+ switch (fileid)
+ {
+ case PROCESS_PPID:
+ num = p->ppid;
+ break;
+ case PROCESS_UID:
+ num = p->uid;
+ break;
+ case PROCESS_PGID:
+ num = p->pgid;
+ break;
+ case PROCESS_SID:
+ num = p->sid;
+ break;
+ case PROCESS_GID:
+ num = p->gid;
+ break;
+ case PROCESS_CTTY:
+ num = p->ctty;
+ break;
+ default: // what's this here for?
+ num = 0;
+ break;
+ }
+ __small_sprintf (filebuf, "%d\n", num);
+ filesize = strlen (filebuf);
+ break;
+ }
+ case PROCESS_EXENAME:
+ {
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = MAX_PATH);
+ if (p->process_state & (PID_ZOMBIE | PID_EXITED))
+ strcpy (filebuf, "<defunct>");
+ else
+ {
+ mount_table->conv_to_posix_path (p->progname, filebuf, 1);
+ int len = strlen (filebuf);
+ if (len > 4)
+ {
+ char *s = filebuf + len - 4;
+ if (strcasecmp (s, ".exe") == 0)
+ *s = 0;
+ }
+ }
+ filesize = strlen (filebuf);
+ break;
+ }
+ case PROCESS_WINPID:
+ {
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 40);
+ __small_sprintf (filebuf, "%d\n", p->dwProcessId);
+ filesize = strlen (filebuf);
+ break;
+ }
+ case PROCESS_WINEXENAME:
+ {
+ int len = strlen (p->progname);
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = (len + 2));
+ strcpy (filebuf, p->progname);
+ filebuf[len] = '\n';
+ filesize = len + 1;
+ break;
+ }
+ case PROCESS_STATUS:
+ {
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 2048);
+ filesize = format_process_status (p, filebuf, bufalloc);
+ break;
+ }
+ case PROCESS_STAT:
+ {
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 2048);
+ filesize = format_process_stat (p, filebuf, bufalloc);
+ break;
+ }
+ case PROCESS_STATM:
+ {
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 2048);
+ filesize = format_process_statm (p, filebuf, bufalloc);
+ break;
+ }
+ }
+}
+
+static
+off_t
+format_process_stat (_pinfo *p, char *destbuf, size_t maxsize)
+{
+ char cmd[MAX_PATH];
+ int state = 'R';
+ unsigned long fault_count = 0UL,
+ utime = 0UL, stime = 0UL,
+ start_time = 0UL,
+ vmsize = 0UL, vmrss = 0UL, vmmaxrss = 0UL;
+ int priority = 0;
+ if (p->process_state & (PID_ZOMBIE | PID_EXITED))
+ strcpy (cmd, "<defunct");
+ else
+ {
+ strcpy(cmd, p->progname);
+ char *last_slash = strrchr (cmd, '\\');
+ if (last_slash != NULL)
+ strcpy (cmd, last_slash + 1);
+ int len = strlen (cmd);
+ if (len > 4)
+ {
+ char *s = cmd + len - 4;
+ if (strcasecmp (s, ".exe") == 0)
+ *s = 0;
+ }
+ }
+ /*
+ * Note: under Windows, a _process_ is always running - it's only _threads_
+ * that get suspended. Therefore the default state is R (runnable).
+ */
+ if (p->process_state & PID_ZOMBIE)
+ state = 'Z';
+ else if (p->process_state & PID_STOPPED)
+ state = 'T';
+ else if (wincap.is_winnt ())
+ state = get_process_state (p->dwProcessId);
+ if (wincap.is_winnt ())
+ {
+ NTSTATUS ret;
+ HANDLE hProcess;
+ VM_COUNTERS vmc;
+ KERNEL_USER_TIMES put;
+ PROCESS_BASIC_INFORMATION pbi;
+ QUOTA_LIMITS ql;
+ SYSTEM_TIME_OF_DAY_INFORMATION stodi;
+ SYSTEM_PROCESSOR_TIMES spt;
+ hProcess = OpenProcess (PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
+ FALSE, p->dwProcessId);
+ if (hProcess != NULL)
+ {
+ ret = NtQueryInformationProcess (hProcess,
+ ProcessVmCounters,
+ (PVOID) &vmc,
+ sizeof vmc, NULL);
+ if (ret == STATUS_SUCCESS)
+ ret = NtQueryInformationProcess (hProcess,
+ ProcessTimes,
+ (PVOID) &put,
+ sizeof put, NULL);
+ if (ret == STATUS_SUCCESS)
+ ret = NtQueryInformationProcess (hProcess,
+ ProcessBasicInformation,
+ (PVOID) &pbi,
+ sizeof pbi, NULL);
+ if (ret == STATUS_SUCCESS)
+ ret = NtQueryInformationProcess (hProcess,
+ ProcessQuotaLimits,
+ (PVOID) &ql,
+ sizeof ql, NULL);
+ CloseHandle (hProcess);
+ }
+ else
+ {
+ DWORD error = GetLastError ();
+ __seterrno_from_win_error (error);
+ debug_printf("OpenProcess: ret = %d",
+ error);
+ return 0;
+ }
+ if (ret == STATUS_SUCCESS)
+ ret = NtQuerySystemInformation (SystemTimeOfDayInformation,
+ (PVOID) &stodi,
+ sizeof stodi, NULL);
+ if (ret == STATUS_SUCCESS)
+ ret = NtQuerySystemInformation (SystemProcessorTimes,
+ (PVOID) &spt,
+ sizeof spt, NULL);
+ if (ret != STATUS_SUCCESS)
+ {
+ __seterrno_from_win_error (RtlNtStatusToDosError (ret));
+ debug_printf("NtQueryInformationProcess: ret = %d, "
+ "Dos(ret) = %d",
+ ret, RtlNtStatusToDosError (ret));
+ return 0;
+ }
+ fault_count = vmc.PageFaultCount;
+ utime = put.UserTime.QuadPart / 100000ULL;
+ stime = put.KernelTime.QuadPart / 100000ULL;
+ if (stodi.CurrentTime.QuadPart > put.CreateTime.QuadPart)
+ start_time = (spt.InterruptTime.QuadPart + spt.KernelTime.QuadPart +
+ spt.IdleTime.QuadPart + spt.UserTime.QuadPart +
+ spt.DpcTime.QuadPart - stodi.CurrentTime.QuadPart +
+ put.CreateTime.QuadPart) / 100000ULL;
+ else
+ /*
+ * sometimes stodi.CurrentTime is a bit behind
+ * Note: some older versions of procps are broken and can't cope
+ * with process start times > time(NULL).
+ */
+ start_time = (spt.InterruptTime.QuadPart + spt.KernelTime.QuadPart +
+ spt.IdleTime.QuadPart + spt.UserTime.QuadPart +
+ spt.DpcTime.QuadPart) / 100000ULL;
+ priority = pbi.BasePriority;
+ unsigned page_size = getpagesize();
+ vmsize = vmc.VirtualSize;
+ vmrss = vmc.WorkingSetSize / page_size;
+ vmmaxrss = ql.MaximumWorkingSetSize / page_size;
+ }
+ else
+ {
+ start_time = (GetTickCount() / 1000 - time(NULL) + p->start_time) * 100;
+ }
+ return __small_sprintf (destbuf, "%d (%s) %c "
+ "%d %d %d %d %d "
+ "%lu %lu %lu %lu %lu %lu %lu "
+ "%ld %ld %ld %ld %ld %ld "
+ "%lu %lu "
+ "%ld "
+ "%lu",
+ p->pid, cmd,
+ state,
+ p->ppid, p->pgid, p->sid, p->ctty, -1,
+ 0, fault_count, fault_count, 0, 0, utime, stime,
+ utime, stime, priority, 0, 0, 0,
+ start_time, vmsize,
+ vmrss, vmmaxrss
+ );
+}
+
+static
+off_t
+format_process_status (_pinfo *p, char *destbuf, size_t maxsize)
+{
+ char cmd[MAX_PATH];
+ int state = 'R';
+ const char *state_str = "unknown";
+ unsigned long vmsize = 0UL, vmrss = 0UL, vmdata = 0UL, vmlib = 0UL, vmtext = 0UL,
+ vmshare = 0UL;
+ if (p->process_state & (PID_ZOMBIE | PID_EXITED))
+ strcpy (cmd, "<defunct>");
+ else
+ {
+ strcpy(cmd, p->progname);
+ char *last_slash = strrchr (cmd, '\\');
+ if (last_slash != NULL)
+ strcpy (cmd, last_slash + 1);
+ int len = strlen (cmd);
+ if (len > 4)
+ {
+ char *s = cmd + len - 4;
+ if (strcasecmp (s, ".exe") == 0)
+ *s = 0;
+ }
+ }
+ /*
+ * Note: under Windows, a _process_ is always running - it's only _threads_
+ * that get suspended. Therefore the default state is R (runnable).
+ */
+ if (p->process_state & PID_ZOMBIE)
+ state = 'Z';
+ else if (p->process_state & PID_STOPPED)
+ state = 'T';
+ else if (wincap.is_winnt ())
+ state = get_process_state (p->dwProcessId);
+ switch (state)
+ {
+ case 'O':
+ state_str = "running";
+ break;
+ case 'D':
+ case 'S':
+ state_str = "sleeping";
+ break;
+ case 'R':
+ state_str = "runnable";
+ break;
+ case 'Z':
+ state_str = "zombie";
+ break;
+ case 'T':
+ state_str = "stopped";
+ break;
+ }
+ if (wincap.is_winnt ())
+ {
+ if (!get_mem_values (p->dwProcessId, &vmsize, &vmrss, &vmtext, &vmdata, &vmlib, &vmshare))
+ return 0;
+ unsigned page_size = getpagesize();
+ vmsize *= page_size; vmrss *= page_size; vmdata *= page_size;
+ vmtext *= page_size; vmlib *= page_size;
+ }
+ return __small_sprintf (destbuf, "Name: %s\n"
+ "State: %c (%s)\n"
+ "Tgid: %d\n"
+ "Pid: %d\n"
+ "PPid: %d\n"
+ "Uid: %d %d %d %d\n"
+ "Gid: %d %d %d %d\n"
+ "VmSize: %8d kB\n"
+ "VmLck: %8d kB\n"
+ "VmRSS: %8d kB\n"
+ "VmData: %8d kB\n"
+ "VmStk: %8d kB\n"
+ "VmExe: %8d kB\n"
+ "VmLib: %8d kB\n"
+ "SigPnd: %016x\n"
+ "SigBlk: %016x\n"
+ "SigIgn: %016x\n",
+ cmd,
+ state, state_str,
+ p->pgid,
+ p->pid,
+ p->ppid,
+ p->uid, cygheap->user.real_uid, cygheap->user.real_uid, p->uid,
+ p->gid, cygheap->user.real_gid, cygheap->user.real_gid, p->gid,
+ vmsize >> 10, 0, vmrss >> 10, vmdata >> 10, 0, vmtext >> 10, vmlib >> 10,
+ 0, 0, p->getsigmask ()
+ );
+}
+
+static
+off_t
+format_process_statm (_pinfo *p, char *destbuf, size_t maxsize)
+{
+ unsigned long vmsize = 0UL, vmrss = 0UL, vmtext = 0UL, vmdata = 0UL, vmlib = 0UL,
+ vmshare = 0UL;
+ if (wincap.is_winnt ())
+ {
+ if (!get_mem_values (p->dwProcessId, &vmsize, &vmrss, &vmtext, &vmdata, &vmlib, &vmshare))
+ return 0;
+ }
+ return __small_sprintf (destbuf, "%ld %ld %ld %ld %ld %ld %ld",
+ vmsize, vmrss, vmshare, vmtext, vmlib, vmdata, 0
+ );
+}
+
+static
+int
+get_process_state (DWORD dwProcessId)
+{
+ /*
+ * This isn't really heavy magic - just go through the processes'
+ * threads one by one and return a value accordingly
+ * Errors are silently ignored.
+ */
+ NTSTATUS ret;
+ SYSTEM_PROCESSES *sp;
+ ULONG n = 0x1000;
+ PULONG p = new ULONG[n];
+ int state =' ';
+ while (STATUS_INFO_LENGTH_MISMATCH ==
+ (ret = NtQuerySystemInformation (SystemProcessesAndThreadsInformation,
+ (PVOID) p,
+ n * sizeof *p, NULL)))
+ delete [] p, p = new ULONG[n *= 2];
+ if (ret != STATUS_SUCCESS)
+ {
+ debug_printf("NtQuerySystemInformation: ret = %d, "
+ "Dos(ret) = %d",
+ ret, RtlNtStatusToDosError (ret));
+ goto out;
+ }
+ state = 'Z';
+ sp = (SYSTEM_PROCESSES *) p;
+ for (;;)
+ {
+ if (sp->ProcessId == dwProcessId)
+ {
+ SYSTEM_THREADS *st;
+ if (wincap.has_process_io_counters ())
+ /*
+ * Windows 2000 and XP have an extra member in SYSTEM_PROCESSES
+ * which means the offset of the first SYSTEM_THREADS entry is
+ * different on these operating systems compared to NT 4.
+ */
+ st = &sp->Threads[0];
+ else
+ /*
+ * 136 is the offset of the first SYSTEM_THREADS entry on
+ * Windows NT 4.
+ */
+ st = (SYSTEM_THREADS *) ((char *) sp + 136);
+ state = 'S';
+ for (unsigned i = 0; i < sp->ThreadCount; i++)
+ {
+ if (st->State == StateRunning ||
+ st->State == StateReady)
+ {
+ state = 'R';
+ goto out;
+ }
+ st++;
+ }
+ break;
+ }
+ if (!sp->NextEntryDelta)
+ break;
+ sp = (SYSTEM_PROCESSES *) ((char *) sp + sp->NextEntryDelta);
+ }
+out:
+ delete [] p;
+ return state;
+}
+
+static
+bool
+get_mem_values(DWORD dwProcessId, unsigned long *vmsize, unsigned long *vmrss, unsigned long *vmtext,
+ unsigned long *vmdata, unsigned long *vmlib, unsigned long *vmshare)
+{
+ bool res = true;
+ NTSTATUS ret;
+ HANDLE hProcess;
+ VM_COUNTERS vmc;
+ MEMORY_WORKING_SET_LIST *mwsl;
+ ULONG n = 0x1000, length;
+ PULONG p = new ULONG[n];
+ unsigned page_size = getpagesize();
+ hProcess = OpenProcess (PROCESS_QUERY_INFORMATION,
+ FALSE, dwProcessId);
+ if (hProcess == NULL)
+ {
+ DWORD error = GetLastError();
+ __seterrno_from_win_error (error);
+ debug_printf("OpenProcess: ret = %d",
+ error);
+ return false;
+ }
+ while ((ret = NtQueryVirtualMemory (hProcess, 0,
+ MemoryWorkingSetList,
+ (PVOID) p,
+ n * sizeof *p, &length)),
+ (ret == STATUS_SUCCESS || ret == STATUS_INFO_LENGTH_MISMATCH) &&
+ length >= n * sizeof *p)
+ delete [] p, p = new ULONG[n *= 2];
+ if (ret != STATUS_SUCCESS)
+ {
+ debug_printf("NtQueryVirtualMemory: ret = %d, "
+ "Dos(ret) = %d",
+ ret, RtlNtStatusToDosError (ret));
+ res = false;
+ goto out;
+ }
+ mwsl = (MEMORY_WORKING_SET_LIST *) p;
+ for (unsigned long i = 0; i < mwsl->NumberOfPages; i++)
+ {
+ ++*vmrss;
+ unsigned flags = mwsl->WorkingSetList[i] & 0x0FFF;
+ if (flags & (WSLE_PAGE_EXECUTE | WSLE_PAGE_SHAREABLE) == (WSLE_PAGE_EXECUTE | WSLE_PAGE_SHAREABLE))
+ ++*vmlib;
+ else if (flags & WSLE_PAGE_SHAREABLE)
+ ++*vmshare;
+ else if (flags & WSLE_PAGE_EXECUTE)
+ ++*vmtext;
+ else
+ ++*vmdata;
+ }
+ ret = NtQueryInformationProcess (hProcess,
+ ProcessVmCounters,
+ (PVOID) &vmc,
+ sizeof vmc, NULL);
+ if (ret != STATUS_SUCCESS)
+ {
+ debug_printf("NtQueryInformationProcess: ret = %d, "
+ "Dos(ret) = %d",
+ ret, RtlNtStatusToDosError (ret));
+ res = false;
+ goto out;
+ }
+ *vmsize = vmc.VirtualSize / page_size;
+out:
+ delete [] p;
+ CloseHandle (hProcess);
+ return res;
+}
diff --git a/winsup/cygwin/fhandler_registry.cc b/winsup/cygwin/fhandler_registry.cc
new file mode 100644
index 000000000..94220c62a
--- /dev/null
+++ b/winsup/cygwin/fhandler_registry.cc
@@ -0,0 +1,544 @@
+/* fhandler_registry.cc: fhandler for /proc/registry virtual filesystem
+
+ Copyright 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+/* FIXME: Access permissions are ignored at the moment. */
+
+#include "winsup.h"
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/cygwin.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "fhandler.h"
+#include "path.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include <assert.h>
+
+#define _COMPILING_NEWLIB
+#include <dirent.h>
+
+static const int registry_len = sizeof ("registry") - 1;
+/* If this bit is set in __d_position then we are enumerating values,
+ * else sub-keys. keeping track of where we are is horribly messy
+ * the bottom 16 bits are the absolute position and the top 15 bits
+ * make up the value index if we are enuerating values.
+ */
+static const __off32_t REG_ENUM_VALUES_MASK = 0x8000000;
+static const __off32_t REG_POSITION_MASK = 0xffff;
+
+/* List of root keys in /proc/registry.
+ * Possibly we should filter out those not relevant to the flavour of Windows
+ * Cygwin is running on.
+ */
+static const char *registry_listing[] =
+{
+ ".",
+ "..",
+ "HKEY_CLASSES_ROOT",
+ "HKEY_CURRENT_CONFIG",
+ "HKEY_CURRENT_USER",
+ "HKEY_LOCAL_MACHINE",
+ "HKEY_USERS",
+ "HKEY_DYN_DATA", // 95/98/Me
+ "HKEY_PERFOMANCE_DATA", // NT/2000/XP
+ NULL
+};
+
+static const HKEY registry_keys[] =
+{
+ (HKEY) INVALID_HANDLE_VALUE,
+ (HKEY) INVALID_HANDLE_VALUE,
+ HKEY_CLASSES_ROOT,
+ HKEY_CURRENT_CONFIG,
+ HKEY_CURRENT_USER,
+ HKEY_LOCAL_MACHINE,
+ HKEY_USERS,
+ HKEY_DYN_DATA,
+ HKEY_PERFORMANCE_DATA
+};
+
+static const int ROOT_KEY_COUNT = sizeof(registry_keys) / sizeof(HKEY);
+
+/* These get added to each subdirectory in /proc/registry.
+ * If we wanted to implement writing, we could maybe add a '.writable' entry or
+ * suchlike.
+ */
+static const char *special_dot_files[] =
+{
+ ".",
+ "..",
+ NULL
+};
+
+static const int SPECIAL_DOT_FILE_COUNT = (sizeof(special_dot_files) / sizeof(const char *)) - 1;
+
+/* Name given to default values */
+static const char *DEFAULT_VALUE_NAME = "@";
+
+/* Returns 0 if path doesn't exist, >0 if path is a directory,
+ * <0 if path is a file.
+ *
+ * We open the last key but one and then enum it's sub-keys and values to see if the
+ * final component is there. This gets round the problem of not having security access
+ * to the final key in the path.
+ */
+int
+fhandler_registry::exists ()
+{
+ int file_type = 0, index = 0, pathlen;
+ DWORD buf_size = MAX_PATH;
+ LONG error;
+ char buf[buf_size];
+ const char *file;
+ HKEY hKey = (HKEY) INVALID_HANDLE_VALUE;
+
+ const char *path = get_name ();
+ debug_printf ("exists (%s)", path);
+ path += proc_len + 1 + registry_len;
+
+ while (SLASH_P (*path))
+ path++;
+ if (*path == 0)
+ {
+ file_type = 2;
+ goto out;
+ }
+ pathlen = strlen (path);
+ file = path + pathlen - 1;
+ if (SLASH_P (*file) && pathlen > 1)
+ file--;
+ while (!SLASH_P (*file))
+ file--;
+ file++;
+
+ if (file == path)
+ {
+ for (int i = 0; registry_listing[i]; i++)
+ if (path_prefix_p
+ (registry_listing[i], path, strlen (registry_listing[i])))
+ {
+ file_type = 1;
+ goto out;
+ }
+ goto out;
+ }
+
+ hKey = open_key (path, KEY_READ, true);
+ if (hKey == (HKEY) INVALID_HANDLE_VALUE)
+ return 0;
+
+ while (ERROR_SUCCESS ==
+ (error = RegEnumKeyEx (hKey, index++, buf, &buf_size, NULL, NULL,
+ NULL, NULL)) || (error == ERROR_MORE_DATA))
+ {
+ if (pathmatch (buf, file))
+ {
+ file_type = 1;
+ goto out;
+ }
+ buf_size = MAX_PATH;
+ }
+ if (error != ERROR_NO_MORE_ITEMS)
+ {
+ seterrno_from_win_error (__FILE__, __LINE__, error);
+ goto out;
+ }
+ index = 0;
+ buf_size = MAX_PATH;
+ while (ERROR_SUCCESS ==
+ (error = RegEnumValue (hKey, index++, buf, &buf_size, NULL, NULL,
+ NULL, NULL)) || (error == ERROR_MORE_DATA))
+ {
+ if (pathmatch (buf, file) || (buf[0] == '\0' &&
+ pathmatch (file, DEFAULT_VALUE_NAME)))
+ {
+ file_type = -1;
+ goto out;
+ }
+ buf_size = MAX_PATH;
+ }
+ if (error != ERROR_NO_MORE_ITEMS)
+ {
+ seterrno_from_win_error (__FILE__, __LINE__, error);
+ goto out;
+ }
+out:
+ if (hKey != (HKEY) INVALID_HANDLE_VALUE)
+ RegCloseKey (hKey);
+ return file_type;
+}
+
+fhandler_registry::fhandler_registry ():
+ fhandler_proc (FH_REGISTRY)
+{
+}
+
+int
+fhandler_registry::fstat (struct __stat64 *buf, path_conv *pc)
+{
+ this->fhandler_base::fstat (buf, pc);
+ buf->st_mode &= ~_IFMT & NO_W;
+ int file_type = exists ();
+ switch (file_type)
+ {
+ case 0:
+ set_errno (ENOENT);
+ return -1;
+ case 1:
+ buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+ break;
+ case 2:
+ buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+ buf->st_nlink = ROOT_KEY_COUNT;
+ break;
+ default:
+ case -1:
+ buf->st_mode |= S_IFREG;
+ buf->st_mode &= NO_X;
+ break;
+ }
+ return 0;
+}
+
+struct dirent *
+fhandler_registry::readdir (DIR * dir)
+{
+ DWORD buf_size = MAX_PATH;
+ char buf[buf_size];
+ HANDLE handle;
+ struct dirent *res = NULL;
+ const char *path = dir->__d_dirname + proc_len + 1 + registry_len;
+ LONG error;
+
+ if (*path == 0)
+ {
+ if (dir->__d_position >= ROOT_KEY_COUNT)
+ goto out;
+ strcpy (dir->__d_dirent->d_name, registry_listing[dir->__d_position++]);
+ res = dir->__d_dirent;
+ goto out;
+ }
+ if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE
+ && dir->__d_position == 0)
+ {
+ handle = open_key (path + 1);
+ dir->__d_u.__d_data.__handle = handle;;
+ }
+ if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE)
+ goto out;
+ if (dir->__d_position < SPECIAL_DOT_FILE_COUNT)
+ {
+ strcpy (dir->__d_dirent->d_name, special_dot_files[dir->__d_position++]);
+ res = dir->__d_dirent;
+ goto out;
+ }
+retry:
+ if (dir->__d_position & REG_ENUM_VALUES_MASK)
+ /* For the moment, the type of key is ignored here. when write access is added,
+ * maybe add an extension for the type of each value?
+ */
+ error = RegEnumValue ((HKEY) dir->__d_u.__d_data.__handle,
+ (dir->__d_position & ~REG_ENUM_VALUES_MASK) >> 16,
+ buf, &buf_size, NULL, NULL, NULL, NULL);
+ else
+ error =
+ RegEnumKeyEx ((HKEY) dir->__d_u.__d_data.__handle, dir->__d_position -
+ SPECIAL_DOT_FILE_COUNT, buf, &buf_size, NULL, NULL, NULL, NULL);
+ if (error == ERROR_NO_MORE_ITEMS
+ && (dir->__d_position & REG_ENUM_VALUES_MASK) == 0)
+ {
+ /* If we're finished with sub-keys, start on values under this key. */
+ dir->__d_position |= REG_ENUM_VALUES_MASK;
+ buf_size = MAX_PATH;
+ goto retry;
+ }
+ if (error != ERROR_SUCCESS && error != ERROR_MORE_DATA)
+ {
+ RegCloseKey ((HKEY) dir->__d_u.__d_data.__handle);
+ dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE;
+ seterrno_from_win_error (__FILE__, __LINE__, error);
+ goto out;
+ }
+
+ /* We get here if `buf' contains valid data. */
+ if (*buf == 0)
+ strcpy (dir->__d_dirent->d_name, DEFAULT_VALUE_NAME);
+ else
+ strcpy (dir->__d_dirent->d_name, buf);
+
+ dir->__d_position++;
+ if (dir->__d_position & REG_ENUM_VALUES_MASK)
+ dir->__d_position += 0x10000;
+ res = dir->__d_dirent;
+out:
+ syscall_printf ("%p = readdir (%p) (%s)", &dir->__d_dirent, dir, buf);
+ return res;
+}
+
+__off64_t
+fhandler_registry::telldir (DIR * dir)
+{
+ return dir->__d_position & REG_POSITION_MASK;
+}
+
+void
+fhandler_registry::seekdir (DIR * dir, __off64_t loc)
+{
+ /* Unfortunately cannot simply set __d_position due to transition from sub-keys to
+ * values.
+ */
+ rewinddir (dir);
+ while (loc > (dir->__d_position & REG_POSITION_MASK))
+ if (!readdir (dir))
+ break;
+}
+
+void
+fhandler_registry::rewinddir (DIR * dir)
+{
+ if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE)
+ {
+ (void) RegCloseKey ((HKEY) dir->__d_u.__d_data.__handle);
+ dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE;
+ }
+ dir->__d_position = 0;
+ return;
+}
+
+int
+fhandler_registry::closedir (DIR * dir)
+{
+ int res = 0;
+ if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE &&
+ RegCloseKey ((HKEY) dir->__d_u.__d_data.__handle) != ERROR_SUCCESS)
+ {
+ __seterrno ();
+ res = -1;
+ }
+ syscall_printf ("%d = closedir (%p)", res, dir);
+ return 0;
+}
+
+int
+fhandler_registry::open (path_conv *pc, int flags, mode_t mode)
+{
+ DWORD type, size;
+ LONG error;
+ HKEY hKey = (HKEY) INVALID_HANDLE_VALUE;
+ int pathlen;
+ const char *file;
+
+ int res = fhandler_virtual::open (pc, flags, mode);
+ if (!res)
+ goto out;
+
+ const char *path;
+ path = get_name () + proc_len + 1 + registry_len;
+ if (!*path)
+ {
+ if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+ {
+ set_errno (EEXIST);
+ res = 0;
+ goto out;
+ }
+ else if (flags & O_WRONLY)
+ {
+ set_errno (EISDIR);
+ res = 0;
+ goto out;
+ }
+ else
+ {
+ flags |= O_DIROPEN;
+ goto success;
+ }
+ }
+ path++;
+ pathlen = strlen (path);
+ file = path + pathlen - 1;
+ if (SLASH_P (*file) && pathlen > 1)
+ file--;
+ while (!SLASH_P (*file))
+ file--;
+ file++;
+
+ if (file == path)
+ {
+ for (int i = 0; registry_listing[i]; i++)
+ if (path_prefix_p
+ (registry_listing[i], path, strlen (registry_listing[i])))
+ {
+ if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+ {
+ set_errno (EEXIST);
+ res = 0;
+ goto out;
+ }
+ else if (flags & O_WRONLY)
+ {
+ set_errno (EISDIR);
+ res = 0;
+ goto out;
+ }
+ else
+ {
+ flags |= O_DIROPEN;
+ goto success;
+ }
+ }
+
+ if (flags & O_CREAT)
+ {
+ set_errno (EROFS);
+ res = 0;
+ goto out;
+ }
+ else
+ {
+ set_errno (ENOENT);
+ res = 0;
+ goto out;
+ }
+ }
+
+ if (flags & O_WRONLY)
+ {
+ set_errno (EROFS);
+ res = 0;
+ goto out;
+ }
+
+ hKey = open_key (path, KEY_READ, true);
+ if (hKey == (HKEY) INVALID_HANDLE_VALUE)
+ {
+ res = 0;
+ goto out;
+ }
+ if (pathmatch (file, DEFAULT_VALUE_NAME))
+ file = "";
+
+ if (hKey != HKEY_PERFORMANCE_DATA)
+ {
+ error = RegQueryValueEx (hKey, file, NULL, &type, NULL, &size);
+ if (error != ERROR_SUCCESS)
+ {
+ seterrno_from_win_error (__FILE__, __LINE__, error);
+ res = -1;
+ goto out;
+ }
+ bufalloc = size;
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc);
+ error =
+ RegQueryValueEx (hKey, file, NULL, NULL, (BYTE *) filebuf, &size);
+ if (error != ERROR_SUCCESS)
+ {
+ seterrno_from_win_error (__FILE__, __LINE__, error);
+ res = 0;
+ goto out;
+ }
+ filesize = size;
+ }
+ else
+ {
+ bufalloc = 0;
+ do
+ {
+ bufalloc += 1000;
+ if (filebuf)
+ {
+ cfree (filebuf);
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc);
+ }
+ error =
+ RegQueryValueEx (hKey, file, NULL, &type, (BYTE *) filebuf,
+ &size);
+ if (error != ERROR_SUCCESS && res != ERROR_MORE_DATA)
+ {
+ seterrno_from_win_error (__FILE__, __LINE__, error);
+ res = 0;
+ goto out;
+ }
+ }
+ while (error == ERROR_MORE_DATA);
+ filesize = size;
+ }
+
+ if (flags & O_APPEND)
+ position = filesize;
+ else
+ position = 0;
+
+success:
+ res = 1;
+ set_flags (flags & ~O_TEXT, O_BINARY);
+ set_open_status ();
+out:
+ if (hKey != (HKEY) INVALID_HANDLE_VALUE)
+ RegCloseKey (hKey);
+ syscall_printf ("%d = fhandler_registry::open (%p, %d)", res, flags, mode);
+ return res;
+}
+
+void
+fhandler_registry::fill_filebuf ()
+{
+}
+
+/* Auxillary member function to open registry keys. */
+HKEY
+fhandler_registry::open_key (const char *name, REGSAM access, bool isValue)
+{
+ HKEY hKey = (HKEY) INVALID_HANDLE_VALUE;
+ HKEY hParentKey = (HKEY) INVALID_HANDLE_VALUE;
+ bool parentOpened = false;
+ char component[MAX_PATH];
+
+ while (*name)
+ {
+ const char *anchor = name;
+ while (*name && !SLASH_P (*name))
+ name++;
+ strncpy (component, anchor, name - anchor);
+ component[name - anchor] = '\0';
+ if (*name)
+ name++;
+ if (*name == 0 && isValue == true)
+ goto out;
+
+ if (hParentKey != (HKEY) INVALID_HANDLE_VALUE)
+ {
+ hKey = (HKEY) INVALID_HANDLE_VALUE;
+ LONG error = RegOpenKeyEx (hParentKey, component, 0, access, &hKey);
+ if (hKey == (HKEY) INVALID_HANDLE_VALUE)
+ {
+ seterrno_from_win_error (__FILE__, __LINE__, error);
+ return hKey;
+ }
+ if (parentOpened)
+ RegCloseKey (hParentKey);
+ hParentKey = hKey;
+ parentOpened = true;
+ }
+ else
+ {
+ for (int i = 0; registry_listing[i]; i++)
+ if (pathmatch (component, registry_listing[i]))
+ hKey = registry_keys[i];
+ if (hKey == (HKEY) INVALID_HANDLE_VALUE)
+ return hKey;
+ hParentKey = hKey;
+ }
+ }
+out:
+ return hKey;
+}
diff --git a/winsup/cygwin/fhandler_virtual.cc b/winsup/cygwin/fhandler_virtual.cc
new file mode 100644
index 000000000..a05543426
--- /dev/null
+++ b/winsup/cygwin/fhandler_virtual.cc
@@ -0,0 +1,226 @@
+/* fhandler_virtual.cc: base fhandler class for virtual filesystems
+
+ Copyright 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/cygwin.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "fhandler.h"
+#include "path.h"
+#include "dtable.h"
+#include "shared_info.h"
+#include "cygheap.h"
+#include <assert.h>
+
+#define _COMPILING_NEWLIB
+#include <dirent.h>
+
+fhandler_virtual::fhandler_virtual (DWORD devtype):
+ fhandler_base (devtype), filebuf (NULL), bufalloc ((size_t) -1),
+ fileid (-1)
+{
+}
+
+fhandler_virtual::~fhandler_virtual ()
+{
+ if (filebuf)
+ cfree (filebuf);
+ filebuf = NULL;
+}
+
+DIR *
+fhandler_virtual::opendir (path_conv& pc)
+{
+ DIR *dir;
+ DIR *res = NULL;
+ size_t len;
+
+ if (exists () <= 0)
+ set_errno (ENOTDIR);
+ else if ((len = strlen (get_name ())) > MAX_PATH - 3)
+ set_errno (ENAMETOOLONG);
+ else if ((dir = (DIR *) malloc (sizeof (DIR))) == NULL)
+ set_errno (ENOMEM);
+ else if ((dir->__d_dirname = (char *) malloc (len + 3)) == NULL)
+ {
+ free (dir);
+ set_errno (ENOMEM);
+ }
+ else if ((dir->__d_dirent =
+ (struct dirent *) malloc (sizeof (struct dirent))) == NULL)
+ {
+ free (dir);
+ set_errno (ENOMEM);
+ }
+ else
+ {
+ strcpy (dir->__d_dirname, get_name ());
+ dir->__d_dirent->d_version = __DIRENT_VERSION;
+ cygheap_fdnew fd;
+ fd = this;
+ fd->set_nohandle (true);
+ dir->__d_dirent->d_fd = fd;
+ dir->__d_u.__d_data.__fh = this;
+ dir->__d_cookie = __DIRENT_COOKIE;
+ dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE;
+ dir->__d_position = 0;
+ dir->__d_dirhash = get_namehash ();
+
+ res = dir;
+ }
+
+ syscall_printf ("%p = opendir (%s)", res, get_name ());
+ return res;
+}
+
+__off64_t fhandler_virtual::telldir (DIR * dir)
+{
+ return dir->__d_position;
+}
+
+void
+fhandler_virtual::seekdir (DIR * dir, __off64_t loc)
+{
+ dir->__d_position = loc;
+ return;
+}
+
+void
+fhandler_virtual::rewinddir (DIR * dir)
+{
+ dir->__d_position = 0;
+ return;
+}
+
+int
+fhandler_virtual::closedir (DIR * dir)
+{
+ return 0;
+}
+
+__off64_t
+fhandler_virtual::lseek (__off64_t offset, int whence)
+{
+ /*
+ * On Linux, when you lseek within a /proc file,
+ * the contents of the file are updated.
+ */
+ fill_filebuf ();
+ switch (whence)
+ {
+ case SEEK_SET:
+ position = offset;
+ break;
+ case SEEK_CUR:
+ position += offset;
+ break;
+ case SEEK_END:
+ position = filesize + offset;
+ break;
+ default:
+ set_errno (EINVAL);
+ return (__off64_t) -1;
+ }
+ return position;
+}
+
+int
+fhandler_virtual::dup (fhandler_base * child)
+{
+ int ret = fhandler_base::dup (child);
+
+ if (!ret)
+ {
+ fhandler_virtual *fhproc_child = (fhandler_virtual *) child;
+ fhproc_child->filebuf = (char *) cmalloc (HEAP_BUF, filesize);
+ fhproc_child->bufalloc = fhproc_child->filesize = filesize;
+ fhproc_child->position = position;
+ memcpy (fhproc_child->filebuf, filebuf, filesize);
+ fhproc_child->set_flags (get_flags ());
+ }
+ return ret;
+}
+
+int
+fhandler_virtual::close ()
+{
+ if (filebuf)
+ cfree (filebuf);
+ filebuf = NULL;
+ bufalloc = (size_t) -1;
+ cygwin_shared->delqueue.process_queue ();
+ return 0;
+}
+
+int
+fhandler_virtual::read (void *ptr, size_t len)
+{
+ if (len == 0)
+ return 0;
+ if (openflags & O_DIROPEN)
+ {
+ set_errno (EISDIR);
+ return -1;
+ }
+ if (!filebuf)
+ return 0;
+ int read = len;
+ if (read > filesize - position)
+ read = filesize - position;
+ if (read < 0)
+ read = 0;
+ else
+ memcpy (ptr, filebuf + position, read);
+ position += read;
+ return read;
+}
+
+int
+fhandler_virtual::write (const void *ptr, size_t len)
+{
+ set_errno (EACCES);
+ return -1;
+}
+
+/* low-level open for all proc files */
+int
+fhandler_virtual::open (path_conv *, int flags, mode_t mode)
+{
+ set_r_binary (1);
+ set_w_binary (1);
+
+ set_has_acls (false);
+ set_isremote (false);
+
+ /* what to do about symlinks? */
+ set_symlink_p (false);
+ set_execable_p (not_executable);
+ set_socket_p (false);
+
+ set_flags (flags & ~O_TEXT, O_BINARY);
+
+ set_nohandle (true);
+
+ return 1;
+}
+
+int
+fhandler_virtual::exists ()
+{
+ return 0;
+}
+
+void
+fhandler_virtual::fill_filebuf ()
+{
+}
diff --git a/winsup/cygwin/include/netinet/udp.h b/winsup/cygwin/include/netinet/udp.h
new file mode 100644
index 000000000..61932720b
--- /dev/null
+++ b/winsup/cygwin/include/netinet/udp.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)udp.h 8.1 (Berkeley) 6/10/93
+ * $FreeBSD: src/sys/netinet/udp.h,v 1.7 1999/08/28 00:49:34 peter Exp $
+ */
+
+#ifndef _NETINET_UDP_H
+#define _NETINET_UDP_H
+
+/*
+ * Udp protocol header.
+ * Per RFC 768, September, 1981.
+ */
+struct udphdr {
+ u_short uh_sport; /* source port */
+ u_short uh_dport; /* destination port */
+ u_short uh_ulen; /* udp length */
+ u_short uh_sum; /* udp checksum */
+};
+
+#endif
diff --git a/winsup/cygwin/stackdump.sgml b/winsup/cygwin/stackdump.sgml
new file mode 100644
index 000000000..bff76bffd
--- /dev/null
+++ b/winsup/cygwin/stackdump.sgml
@@ -0,0 +1,13 @@
+<sect1 id="func-cygwin-stackdump">
+<title>cygwin_stackdump</title>
+
+<funcsynopsis>
+<funcdef>extern "C" void
+<function>cygwin_stackdump</function></funcdef>
+<void>
+</funcsynopsis>
+
+<para> Outputs a stackdump to stderr from the called location.
+</para>
+
+</sect1>