From faf07ace9256e17e846adcb514ee33d5ceccf1e7 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Sat, 29 Jan 2005 11:23:07 +0000 Subject: [PATCH] * autoload.cc (GetModuleFileNameExA): Add. (GetModuleInformation): Add. (QueryWorkingSet): Add. * fhandler.h (fhandler_virtual::get_filebuf): New method. * fhandler_proc.cc (PROC_SELF): Define. (proc_fhandlers): Change type of self to FH_PROC. (fhandler_proc::exists): Return -3 if self. (fhandler_proc::fstat): Handle self as symlink. (fhandler_proc::fill_filebuf): Handle self. * fhandler_process.cc: Include psapi.h. (PROCESS_EXENAME): Remove. (PROCESS_MAPS): Define. (PROCESS_ROOT): Define. (PROCESS_EXE): Define. (PROCESS_CWD): Define. (process_listing): Remove "exename", add "maps, "root", "exe" and "cwd" elements. (fhandler_process::exists): Return -2 for symlinks. (fhandler_process::fstat): Handle symlinks. (fill_filebuf): Evaluate pid if pid is 0. Use exename handling for exe. Handle maps, root and cwd. (format_process_maps): New function evaluating "maps". * path.cc (symlink_info::set): New method to fill symlink_info with data matching virtual symlinks. (path_conv::check): Handle virtual symlinks. * pinfo.cc (_pinfo::commune_recv): Add PICOM_CWD and PICOM_ROOT handling. (_pinfo::commune_send): Ditto. (_pinfo::root): New function. (_pinfo::cwd): New function. * pinfo.h (enum picom): Add PICOM_CWD and PICOM_ROOT. (_pinfo::root): Declare. (_pinfo::cwd): Declare. --- winsup/cygwin/ChangeLog | 36 +++++++ winsup/cygwin/autoload.cc | 3 + winsup/cygwin/fhandler.h | 1 + winsup/cygwin/fhandler_proc.cc | 15 ++- winsup/cygwin/fhandler_process.cc | 170 ++++++++++++++++++++++++++---- winsup/cygwin/path.cc | 43 +++++++- winsup/cygwin/pinfo.cc | 73 +++++++++++++ winsup/cygwin/pinfo.h | 6 +- 8 files changed, 324 insertions(+), 23 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 1b53aa42e..40ef4d14a 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,39 @@ +2005-01-29 Corinna Vinschen + + * autoload.cc (GetModuleFileNameExA): Add. + (GetModuleInformation): Add. + (QueryWorkingSet): Add. + * fhandler.h (fhandler_virtual::get_filebuf): New method. + * fhandler_proc.cc (PROC_SELF): Define. + (proc_fhandlers): Change type of self to FH_PROC. + (fhandler_proc::exists): Return -3 if self. + (fhandler_proc::fstat): Handle self as symlink. + (fhandler_proc::fill_filebuf): Handle self. + * fhandler_process.cc: Include psapi.h. + (PROCESS_EXENAME): Remove. + (PROCESS_MAPS): Define. + (PROCESS_ROOT): Define. + (PROCESS_EXE): Define. + (PROCESS_CWD): Define. + (process_listing): Remove "exename", add "maps, "root", "exe" and + "cwd" elements. + (fhandler_process::exists): Return -2 for symlinks. + (fhandler_process::fstat): Handle symlinks. + (fill_filebuf): Evaluate pid if pid is 0. Use exename handling for + exe. Handle maps, root and cwd. + (format_process_maps): New function evaluating "maps". + * path.cc (symlink_info::set): New method to fill symlink_info + with data matching virtual symlinks. + (path_conv::check): Handle virtual symlinks. + * pinfo.cc (_pinfo::commune_recv): Add PICOM_CWD and PICOM_ROOT + handling. + (_pinfo::commune_send): Ditto. + (_pinfo::root): New function. + (_pinfo::cwd): New function. + * pinfo.h (enum picom): Add PICOM_CWD and PICOM_ROOT. + (_pinfo::root): Declare. + (_pinfo::cwd): Declare. + 2005-01-29 Christopher Faylor * cygthread.cc (new): Add a little more debugging. diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc index 5c2832a23..125b77eb5 100644 --- a/winsup/cygwin/autoload.cc +++ b/winsup/cygwin/autoload.cc @@ -392,7 +392,10 @@ LoadDLLfuncEx (RtlNtStatusToDosError, 4, ntdll, 1) LoadDLLfuncEx (RtlIsDosDeviceName_U, 4, ntdll, 1) LoadDLLfuncEx (EnumProcessModules, 16, psapi, 1) +LoadDLLfuncEx (GetModuleFileNameExA, 16, psapi, 1) +LoadDLLfuncEx (GetModuleInformation, 16, psapi, 1) LoadDLLfuncEx (GetProcessMemoryInfo, 12, psapi, 1) +LoadDLLfuncEx (QueryWorkingSet, 12, psapi, 1) LoadDLLfuncEx (LsaDeregisterLogonProcess, 4, secur32, 1) LoadDLLfuncEx (LsaFreeReturnBuffer, 4, secur32, 1) diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 34b40b83d..f1041c68c 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -1121,6 +1121,7 @@ class fhandler_virtual : public fhandler_base int __stdcall fchown (__uid32_t uid, __gid32_t gid) __attribute__ ((regparm (2))); int __stdcall facl (int, int, __acl32 *) __attribute__ ((regparm (3))); virtual bool fill_filebuf (); + char *get_filebuf () { return filebuf; } void fixup_after_exec (); }; diff --git a/winsup/cygwin/fhandler_proc.cc b/winsup/cygwin/fhandler_proc.cc index 8e94092df..f47a2fd24 100644 --- a/winsup/cygwin/fhandler_proc.cc +++ b/winsup/cygwin/fhandler_proc.cc @@ -41,6 +41,7 @@ static const int PROC_VERSION = 6; // /proc/version static const int PROC_UPTIME = 7; // /proc/uptime static const int PROC_CPUINFO = 8; // /proc/cpuinfo static const int PROC_PARTITIONS = 9; // /proc/partitions +static const int PROC_SELF = 10; // /proc/self /* names of objects in /proc */ static const char *proc_listing[] = { @@ -74,7 +75,7 @@ static const DWORD proc_fhandlers[PROC_LINK_COUNT] = { FH_PROC, FH_PROC, FH_PROC, - FH_PROCESS, + FH_PROC, }; /* name of the /proc filesystem */ @@ -143,7 +144,10 @@ fhandler_proc::exists () 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; + { + fileid = i; + return (proc_fhandlers[i] == FH_PROC) ? (i == PROC_SELF ? -3 : -1) : 1; + } return 0; } @@ -177,6 +181,8 @@ fhandler_proc::fstat (struct __stat64 *buf) { if (proc_fhandlers[i] != FH_PROC) buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; + else if (i == PROC_SELF) + buf->st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; else { buf->st_mode &= NO_X; @@ -379,6 +385,11 @@ fhandler_proc::fill_filebuf () filesize = format_proc_partitions (filebuf, bufalloc); break; } + case PROC_SELF: + { + filebuf = (char *) realloc (filebuf, bufalloc = 32); + filesize = __small_sprintf (filebuf, "%d", getpid ()); + } } return true; } diff --git a/winsup/cygwin/fhandler_process.cc b/winsup/cygwin/fhandler_process.cc index 3c996d067..4a14bca56 100644 --- a/winsup/cygwin/fhandler_process.cc +++ b/winsup/cygwin/fhandler_process.cc @@ -25,30 +25,37 @@ details. */ #include #include #include +#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 int PROCESS_CMDLINE = 14; +static const int PROCESS_WINPID = 3; +static const int PROCESS_WINEXENAME = 4; +static const int PROCESS_STATUS = 5; +static const int PROCESS_UID = 6; +static const int PROCESS_GID = 7; +static const int PROCESS_PGID = 8; +static const int PROCESS_SID = 9; +static const int PROCESS_CTTY = 10; +static const int PROCESS_STAT = 11; +static const int PROCESS_STATM = 12; +static const int PROCESS_CMDLINE = 13; +static const int PROCESS_MAPS = 14; +/* Keep symlinks always the last entries. */ +static const int PROCESS_ROOT = 15; +static const int PROCESS_EXE = 16; +static const int PROCESS_CWD = 17; + +/* The position of "root" defines the beginning of symlik entries. */ +#define is_symlink(nr) ((nr) >= PROCESS_ROOT) static const char * const process_listing[] = { ".", "..", "ppid", - "exename", "winpid", "winexename", "status", @@ -60,12 +67,18 @@ static const char * const process_listing[] = "stat", "statm", "cmdline", + "maps", + /* Keep symlinks always the last entries. */ + "root", + "exe", + "cwd", NULL }; static const int PROCESS_LINK_COUNT = (sizeof (process_listing) / sizeof (const char *)) - 1; +static _off64_t format_process_maps (_pinfo *p, char *destbuf, size_t maxsize); static _off64_t format_process_stat (_pinfo *p, char *destbuf, size_t maxsize); static _off64_t format_process_status (_pinfo *p, char *destbuf, size_t maxsize); static _off64_t format_process_statm (_pinfo *p, char *destbuf, size_t maxsize); @@ -91,7 +104,10 @@ fhandler_process::exists () for (int i = 0; process_listing[i]; i++) if (pathmatch (path + 1, process_listing[i])) - return -1; + { + fileid = i; + return is_symlink (i) ? -2 : -1; + } return 0; } @@ -137,8 +153,13 @@ fhandler_process::fstat (struct __stat64 *buf) buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; buf->st_nlink = PROCESS_LINK_COUNT; return 0; - default: + case -2: + buf->st_uid = p->uid; + buf->st_gid = p->gid; + buf->st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; + return 0; case -1: + default: buf->st_uid = p->uid; buf->st_gid = p->gid; buf->st_mode |= S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; @@ -251,6 +272,15 @@ out: bool fhandler_process::fill_filebuf () { + if (!pid) + { + const char *path; + path = get_name () + proc_len + 1; + if (path_prefix_p ("self", path, 4)) + pid = getpid (); + else + pid = atoi (path); + } pinfo p (pid); if (!p) @@ -298,12 +328,25 @@ fhandler_process::fill_filebuf () filesize = strlen (filebuf); break; } + case PROCESS_ROOT: + case PROCESS_CWD: case PROCESS_CMDLINE: { - if (filebuf) + if (filebuf) free (filebuf); - size_t fs; - filebuf = p->cmdline (fs); + size_t fs; + switch (fileid) + { + case PROCESS_ROOT: + filebuf = p->root (fs); + break; + case PROCESS_CWD: + filebuf = p->cwd (fs); + break; + case PROCESS_CMDLINE: + filebuf = p->cmdline (fs); + break; + } filesize = fs; if (!filebuf || !*filebuf) { @@ -312,7 +355,7 @@ fhandler_process::fill_filebuf () } break; } - case PROCESS_EXENAME: + case PROCESS_EXE: { filebuf = (char *) realloc (filebuf, bufalloc = CYG_MAX_PATH); if (p->process_state & PID_EXITED) @@ -365,11 +408,100 @@ fhandler_process::fill_filebuf () filesize = format_process_statm (*p, filebuf, bufalloc); break; } + case PROCESS_MAPS: + { + filebuf = (char *) realloc (filebuf, bufalloc = 2048); + filesize = format_process_maps (*p, filebuf, bufalloc); + break; + } } return true; } +static _off64_t +format_process_maps (_pinfo *p, char *destbuf, size_t maxsize) +{ + if (!wincap.is_winnt ()) + return 0; + + HANDLE proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + FALSE, + p->dwProcessId); + if (!proc) + return 0; + + _off64_t len = 0; + HMODULE *modules; + DWORD needed, i; + DWORD_PTR wset_size; + DWORD_PTR *workingset = NULL; + MODULEINFO info; + char modname[CYG_MAX_PATH + 1]; + char posix_modname[CYG_MAX_PATH + 1]; + + if (!EnumProcessModules (proc, NULL, 0, &needed)) + { + __seterrno (); + len = -1; + goto out; + } + modules = (HMODULE*) alloca (needed); + if (!EnumProcessModules (proc, modules, needed, &needed)) + { + __seterrno (); + len = -1; + goto out; + } + + QueryWorkingSet (proc, (void *) &wset_size, sizeof wset_size); + if (GetLastError () == ERROR_BAD_LENGTH) + { + workingset = (DWORD_PTR *) alloca (sizeof (DWORD_PTR) * ++wset_size); + if (!QueryWorkingSet (proc, (void *) workingset, + sizeof (DWORD_PTR) * wset_size)) + workingset = NULL; + } + for (i = 0; i < needed / sizeof (HMODULE); i++) + if (GetModuleInformation (proc, modules[i], &info, sizeof info) + && GetModuleFileNameEx (proc, modules[i], modname, sizeof modname)) + { + char access[5]; + strcpy (access, "r--p"); + cygwin_conv_to_full_posix_path (modname, posix_modname); + if (len + strlen (posix_modname) + 50 > maxsize - 1) + break; + if (workingset) + for (unsigned i = 1; i <= wset_size; ++i) + { + DWORD_PTR addr = workingset[i] & 0xfffff000UL; + if ((char *)addr >= info.lpBaseOfDll + && (char *)addr < (char *)info.lpBaseOfDll + info.SizeOfImage) + { + access[0] = (workingset[i] & 0x5) ? 'r' : '-'; + access[1] = (workingset[i] & 0x4) ? 'w' : '-'; + access[2] = (workingset[i] & 0x2) ? 'x' : '-'; + access[3] = (workingset[i] & 0x100) ? 's' : 'p'; + } + } + int written = __small_sprintf (destbuf + len, + "%08lx-%08lx %s %08lx 00:00 %lu ", + info.lpBaseOfDll, + (unsigned long)info.lpBaseOfDll + + info.SizeOfImage, + access, + info.EntryPoint, + info.SizeOfImage); + while (written++ < 49) + destbuf[len + written] = ' '; + len += written; + len += __small_sprintf (destbuf + len, "%s\n", posix_modname); + } +out: + CloseHandle (proc); + return len; +} + static _off64_t format_process_stat (_pinfo *p, char *destbuf, size_t maxsize) { diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index a9d6292d7..0d2637537 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -95,6 +95,7 @@ struct symlink_info _minor_t minor; _mode_t mode; int check (char *path, const suffix_info *suffixes, unsigned opt); + int set (char *path, int type); bool parse_device (const char *); bool case_check (char *path); }; @@ -616,6 +617,11 @@ path_conv::check (const char *src, unsigned opt, /* FIXME: Calling build_fhandler here is not the right way to handle this. */ fhandler_virtual *fh = (fhandler_virtual *) build_fh_dev (dev, path_copy); int file_type = fh->exists (); + if (file_type == -2 || file_type == -3) + { + fh->fill_filebuf (); + symlen = sym.set (fh->get_filebuf (), file_type); + } delete fh; switch (file_type) { @@ -626,9 +632,12 @@ path_conv::check (const char *src, unsigned opt, case -1: fileattr = 0; break; + case -2: /* /proc//symlinks */ + case -3: /* /proc/self */ + goto is_virtual_symlink; default: fileattr = INVALID_FILE_ATTRIBUTES; - break; + goto virtual_component_retry; } goto out; } @@ -657,6 +666,8 @@ path_conv::check (const char *src, unsigned opt, symlen = sym.check (full_path, suff, opt | fs.has_ea ()); +is_virtual_symlink: + if (sym.minor || sym.major) { dev.parse (sym.major, sym.minor); @@ -740,6 +751,8 @@ path_conv::check (const char *src, unsigned opt, /* No existing file found. */ } +virtual_component_retry: + /* Find the new "tail" of the path, e.g. in '/for/bar/baz', /baz is the tail. */ if (tail != path_end) @@ -3117,6 +3130,34 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt) return res; } +/* "path" is the path in a virtual symlink. Set a symlink_info struct from + that and proceed with further path checking afterwards. */ +int +symlink_info::set (char *path, int type) +{ + extern suffix_info stat_suffixes[]; + + strcpy (contents, path); + pflags = PATH_SYMLINK; + if (type == -3) /* /proc/self */ + { + fileattr = FILE_ATTRIBUTE_DIRECTORY; + error = 0; + } + else + { + /* That's save since a virtual symlink doesn't point to itself. */ + path_conv pc (contents, PC_SYM_NOFOLLOW | PC_FULL, stat_suffixes); + fileattr = pc; + error = pc.error; + } + is_symlink = true; + ext_tacked_on = case_clash = false; + ext_here = NULL; + extn = major = minor = mode = 0; + return strlen (path); +} + /* Check the correct case of the last path component (given in DOS style). Adjust the case in this->path if pcheck_case == PCHECK_ADJUST or return false if pcheck_case == PCHECK_STRICT. diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc index 83764651d..fa440aa39 100644 --- a/winsup/cygwin/pinfo.cc +++ b/winsup/cygwin/pinfo.cc @@ -380,6 +380,7 @@ extern char **__argv; void _pinfo::commune_recv () { + char pathbuf[CYG_MAX_PATH]; DWORD nr; DWORD code; HANDLE hp; @@ -457,6 +458,32 @@ _pinfo::commune_recv () } break; } + case PICOM_CWD: + { + unsigned int n = strlen (cygheap->cwd.get (pathbuf, 1, 1, CYG_MAX_PATH)) + 1; + CloseHandle (__fromthem); __fromthem = NULL; + CloseHandle (hp); + if (!WriteFile (__tothem, &n, sizeof n, &nr, NULL)) + sigproc_printf ("WriteFile sizeof argv failed, %E"); + else if (!WriteFile (__tothem, pathbuf, n, &nr, NULL)) + sigproc_printf ("WriteFile sizeof argv failed, %E"); + break; + } + case PICOM_ROOT: + { + unsigned int n; + if (cygheap->root.exists ()) + n = strlen (strcpy (pathbuf, cygheap->root.posix_path ())) + 1; + else + n = strlen (strcpy (pathbuf, "/")) + 1; + CloseHandle (__fromthem); __fromthem = NULL; + CloseHandle (hp); + if (!WriteFile (__tothem, &n, sizeof n, &nr, NULL)) + sigproc_printf ("WriteFile sizeof argv failed, %E"); + else if (!WriteFile (__tothem, pathbuf, n, &nr, NULL)) + sigproc_printf ("WriteFile sizeof argv failed, %E"); + break; + } case PICOM_FIFO: { char path[CYG_MAX_PATH + 1]; @@ -588,6 +615,8 @@ _pinfo::commune_send (DWORD code, ...) switch (code) { case PICOM_CMDLINE: + case PICOM_CWD: + case PICOM_ROOT: if (!ReadFile (fromthem, &n, sizeof n, &nr, NULL) || nr != sizeof n) { __seterrno (); @@ -654,6 +683,50 @@ out: return res; } +char * +_pinfo::root (size_t& n) +{ + char *s; + if (!this || !pid) + return NULL; + if (pid != myself->pid) + { + commune_result cr = commune_send (PICOM_ROOT); + s = cr.s; + n = cr.n; + } + else + { + if (cygheap->root.exists ()) + s = strdup (cygheap->root.posix_path ()); + else + s = strdup ("/"); + n = strlen (s) + 1; + } + return s; +} + +char * +_pinfo::cwd (size_t& n) +{ + char *s; + if (!this || !pid) + return NULL; + if (pid != myself->pid) + { + commune_result cr = commune_send (PICOM_CWD); + s = cr.s; + n = cr.n; + } + else + { + s = (char *) malloc (CYG_MAX_PATH); + cygheap->cwd.get (s, 1, 1, CYG_MAX_PATH); + n = strlen (s) + 1; + } + return s; +} + char * _pinfo::cmdline (size_t& n) { diff --git a/winsup/cygwin/pinfo.h b/winsup/cygwin/pinfo.h index 3203a6975..88442ca22 100644 --- a/winsup/cygwin/pinfo.h +++ b/winsup/cygwin/pinfo.h @@ -23,7 +23,9 @@ struct commune_result enum picom { PICOM_CMDLINE = 1, - PICOM_FIFO = 2 + PICOM_FIFO = 2, + PICOM_CWD = 3, + PICOM_ROOT = 4 }; #define EXITCODE_SET 0x80000000 @@ -106,6 +108,8 @@ public: void commune_recv (); commune_result commune_send (DWORD, ...); bool alive (); + char *root (size_t &); + char *cwd (size_t &); char *cmdline (size_t &); void set_ctty (class tty_min *, int, class fhandler_tty_slave *); bool dup_proc_pipe (HANDLE) __attribute__ ((regparm(2))); -- 2.43.5