Re: Simple way to terminate an executed command if it's waiting for standard input?

535 views
Skip to first unread message

Dumitru Ungureanu

unread,
Oct 17, 2012, 12:07:35 PM10/17/12
to golan...@googlegroups.com, rando...@gmail.com
Wrap it in a for {}, for which you have a time pkc function to schedule a break out. Maybe use time.Since().

random0x00

unread,
Oct 17, 2012, 1:26:46 PM10/17/12
to Dumitru Ungureanu, golan...@googlegroups.com
On 10/17/2012 06:07 PM, Dumitru Ungureanu wrote:
> Wrap it in a for {}, for which you have a time pkc function to schedule
> a break out. Maybe use time.Since().

Thanks for the suggestion, but what if it should take a long time to
finish? Such as when downloading a huge repo.

I was thinking about reading the standard output and specifically check
for the text "Username for "..., but would rather user a generic solution.

The main problem is that the child processes will have a
connected/working stdin, even tho cmd.Stdin is set to nil.

Is there any way to control the stdin of child processes. It would be
nice to close the standard input.

cheers /u

Cole Mickens

unread,
Oct 17, 2012, 2:07:13 PM10/17/12
to golan...@googlegroups.com, Dumitru Ungureanu, rando...@gmail.com
I don't understand this part, programmatically or conceptually.

Assuming this isn't a trivial answer, I would consult the `git` docs, there is probably a way to not prompt or set those sorts of things ahead of time via the environment or something.

It *is* possible to terminal a process you've started through an os.Command. I copy from Stdout and copy to an http responsewriter and will kill the process feeding the response writer under certain conditions. It's not really code I can share, but if you're still stuck I can pull it out and Play-paste it.

bryanturley

unread,
Oct 17, 2012, 2:49:49 PM10/17/12
to golan...@googlegroups.com, Dumitru Ungureanu, rando...@gmail.com
Wait for a return value from git?  I am fairly sure the ssh (I assume) login will time out and make git return an error code.
Might take 3+ minutes depending on what the timeout is set for.  git might use the default ssh timeouts check the ssh and git docs.

jorelli

unread,
Oct 17, 2012, 3:17:24 PM10/17/12
to golan...@googlegroups.com, rando...@gmail.com
Perhaps I am doing something wrong, but I have been playing with this for the past hour or so and I'm of the opinion that something, somewhere, is broken with regards to killing child processes, at least on OS X.  I am able to consistently crash my computer using os.Process.Release().

I have a solution that I believe should work in theory, but in practice the results are rather inconsistent.  It may work on your machine, but I can't get it to work consistently on mine; sometimes it works cleanly, sometimes it doesn't.

Use cmd.Start() instead of cmd.Run().  This will start the command but not wait for it.  To wait for the command to finish, you can use cmd.Wait().

Instead, if the command is running and you want to abort it, use cmd.Process.Kill() to end the command.  As for doing it with timeout handling, it's pretty straightforward go concurrency patterns; run the command in one goroutine and send a signal when it's finished, have another goroutine send a signal on a timeout, and use a select statement to chose the event that happens first.  The result on my machine is that sometimes the resources are freed properly, sometimes they aren't; that typically signals some kind of subtle race condition that I can't spot.

Here's a gist of a partial solution: https://gist.github.com/3907512

if you're running this in some other shell and you don't care that it mangles the TTY because it's not a login shell, then that'll work.  For me, I can't get a healthy shell to return from that.


On Wednesday, October 17, 2012 3:43:06 AM UTC-4, (unknown) wrote:
Hello.

The sample code will try to execute git clone a non-existent repo from github.
The command will output "Username for 'https://github.com':" and wait for user
input.

Sample code: http://play.golang.org/p/rY77eJs0Z9

Is there a simple way to terminate an executed command if it's waiting for
standard input.

If I try to execute "cat" it will terminate by itself if cmd.Stdin is not set to
os.Stdin.

Any thoughts on the matter are appreciated.


Cheers /u

random0x00

