From 5eea0254c7a10b31f9c9b3f6339ce454d1d0a27c Mon Sep 17 00:00:00 2001 From: cvs2svn <> Date: Thu, 6 Jun 2002 15:35:10 +0000 Subject: This commit was manufactured by cvs2svn to create branch 'cygwin_daemon'. Cherrypick from master 2002-06-06 15:35:09 UTC Corinna Vinschen ' * 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 --- winsup/cygwin/fhandler_proc.cc | 502 ++++++++++++++++++++++++ winsup/cygwin/fhandler_process.cc | 736 ++++++++++++++++++++++++++++++++++++ winsup/cygwin/fhandler_registry.cc | 544 ++++++++++++++++++++++++++ winsup/cygwin/fhandler_virtual.cc | 226 +++++++++++ winsup/cygwin/include/netinet/udp.h | 51 +++ winsup/cygwin/stackdump.sgml | 13 + 6 files changed, 2072 insertions(+) create mode 100644 winsup/cygwin/fhandler_proc.cc create mode 100644 winsup/cygwin/fhandler_process.cc create mode 100644 winsup/cygwin/fhandler_registry.cc create mode 100644 winsup/cygwin/fhandler_virtual.cc create mode 100644 winsup/cygwin/include/netinet/udp.h create mode 100644 winsup/cygwin/stackdump.sgml 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 +#include +#include +#include +#include +#include "cygerrno.h" +#include "security.h" +#include "fhandler.h" +#include "path.h" +#include "pinfo.h" +#include "dtable.h" +#include "cygheap.h" +#include +#include +#include "ntdll.h" + +#define _COMPILING_NEWLIB +#include + +/* 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/ 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 +#include +#include +#include +#include +#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 + +#define _COMPILING_NEWLIB +#include + +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, ""); + 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, "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, ""); + 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 +#include +#include +#include +#include "cygerrno.h" +#include "security.h" +#include "fhandler.h" +#include "path.h" +#include "dtable.h" +#include "cygheap.h" +#include + +#define _COMPILING_NEWLIB +#include + +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 +#include +#include +#include +#include "cygerrno.h" +#include "security.h" +#include "fhandler.h" +#include "path.h" +#include "dtable.h" +#include "shared_info.h" +#include "cygheap.h" +#include + +#define _COMPILING_NEWLIB +#include + +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 @@ + +cygwin_stackdump + + +extern "C" void +cygwin_stackdump + + + + Outputs a stackdump to stderr from the called location. + + + -- cgit v1.2.3