[PATCH setup 0/2] List and offer to kill processes preventing a file from being written

2013-02-05 Thread Jon TURNEY
I find it irritating to have to work out which process I need to stop when 
setup 
can't update a file, and setup not helping you find it doesn't really meet 
contemporary standards.  So, loosely inspired by [1], a patch to list and offer 
to kill processes preventing a file from being written.

This uses psapi.dll to find which out processes have a file loaded as a module.

Note that this doesn't help when file isn't writeable because process has the 
file open exclusively, but there doesn't seem to be an interface to do this 
until the restart manager API introduced in Vista.

This relies on the probably undocumented behaviour of /usr/bin/kill working 
with 
windows PIDs as well as cygwin PIDs, and the assumption those PID sets are 
disjoint.

Ideally, I wanted to note if the process which had the file loaded was a 
service, and stop and restart the service.  But this seems to be not 
straightforward to do, as setup doesn't have any visibility of the cygwin 
process tree, which is needed to find the cygrunsrv service process which is 
the 
parent of the process using the file, and thus the service name to stop and 
restart.

[1] http://cygwin.com/ml/cygwin/2012-08/msg00444.html

Jon TURNEY (2):
  Refactor ::run() so it's more generally useful
  List and offer to kill processes preventing a file from being written

 Makefile.am|4 +-
 install.cc |  152 +---
 processlist.cc |  237 
 processlist.h  |   41 ++
 res.rc |   20 +
 resource.h |4 +
 script.cc  |   33 +
 script.h   |7 +-
 8 files changed, 435 insertions(+), 63 deletions(-)
 create mode 100644 processlist.cc
 create mode 100644 processlist.h

-- 
1.7.9



[PATCH setup 1/2] Refactor ::run() so it's more generally useful

2013-02-05 Thread Jon TURNEY
Move all the logging of the command it runs in
Move the formatting of the command line used for postinstall script running out

2013-02-01  Jon TURNEY  jon.tur...@dronecode.org.uk

* script.cc (::run, Script::run): Move the formatting of the command
line used for postinstall script running out to Script::run. Move the
logging of the command and it's output into ::run.
* script.h: Add ::run() prototype.

Signed-off-by: Jon TURNEY jon.tur...@dronecode.org.uk
---
 script.cc |   33 +++--
 script.h  |7 +--
 2 files changed, 24 insertions(+), 16 deletions(-)

diff --git a/script.cc b/script.cc
index 6663e8c..4bf0f09 100644
--- a/script.cc
+++ b/script.cc
@@ -196,10 +196,10 @@ OutputLog::out_to(std::ostream out)
   SetFilePointer(_handle, 0, NULL, FILE_END);
 }
 
-static int
-run (const char *sh, const char *args, const char *file, OutputLog file_out)
+int
+run (const char *cmdline)
 {
-  char cmdline[MAX_PATH];
+
   STARTUPINFO si;
   PROCESS_INFORMATION pi;
   DWORD flags = CREATE_NEW_CONSOLE;
@@ -207,7 +207,11 @@ run (const char *sh, const char *args, const char *file, 
OutputLog file_out)
   BOOL inheritHandles = FALSE;
   BOOL exitCodeValid = FALSE;
 
-  sprintf (cmdline, %s %s \%s\, sh, args, file);
+  log(LOG_PLAIN)  running:   cmdline  endLog;
+
+  char tmp_pat[] = /var/log/setup.log.runXXX;
+  OutputLog file_out = std::string (mktemp (tmp_pat));
+
   memset (pi, 0, sizeof (pi));
   memset (si, 0, sizeof (si));
   si.cb = sizeof (si);
@@ -226,7 +230,7 @@ run (const char *sh, const char *args, const char *file, 
OutputLog file_out)
   flags = CREATE_NO_WINDOW;  // Note: this is ignored on Win9x
 }
 
-  BOOL createSucceeded = CreateProcess (0, cmdline, 0, 0, inheritHandles,
+  BOOL createSucceeded = CreateProcess (0, (char *)cmdline, 0, 0, 
inheritHandles,
flags, 0, get_root_dir ().c_str(),
si, pi);
 
@@ -237,6 +241,10 @@ run (const char *sh, const char *args, const char *file, 
OutputLog file_out)
 }
   CloseHandle(pi.hProcess);
   CloseHandle(pi.hThread);
+
+  if (!file_out.isEmpty ())
+log(LOG_BABBLE)  file_out  endLog;
+
   if (exitCodeValid)
 return exitCode;
   return -GetLastError();
@@ -268,24 +276,21 @@ Script::run() const
 }
 
   int retval;
-  char tmp_pat[] = /var/log/setup.log.postinstallXXX;
-  OutputLog file_out = std::string (mktemp (tmp_pat));
+  char cmdline[MAX_PATH];
+
   if (sh.size()  stricmp (extension(), .sh) == 0)
 {
-  log(LOG_PLAIN)  running:   sh   --norc --noprofile \  
scriptName  \  endLog;
-  retval = ::run (sh.c_str(), --norc --noprofile, scriptName.c_str(), 
file_out);
+  sprintf (cmdline, %s %s \%s\, sh.c_str(), --norc --noprofile, 
scriptName.c_str());
+  retval = ::run (cmdline);
 }
   else if (cmd  stricmp (extension(), .bat) == 0)
 {
-  log(LOG_PLAIN)  running:   cmd   /c \  windowsName  \ 
 endLog;
-  retval = ::run (cmd, /c, windowsName.c_str(), file_out);
+  sprintf (cmdline, %s %s \%s\, cmd, /c, windowsName.c_str());
+  retval = ::run (cmdline);
 }
   else
 return -ERROR_INVALID_DATA;
 
-  if (!file_out.isEmpty ())
-log(LOG_BABBLE)  file_out  endLog;
-
   if (retval)
 log(LOG_PLAIN)  abnormal exit: exit code=  retval  endLog;
 
diff --git a/script.h b/script.h
index 144fd71..abdd43e 100644
--- a/script.h
+++ b/script.h
@@ -14,7 +14,7 @@
  */
 #ifndef SETUP_SCRIPT_H
 #define SETUP_SCRIPT_H
-   
+
 /* Initialisation stuff for run_script: sh, cmd, CYGWINROOT and PATH */
 void init_run_script ();
 
@@ -24,6 +24,9 @@ int try_run_script (const std::string dir,
 const std::string fname,
 const std::string ext);
 
+/* Run a command and capture it's output to the log */
+int run (const char *cmdline);
+
 class Script {
 public:
   static bool isAScript (const std::string file);
@@ -32,7 +35,7 @@ public:
   std::string fullName() const;
 /* Run the script.  If its suffix is .sh, and we have a Bourne shell, execute
it using sh.  Otherwise, if the suffix is .bat, execute using cmd.exe (NT)
-   or command.com (9x).  Returns the exit status of the process, or 
+   or command.com (9x).  Returns the exit status of the process, or
negative error if any.  */
   int run() const;
   bool operator == (const Script s) { return s.scriptName == scriptName; } ;
-- 
1.7.9



[PATCH setup 2/2] List and offer to kill processes preventing a file from being written

2013-02-05 Thread Jon TURNEY
- Enumerate processes preventing a file from being written
- Replace the MessageBox reporting an in-use file with a DialogBox reporting the
in-use file and the processes which are using that file.
- Use /usr/bin/kill to kill processes which have files open, trying SIGTERM,
then SIGKILL, then TerminateProcess

2013-02-01  Jon TURNEY  jon.tur...@dronecode.org.uk

* install.cc ( _custom_MessageBox): Remove custom message box.
(FileInuseDlgProc): Add file-in-use dialog box.
(installOne): Use processlist to list processes using a file, and
offer to kill them with the file-in-use dialog.
* res.rc (IDD_FILE_INUSE) : New dialog.
* resource.h (IDD_FILE_INUSE, IDC_FILE_INUSE_EDIT)
(IDC_FILE_INUSE_MSG, IDC_FILE_INUSE_HELP): Define corresponding
resource ID numbers.
* processlist.h: New file.
* processlist.cc: New file.
* Makefile.am (setup_LDADD): Add -lpsapi.
(setup_SOURCES): Add new files.

Signed-off-by: Jon TURNEY jon.tur...@dronecode.org.uk
---
 Makefile.am|4 +-
 install.cc |  152 +---
 processlist.cc |  237 
 processlist.h  |   41 ++
 res.rc |   20 +
 resource.h |4 +
 6 files changed, 411 insertions(+), 47 deletions(-)
 create mode 100644 processlist.cc
 create mode 100644 processlist.h

diff --git a/Makefile.am b/Makefile.am
index 0f1498b..ddd19ed 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -105,7 +105,7 @@ inilint_SOURCES = \
 
 setup_LDADD = \
libgetopt++/libgetopt++.la -lgcrypt -lgpg-error \
-   -lshlwapi -lcomctl32 -lole32 -lwsock32 -lnetapi32 -luuid -llzma -lbz2 
-lz 
+   -lshlwapi -lcomctl32 -lole32 -lwsock32 -lnetapi32 -lpsapi -luuid -llzma 
-lbz2 -lz
 setup_LDFLAGS = -mwindows -Wc,-static -static-libtool-libs
 setup_SOURCES = \
AntiVirus.cc \
@@ -230,6 +230,8 @@ setup_SOURCES = \
postinstallresults.h \
prereq.cc \
prereq.h \
+   processlist.cc \
+   processlist.h \
proppage.cc \
proppage.h \
propsheet.cc \
diff --git a/install.cc b/install.cc
index 9d39f33..61333b7 100644
--- a/install.cc
+++ b/install.cc
@@ -63,6 +63,7 @@ static const char *cvsid = \n%%% $Id: install.cc,v 2.101 
2011/07/25 14:36:24 jt
 
 #include threebar.h
 #include Exception.h
+#include processlist.h
 
 using namespace std;
 
@@ -192,39 +193,61 @@ Installer::replaceOnRebootSucceeded (const std::string 
fn, bool rebootneeded)
   rebootneeded = true;
 }
 
-#define MB_RETRYCONTINUE 7
-#if !defined(IDCONTINUE)
-#define IDCONTINUE IDCANCEL
-#endif
+typedef struct
+{
+  const char *msg;
+  const char *processlist;
+  int iteration;
+} FileInuseDlgData;
 
