aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--winsup/cygwin/ChangeLog36
-rw-r--r--winsup/cygwin/autoload.cc3
-rw-r--r--winsup/cygwin/fhandler.h1
-rw-r--r--winsup/cygwin/fhandler_proc.cc15
-rw-r--r--winsup/cygwin/fhandler_process.cc170
-rw-r--r--winsup/cygwin/path.cc43
-rw-r--r--winsup/cygwin/pinfo.cc73
-rw-r--r--winsup/cygwin/pinfo.h6
8 files changed, 324 insertions, 23 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 1b53aa4..40ef4d1 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,39 @@
+2005-01-29 Corinna Vinschen <corinna@vinschen.de>
+
+ * 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 <cgf@timesys.com>
* cygthread.cc (new): Add a little more debugging.
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index 5c2832a..125b77e 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 34b40b8..f1041c6 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 8e94092..f47a2fd 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 3c996d0..4a14bca 100644
--- a/winsup/cygwin/fhandler_process.cc
+++ b/winsup/cygwin/fhandler_process.cc
@@ -25,30 +25,37 @@ details. */
#include <sys/param.h>
#include <assert.h>
#include <sys/sysmacros.h>
+#include <psapi.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 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,12 +408,101 @@ 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)
{
char cmd[CYG_MAX_PATH];
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index a9d6292..0d26375 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/<pid>/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 8376465..fa440aa 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 ();
@@ -655,6 +684,50 @@ out:
}
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)
{
char *s;
diff --git a/winsup/cygwin/pinfo.h b/winsup/cygwin/pinfo.h
index 3203a69..88442ca 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)));