unread,
Oct 18, 2012, 12:09:59 PM10/18/12
to jorelli, bryan...@gmail.com, cole.m...@gmail.com, Dumitru Ungureanu, golan...@googlegroups.com
On 10/17/2012 09:17 PM, jorelli wrote:
> Perhaps I am doing something wrong, but I have been playing with this for the past hour or so and
> I'm of the opinion that something, somewhere, is broken with regards to killing child processes, at
> least on OS X. I am able to consistently crash my computer using os.Process.Release().
>
> I have a solution that I believe should work in theory, but in practice the results are rather
> inconsistent. It may work on your machine, but I can't get it to work consistently on mine;
> sometimes it works cleanly, sometimes it doesn't.
>
> Use cmd.Start() instead of cmd.Run(). This will start the command but not wait for it. To wait
> for the command to finish, you can use cmd.Wait().
>
> Instead, if the command is running and you want to abort it, use cmd.Process.Kill() to end the
> command. As for doing it with timeout handling, it's pretty straightforward go concurrency
> patterns; run the command in one goroutine and send a signal when it's finished, have another
> goroutine send a signal on a timeout, and use a select statement to chose the event that happens
> first. The result on my machine is that sometimes the resources are freed properly, sometimes they
> aren't; that typically signals some kind of subtle race condition that I can't spot.
>
> Here's a gist of a partial solution: https://gist.github.com/3907512
>
> if you're running this in some other shell and you don't care that it mangles the TTY because it's
> not a login shell, then that'll work. For me, I can't get a healthy shell to return from that.
>
>
> On Wednesday, October 17, 2012 3:43:06 AM UTC-4, (unknown) wrote:
>
> Hello.
>
> The sample code will try to execute git clone a non-existent repo from github.
> The command will output "Username for 'https://github.com':" and wait for user
> input.
>
> Sample code: http://play.golang.org/p/rY77eJs0Z9 <http://play.golang.org/p/rY77eJs0Z9>
>
> Is there a simple way to terminate an executed command if it's waiting for
> standard input.
>
> If I try to execute "cat" it will terminate by itself if cmd.Stdin is not set to
> os.Stdin.
>
> Any thoughts on the matter are appreciated.
>
>
> Cheers /u
>

Thank you for all the replies. I would like to give you some background about
what I'm trying to accomplish.

Basically I would like to evaluate if an import path is downloadable through
"go get".

Imagine if you could systematically check all import paths listed at
http://go.pkgdoc.org/-/index and label them, based on if they are "go-getable".

Being able to filter the import paths on pkgdoc.org based "CanGet" (go getable)
and "CanBuild" would be interesting, making the list more convenient to use.

I've uploaded a simple test case for those who want to try it out:
go get github.com/mewmew/status/cmd/gos

I tried to make the first sample as minimal as possible. The command I'm
actually running is "go get -d" (only download), which in turn executes git
clone.

It will download the provided import path, and all it's import dependencies. If
the import path or one of it's dependencies result in a 404, the "go get"
command will output "Username for..." and wait for user input.

That is the thing I want to find a clean solution to. Killing the "go get"
command based on a timeout would not work for large projects (possibly with many
dependencies), since they should take a longer time to download.

These are the things I've been playing around with, so far without any succes:

* Close os.Stdin before executing "go get".
* Use a fake io.Reader for cmd.Stdin with a Read method that always returns
io.EOF

I would like to stay away from specific solutions if possible, such as scanning
standard output for "Username for..." before killing the "go get" command.

Any and all suggestions are welcome :)

cheers /u

minux

unread,
Oct 18, 2012, 12:48:53 PM10/18/12
to random0x00, golan...@googlegroups.com, jorelli, cole.m...@gmail.com, bryan...@gmail.com, Dumitru Ungureanu

the reason that git askes for password even you've assigned
cmd.Stdin to null is that it is reading directly from your
terminal (ssh keyboard-interactive auth for example).

you need to use some pseudo terminal trickery to trick
it.it is certainly possible to do in go, but i think you can
use some existing unix command to do that. for example
script(1).

for git, though, you can set env. var $GIT_ASKPASS
to an external command (/bin/false for example)
to simulate the case when user doesn't provide
a pass. (git help config, look for core.askpass
for this feature). note that you can use $GIT_CONFIG
to provide git a config to override its behavior.

random0x00

unread,
Oct 18, 2012, 1:42:25 PM10/18/12
to minux, golan...@googlegroups.com, jorelli, cole.m...@gmail.com, bryan...@gmail.com, Dumitru Ungureanu
Thanks! Using GIT_ASKPASS worked flawlessly. And thanks for explaining why this was happening in
the first place.

The sample git repo has been updated and works after this fix.

What do you guys think about the idea of providing status information about go package repositories.

This is what I have in mind:

* Mark packages with CanGet if they are "go getable".
* Mark packages with CanBuild if they are able to compile with "go build"
- Some packages (mostly those using cgo) will not compile using "go build", but it could still
be a valuable indicator.
* Parse the package documentation and give some status regarding it's quality.
- This status should be based on godoc conventions.
- For instance: "Notice this comment is a complete sentence that begins with the name of the
element it describes."
ref: http://golang.org/doc/articles/godoc_documenting_go_code.html

Do you have any ideas that might be interesting to try when giving some rough status about the
maturity of a package?

* "go vet"?
* ...

Thanks for your input.

cheers /u

Reply all
Reply to author
Forward
0 new messages