-static HHOOK hMsgBoxHook;
-LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam) {
-  HWND hWnd;
-  switch (nCode) {
-case HCBT_ACTIVATE:
-  hWnd = (HWND)wParam;
-  if (GetDlgItem(hWnd, IDCANCEL) != NULL)
- SetDlgItemText(hWnd, IDCANCEL, Continue);
-  UnhookWindowsHookEx(hMsgBoxHook);
-  }
-  return CallNextHookEx(hMsgBoxHook, nCode, wParam, lParam);
-}
+static BOOL CALLBACK
+FileInuseDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+  switch (uMsg)
+{
+case WM_INITDIALOG:
+  {
+FileInuseDlgData *dlg_data = (FileInuseDlgData *)lParam;
+
+SetDlgItemText(hwndDlg, IDC_FILE_INUSE_MSG, dlg_data-msg);
+SetDlgItemText(hwndDlg, IDC_FILE_INUSE_EDIT, dlg_data-processlist);
+
+switch (dlg_data-iteration)
+  {
+  case 0:
+break; // show the dialog the way it is in the resource
+
+  case 1:
+SetDlgItemText(hwndDlg, IDRETRY, Kill Processes);
+SetDlgItemText(hwndDlg, IDC_FILE_INUSE_HELP,
+   Select 'Kill' to kill Cygwin processes and retry, 
or 
+   select 'Continue' to go on anyway (you will need 
to reboot).);
+break;
+
+  default:
+  case 2:
+SetDlgItemText(hwndDlg, IDRETRY, Kill Processes);
+SetDlgItemText(hwndDlg, IDC_FILE_INUSE_HELP,
+   Select 'Kill' to forcibly kill all processes and 
retry, or 
+   select 'Continue' to go on anyway (you will need 
to reboot).);
+  }
+  }
+  return TRUE; // automatically set focus, please
 
-int _custom_MessageBox(HWND hWnd, LPCTSTR szText, LPCTSTR szCaption, UINT 
uType) {
-  int retval;
-  bool retry_continue = (uType  MB_TYPEMASK) == MB_RETRYCONTINUE;
-  if (retry_continue) {
-uType = ~MB_TYPEMASK; uType |= MB_RETRYCANCEL;
-// Install a window hook, so we can intercept the message-box
-// creation, and customize it
-// Only install for THIS thread!!!
-hMsgBoxHook = SetWindowsHookEx(WH_CBT, CBTProc, NULL, 
GetCurrentThreadId());
-  }
-  retval = MessageBox(hWnd, szText, szCaption, uType);
-  // Intercept the return value 

Re: [PATCH setup 0/2] List and offer to kill processes preventing a file from being written

2013-02-05 Thread Christopher Faylor
Wow.  Ambitious!

On Tue, Feb 05, 2013 at 03:24:48PM +, Jon TURNEY wrote:
I find it irritating to have to work out which process I need to stop when 
setup 
can't update a file, and setup not helping you find it doesn't really meet 
contemporary standards.  So, loosely inspired by [1], a patch to list and 
offer 
to kill processes preventing a file from being written.

This uses psapi.dll to find which out processes have a file loaded as a module.

Note that this doesn't help when file isn't writeable because process has the 
file open exclusively, but there doesn't seem to be an interface to do this 
until the restart manager API introduced in Vista.

This relies on the probably undocumented behaviour of /usr/bin/kill working 
with 
windows PIDs as well as cygwin PIDs, and the assumption those PID sets are 
disjoint.

Why not just use TerminateProcess rather than Cygwin's /usr/bin/kill?
FWIW, Cygwin's pids often == Windows pids.  They are derived from the
same pool.

I really like this idea but I wonder if the use of psapi.dll will mean
that setup-legacy.exe will be broken by that change since it is supposed
to work on older platforms.  And, I wonder if it really is time to stop
offering the old 1.5.x binaries so we wouldn't have to worry about that.

Other than that, I see some very minor formatting problems - you need to
put spaces before opening parentheses for functions and macros.

Ideally, I wanted to note if the process which had the file loaded was a 
service, and stop and restart the service.  But this seems to be not 
straightforward to do, as setup doesn't have any visibility of the cygwin 
process tree, which is needed to find the cygrunsrv service process which is 
the 
parent of the process using the file, and thus the service name to stop and 
restart.

Is there any way to determine if a process is running as a service?  If
so, I'd think that just telling someone they had to restart the service
would be adequate.

cgf


Re: [PATCH setup 0/2] List and offer to kill processes preventing a file from being written

2013-02-05 Thread Corinna Vinschen
On Feb  5 11:06, Christopher Faylor wrote:
 Wow.  Ambitious!
 
 On Tue, Feb 05, 2013 at 03:24:48PM +, Jon TURNEY wrote:
 I find it irritating to have to work out which process I need to stop when 
 setup 
 can't update a file, and setup not helping you find it doesn't really meet 
 contemporary standards.  So, loosely inspired by [1], a patch to list and 
 offer 
 to kill processes preventing a file from being written.
 
 This uses psapi.dll to find which out processes have a file loaded as a 
 module.
 
 Note that this doesn't help when file isn't writeable because process has 
 the 
 file open exclusively, but there doesn't seem to be an interface to do this 
 until the restart manager API introduced in Vista.
 
 This relies on the probably undocumented behaviour of /usr/bin/kill working 
 with 
 windows PIDs as well as cygwin PIDs, and the assumption those PID sets are 
 disjoint.
 
 Why not just use TerminateProcess rather than Cygwin's /usr/bin/kill?
 FWIW, Cygwin's pids often == Windows pids.  They are derived from the
 same pool.
 
 I really like this idea but I wonder if the use of psapi.dll will mean
 that setup-legacy.exe will be broken by that change since it is supposed
 to work on older platforms.  And, I wonder if it really is time to stop
 offering the old 1.5.x binaries so we wouldn't have to worry about that.

+1.

 Other than that, I see some very minor formatting problems - you need to
 put spaces before opening parentheses for functions and macros.
 
 Ideally, I wanted to note if the process which had the file loaded was a 
 service, and stop and restart the service.  But this seems to be not 
 straightforward to do, as setup doesn't have any visibility of the cygwin 
 process tree, which is needed to find the cygrunsrv service process which is 
 the 
 parent of the process using the file, and thus the service name to stop and 
 restart.
 
 Is there any way to determine if a process is running as a service?  If
 so, I'd think that just telling someone they had to restart the service
 would be adequate.

Starting with Vista you know a process is running as service if it's
running in session 0.  Other than that, if the process is called
cygrunsrv, or if the process parent is called cygrunsrv, it's pretty
likely that it's a service.


Corinna

-- 
Corinna Vinschen  Please, send mails regarding Cygwin to
Cygwin Maintainer cygwin AT cygwin DOT com
Red Hat


nuke cygwin legacy?

2013-02-05 Thread Christopher Faylor
Corinna +1'ed my suggestion that it was time to remove cygwin 1.5
support so I'm wondering if anyone has any objections to removing
1.5 from cygwin.com.

I was going to suggest this a few months ago and mention that the Cygwin
Time Machine was an alternative but it looks like that service is no
longer available.

So, as an alternative, we could advertise that the directory is going
away on the main web page for a month before nuking it.

cgf


Re: [PATCH setup 0/2] List and offer to kill processes preventing a file from being written

2013-02-05 Thread Jon TURNEY
On 05/02/2013 16:16, Corinna Vinschen wrote:
 On Feb  5 11:06, Christopher Faylor wrote:
 Wow.  Ambitious!

 On Tue, Feb 05, 2013 at 03:24:48PM +, Jon TURNEY wrote:
 I find it irritating to have to work out which process I need to stop when 
 setup 
 can't update a file, and setup not helping you find it doesn't really meet 
 contemporary standards.  So, loosely inspired by [1], a patch to list and 
 offer 
 to kill processes preventing a file from being written.

 This uses psapi.dll to find which out processes have a file loaded as a 
 module.

 Note that this doesn't help when file isn't writeable because process has 
 the 
 file open exclusively, but there doesn't seem to be an interface to do this 
 until the restart manager API introduced in Vista.

 This relies on the probably undocumented behaviour of /usr/bin/kill working 
 with 
 windows PIDs as well as cygwin PIDs, and the assumption those PID sets are 
 disjoint.

 Why not just use TerminateProcess rather than Cygwin's /usr/bin/kill?

Because sending SIGTERM gives the target process the opportunity to clean up?

 FWIW, Cygwin's pids often == Windows pids.  They are derived from the
 same pool.

 I really like this idea but I wonder if the use of psapi.dll will mean
 that setup-legacy.exe will be broken by that change since it is supposed
 to work on older platforms.

Yes, this probably doesn't work on older Windows versions (I have tested with
W2K and that is fine), although  information on API support in EOL'ed versions
of Windows is hard to find...

I guess this could be changed to use the autoload mechanism for the functions
imported from psapi rather than linking with it.

 And, I wonder if it really is time to stop
 offering the old 1.5.x binaries so we wouldn't have to worry about that.
 
 +1.
 
 Other than that, I see some very minor formatting problems - you need to
 put spaces before opening parentheses for functions and macros.

 Ideally, I wanted to note if the process which had the file loaded was a 
 service, and stop and restart the service.  But this seems to be not 
 straightforward to do, as setup doesn't have any visibility of the cygwin 
 process tree, which is needed to find the cygrunsrv service process which 
 is the 
 parent of the process using the file, and thus the service name to stop and 
 restart.

 Is there any way to determine if a process is running as a service?  If
 so, I'd think that just telling someone they had to restart the service
 would be adequate.

The problem is that (for example), sshd is not a service, it's a process
started by an instance of cygrunsrv which is registered with the sshd service
name and the sshd command line to run.

I think that after finding that sshd is using some module we need to update,
setup would need to navigate the Cygwin process tree to find the cygrunsrv
process which is the parent of sshd to get the service name we would need to
restart.  I can't see how to do this in a purely windows application.

 Starting with Vista you know a process is running as service if it's
 running in session 0.  Other than that, if the process is called
 cygrunsrv, or if the process parent is called cygrunsrv, it's pretty
 likely that it's a service.


Re: nuke cygwin legacy?

2013-02-05 Thread Thomas Wolff

Am 05.02.2013 18:41, schrieb Christopher Faylor:

Corinna +1'ed my suggestion that it was time to remove cygwin 1.5
support so I'm wondering if anyone has any objections to removing
1.5 from cygwin.com.

I was going to suggest this a few months ago and mention that the Cygwin
Time Machine was an alternative but it looks like that service is no
longer available.

So, as an alternative, we could advertise that the directory is going
away on the main web page for a month before nuking it.

cgf
I had thought that support had stopped anyway, just keeping the files 
available.
I used to run an old laptop with Windows ME until recently and maybe 
there's an ME or Windows 2000 surviving in some virtual machine...
For owners of old hardware, there is also some Linux installations still 
available that fit into something like 20MB, so why not keep cygwin for 
download?

Thomas


Re: nuke cygwin legacy?

2013-02-05 Thread Warren Young

On 2/5/2013 10:41, Christopher Faylor wrote:

Corinna +1'ed my suggestion that it was time to remove cygwin 1.5
support so I'm wondering if anyone has any objections to removing
1.5 from cygwin.com.


It seems to me that the sort of person who's still hanging onto a 
DOS-based version of Windows probably won't be watching this list, or to 
the cygwin.com home page.


I propose making the deprecation a two-stage affair:

1. Move Cygwin 1.5 somewhere else, so that it doesn't get included in 
mirrors.


2. Point everything referring to the old mirror system at the new 
location, presumably a different subtree on sourceware.org.  Then you 
can rely on the FTP/HTTP logs to determine how often people actually 
install these packages.


There's a core assumption here, which is that download volumes have 
dropped enough that going back to a single download server is sane.  If 
it turns out that download volume is unexpectedly high, though, well, 
that's answer enough, isn't it?


Re: nuke cygwin legacy?

2013-02-05 Thread Cygwin/X
On Tue, 5 Feb 2013 13:00:43 -0500, Christopher Faylor wrote:
 Because it is taking space on the web site and on sourceware.org and
 there is no good reason for it to be offered anymore.  If there are
 virtual machines running ME then, if they haven't installed Cygwin 1.5
 by now, there is no reason to assume that they will need it.
 
 Additionally, except for setup.exe, there have been no bug fixes or
 security fixes in 1.5 so we're offering buggy, insecure software on our
 site.

Which, in and of itself, is reason to drop it.  FWIW, I deleted legacy
files from Ports a few months ago without complaint. 


Yaakov


Re: nuke cygwin legacy?

2013-02-05 Thread Christopher Faylor
On Tue, Feb 05, 2013 at 07:57:58PM -0600, Yaakov wrote:
On Tue, 5 Feb 2013 13:00:43 -0500, Christopher Faylor wrote:
 Because it is taking space on the web site and on sourceware.org and
 there is no good reason for it to be offered anymore.  If there are
 virtual machines running ME then, if they haven't installed Cygwin 1.5
 by now, there is no reason to assume that they will need it.
 
 Additionally, except for setup.exe, there have been no bug fixes or
 security fixes in 1.5 so we're offering buggy, insecure software on our
 site.

Which, in and of itself, is reason to drop it.  FWIW, I deleted legacy
files from Ports a few months ago without complaint. 

Also, FWIW, it looks like setup-legacy was downloaded 14 times in the
last year.  I think that's a pretty good indication that it isn't
very popular.

cgf


Re: nuke cygwin legacy?

2013-02-05 Thread Cygwin/X
On Tue, 05 Feb 2013 20:56:42 +0100, Erwin Waterlander wrote:
 It doesn't matter that it is not secure.

Yes, it does.  IMHO it is irresponsible on our part to distribute
unmaintained or knowingly vulnerable software, and it reflects badly on
the Cygwin project.


Yaakov