Allegro.cc - Online Community

Allegro.cc Forums » Off-Topic Ordeals » [C#/.NET] Starting Another Process And Writing To StandardInput (stdin)

This thread is locked; no one can reply to it. rss feed Print
 1   2 
[C#/.NET] Starting Another Process And Writing To StandardInput (stdin)
bamccaig
Member #7,536
July 2006
avatar

I'm having trouble getting this to work and hope that one of you have done this before in .NET. The code I have seems like it should work, but unfortunately I can't directly test it because it's being executed by a subversion hook script (post-commit.bat)... :( Essentially, my program is like a wrapper for svn export. I'm thinking that what's happening is svn is prompting for confirmation to accept the SSL certificate, but since it's an automated process there is no user to respond. As a result, I'm attempting to simulate the user's response by writing to svn's stdin stream.

I'm starting svn with a System.Diagnostics.ProcessStartInfo instance and System.Diagnostics.Process.Start() as follows...

1using System;
2using System.Diagnostics;
3using System.IO;
4 
5.
6.
7.
8 
9int svn_timeout = (int)Math.Round(TimeSpan.FromMinutes(1).TotalMilliseconds, 0);
10 
11Process svn = null;
12ProcessStartInfo svn_startinfo = new ProcessStartInfo("svn", "export ...");
13 
14psi.RedirectStandardError = true;
15psi.RedirectStandardInput = true;
16psi.RedirectStandardOutput = true;
17psi.WorkingDirectory = Environment.CurrentDirectory;
18psi.UseShellExecute = false;
19 
20// Try to start svn.
21try
22{
23 // Start svn.
24 svn = Process.Start(svn_startinfo);
25}
26catch(Exception)
27{
28 // Print/log error and terminate with -1 exit status.
29}
30 
31// Wait for svn to exit.
32if(!svn.WaitForExit(svn_timeout))
33{
34 // Print/log error and terminate with -1 exit status.
35}
36 
37// Check svn exit status.
38if(svn.ExitCode != 0)
39{
40 // Print/log error and terminate with -1 exit status.
41}
42 
43// Print/log success.

I think it should work to WriteLine() a response to the StandardInput StreamWriter of the svn process.

1// |<--- svn = Process.Start()
2 
3/*
4 * I'd like to change this to only write if svn prompts. That should probably
5 * involve reading from svn.StandardOutput and looking for a particular message,
6 * which I don't currently have because my system already accepted the certificate.
7 * There is a WaitForInputIdle() method of the Process class, but the summary
8 * suggests that it is for GUI applications only.
9 */
10try
11{
12 // (t)emporarily accept certificate.
13 svn.StandardInput.WriteLine("t");
14 
15 // Flush buffer to stream.
16 svn.StandardInput.Flush();
17}
18catch(Exception)
19{
20 // Print/log error and terminate with -1 exit status.
21}
22 
23// svn.WaitForExit() --->|

I've added log messages before and after the above code where I write to the stdin stream. Both are logged, but nothing more. If svn fails to start, times out, or exits with a non-zero exit status that should be logged. If svn succeeds that should be logged. Instead, I get nothing to stderr, stdout, and nothing more to my log file. And my process just seems to hang there doing nothing.

I wonder if maybe the way I'm launching svn is wrong. Useful posts on the matter seem few and far between, but I did find one that suggested that the application being written to was terminating itself before the write could happen... Maybe something about the way I'm starting svn tells it to terminate if it starts to wait...

Does anybody have experience with this in .NET?

CGamesPlay
Member #2,559
July 2002
avatar

Quote:

I'm thinking that what's happening is svn is prompting for confirmation to accept the SSL certificate, but since it's an automated process there is no user to respond. As a result, I'm attempting to simulate the user's response by writing to svn's stdin stream.

If this really is the case, then the better solution is to permanently accept the certificate.

Quote:

That should probably involve reading from svn.StandardOutput and looking for a particular message, which I don't currently have because my system already accepted the certificate.

Remove your %APPDATA%\​Subversion directory.

Your best best would be to log on as the user that the subversion server is running as, permanently accept the certificate, and be done with it.

[append]

After experimentation, it seems that the certificate is stored in %APPDATA%\​Subversion\​auth\​svn.ssl.server\​<hash>. Using that information, you should be able to copy the certificate into the target configuration.

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

bamccaig
Member #7,536
July 2006
avatar

CGamesPlay said:

If this really is the case, then the better solution is to permanently accept the certificate.

...

Your best best would be to log on as the user that the subversion server is running as, permanently accept the certificate, and be done with it.

I agree, that is an excellent solution, but unfortunately I hit another snag there. I don't know why, but my Subversion hook (which is executing my program, which then executes svn) is being executed as a "phantom" user (and I just made that up so it has no specific meaning). The USERNAME environment variable is apparently an empty string. I haven't figured that out yet, since every workstation I've tested (as opposed to the development server) has an actual user executing it... :-/ So it's not going to be quite so easy, but I would certainly like to figure out why the USERNAME variable is empty... :-/ Does anybody know where the Subversion hook scripts get their user credentials from? :-/

CGamesPlay said:

After experimentation, it seems that the certificate is stored in %APPDATA%\​Subversion\​auth\​svn.ssl.server\​<hash>. Using that information, you should be able to copy the certificate into the target configuration.

That sounds like a nice solution, but unfortunately the APPDATA environment variable is also empty when the hook script is executed. :( So I don't think Subversion is creating any kind of user data...

CGamesPlay
Member #2,559
July 2002
avatar

So it's running as NETWORK SERVICE or NETWORK GUEST or some such... Perhaps you can create the configuration in All Users\Subversion and then set the environment variable yourself? Sounds easier.

Oh, and subversion hook scripts run under the subversion server process. If that's IIS, then it's going to be the NETWORK SERVICE or NETWORK GUEST accounts.

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

bamccaig
Member #7,536
July 2006
avatar

We're running VisualSVN Server, which AFAIK is using Apache. :-/ Personally, I wanted to just install Subversion and Apache myself...

CGamesPlay
Member #2,559
July 2002
avatar

Here's one:

svn export --config-dir=C:\svnconfig ...

Got that out of svn help export. Should fix you up, right?

Also, there's a --non-interactive option, but that will probably cause it to fail silently.

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

bamccaig
Member #7,536
July 2006
avatar

I was looking at that, but I wasn't sure the --config-dir is the %APPDATA%\Subversion equivalent... I tried searching for confirmation, but couldn't find it... In hindsight I suppose it should be obvious, but testing is difficult and abstract through a hook script... :-X Plus I've been pretty tired these past few days.

CGamesPlay
Member #2,559
July 2002
avatar

So, does it work?

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

bamccaig
Member #7,536
July 2006
avatar

CGamesPlay
Member #2,559
July 2002
avatar

Yeah, so I'm going to keep bumping this thread so when it doesn't work you can just reply instead of starting a new thread :P

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

bamccaig
Member #7,536
July 2006
avatar

Heh, I'm now at work... Now I need to figure out how to go about testing this...

** EDIT **

It's taking longer than expected. Was having problems getting the service process to run as a custom user with restricted access and ownership of the desired directories. Hopefully I can confirm whether this --config-dir option solves my problem in the next hour.

I'm still curious why writing to stdin didn't work though... :-/ It was a poor solution to this problem, but it would be nice to understand how it works to write to stdin of another process like that for future reference.

** EDIT **

It just occurred to me to just try svn log on my local machine with a new --config-dir option specified to see if it would create the directory and prompt me again for authentication and the SSL certificate. It did so I'm pretty confident that this solution will work... At least, if nothing else goes wrong. :P

CGamesPlay
Member #2,559
July 2002
avatar

Quote:

I'm still curious why writing to stdin didn't work though... :-/ It was a poor solution to this problem, but it would be nice to understand how it works to write to stdin of another process like that for future reference.

On Linux, password prompts do not read from stdin: instead, they read from the owner terminal. This means you can't echo password | ssh host. Something similar may be going on for subversion.

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

bamccaig
Member #7,536
July 2006
avatar

I'm unsure if the config directory is working or not... svn appears to be still prompting for confirmation, which doesn't seem to make sense because if a human user executes an svn command while pointing to the created Subversion client config directory they are not prompted to accept the certificate... :'(

CGamesPlay said:

On Linux, password prompts do not read from stdin: instead, they read from the owner terminal. This means you can't echo password | ssh host. Something similar may be going on for subversion.

Well I wasn't actually writing the password to svn's stdin. Instead, I was writing a 't' character to temporarily accept the SSL certificate, which I just confirmed works from the command line in Windows by piping it.

svn log url
<svn prompt for confirmation>t
<output>
svn log url
<svn prompt for confirmation>t
<output>
echo t | svn log url
<output>

What exactly is the difference between reading from the owner terminal and stdin? I think that I was under the impression that the owner terminal would be writing to stdin, though I admit that my understanding of terminals is abstract and incomplete... :-/

CGamesPlay
Member #2,559
July 2002
avatar

Pipe the output of the svn export to a temporary file so you can see what exactly it is outputting. Also, have you used --non-interactive?

Quote:

What exactly is the difference between reading from the owner terminal and stdin?

One can be redirected to a file, and the other is the terminal? :P I don't know if Windows works the same way, but it probably doesn't.

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

bamccaig
Member #7,536
July 2006
avatar

It seems to be working (at least in part) to specify the --config-dir option, but now I'm getting the following output to svn's stderr stream (by memory):

Authentication realm: (url) authentication_realm_name

It doesn't really resemble a prompt, but there is no further output and the program seems to hang there... When a colleague with server access executes the command from the Command Prompt it executes successfully and the above message isn't displayed (unless stderr isn't display by default in Windows, in which case I don't know if this message is written to stderr for the colleague). If it's not a prompt, then my only explanation is that it's actually just Apache being informative and my debugging code is blocking...

// Debugging code to try to see why/if svn is failing.

string line;

Program.StartLog("svn stderr:\n\n");
while((line = svn.StandardError.ReadLine()) != null)
  Program.Log(String.Format("{0}\n", line));

Program.StartLog("svn stdout:\n\n");
while((line = svn.StandardOutput.ReadLine()) != null)
  Program.Log(String.Format("{0}\n", line));

Does anybody know if this is the right/wrong way to read from the streams in C#? I've noted in examples that it seems the Flush() or Close() method needs to be called for some reason, but I don't really understand how you would go about reading again (as some programs would dictate) if the stream is closed... :-/ I don't really understand how to check if there is data to be read from a particular StreamReader; if so read it line by line and process it; and if not continue on with the program...

** EDIT **

I removed the above code from the program (I think) and it's still blocking on the svn process... :-/ I can't imagine any reason for svn to take more than a second to execute (it's only processing one file) unless it's prompting...

CGamesPlay said:

Pipe the output of the svn export to a temporary file so you can see what exactly it is outputting.

I'm not sure how I would do that in C#... :-/

CGamesPlay said:

Also, have you used --non-interactive?

I originally wanted to use that option, but before I understood the --config-dir option I was trying to figure out how to respond to a prompt... I guess now I can go back to --non-interactive mode and hope that svn either succeeds or writes something useful to stderr.

CGamesPlay
Member #2,559
July 2002
avatar

Quote:

I'm not sure how I would do that in C#... :-/

You would not use C#, you would use the shell's output piping: command > program.log

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

bamccaig
Member #7,536
July 2006
avatar

CGamesPlay said:

You would not use C#, you would use the shell's output piping: command > program.log

Are you talking about svn's output when executed by my program or by my colleague from the command line? :-/ My colleague copied the output from svn to me and it was the standard successful output...

prompt>svn export arguments flags file Export complete.

From my program, svn is started with System.Diagnostics.Process.Start(ProcessStartInfo). The ProcessStartInfo instance has a FileName property (i.e. the executable) and an Arguments property. I'm not sure if it would work to add redirection arguments (especially with the UseShellExecute property set to false)...

I did try reading from the svn output streams and writing them to files:

1StreamWriter svn_stderr = null;
2StreamWriter svn_stdout = null;
3 
4try
5{
6 svn_stderr = new StreamWriter(@".\svn.stderr");
7 svn_stderr.Write(svn.StandardError.ReadToEnd());
8}
9catch(Exception)
10{
11 Program.PrintError(msg = "Failed to redirect svn stderr.\n");
12 Program.StartLog(msg);
13}
14finally
15{
16 svn_stderr.Close();
17 svn_stderr = null;
18}
19 
20try
21{
22 svn_stdout = new StreamWriter(@".\svn.stdout");
23 svn_stdout.Write(svn.StandardOutput.ReadToEnd());
24}
25catch(Exception)
26{
27 Program.PrintError(msg = "Failed to redirect svn stdout.\n");
28 Program.StartLog(msg);
29}
30finally
31{
32 svn_stdout.Close();
33 svn_stdout = null;
34}

Which seems to work on my local system, but is apparently never reached on the server... :-/ If there was an uncaught exception (while being executed by a user with no logon) what should happen to my program...? Would Windows terminate it or would it just stop executing and hang?

CGamesPlay
Member #2,559
July 2002
avatar

You have a batch file, called post-commit.bat. In it, you run svn export <parameters> > C:\WINDOWS\Temp\post-commit.log You then review post-commit.log and find why your stuff doesn't work.

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

bamccaig
Member #7,536
July 2006
avatar

CGamesPlay said:

You have a batch file, called post-commit.bat. In it, you run svn export <parameters> > C:\WINDOWS\Temp\post-commit.log You then review post-commit.log and find why your stuff doesn't work.

That's brilliant! :o I can't believe I didn't think of running svn from the batch file... :-[

MiquelFire
Member #3,110
January 2003
avatar

Didn't I say that in another one of your threads? ???

---
Febreze (and other air fresheners actually) is just below perfumes/colognes, and that's just below dead skunks in terms of smells that offend my nose.
MiquelFire.red
If anyone is of the opinion that there is no systemic racism in America, they're either blind, stupid, or racist too. ~Edgar Reynaldo

bamccaig
Member #7,536
July 2006
avatar

MiquelFire said:

Didn't I say that in another one of your threads? ???

I'm not sure... ??? Not that I can find... You did suggest that I call a more powerful script from my batch file, but instead I've opted to write a simple C# program to handle it. That's all I can find...

MiquelFire
Member #3,110
January 2003
avatar

I think the more powerful program was meant for if you need to delete a file, as if you delete/rename in SVN, the exported copy would still have the last version, and if it's a file that needs to be deleted...

---
Febreze (and other air fresheners actually) is just below perfumes/colognes, and that's just below dead skunks in terms of smells that offend my nose.
MiquelFire.red
If anyone is of the opinion that there is no systemic racism in America, they're either blind, stupid, or racist too. ~Edgar Reynaldo

bamccaig
Member #7,536
July 2006
avatar

By executing svn from the batch file, the following was output to stderr:

svn: PROPFIND request failed on 'file' svn: PROPFIND of 'file': authorization failed (url)

stdout was empty. :-/

BAF
Member #2,981
December 2002
avatar

Personally, I would check out a working copy, use htaccess do deny any access to anything .svn, and then just issue a svn update.

CGamesPlay
Member #2,559
July 2002
avatar

You used --config-dir and --non-interactive? You should run it manually and add in the user and password information, since it seems it couldn't ask you for them.

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

 1   2 


Go to: