views:

181

answers:

2

I'm trying to write a little lib which generates a keypair using open4, is this the best way of dealing with system calls with multiple prompts?

require 'rubygems'
require 'open4'
Open4::popen4("sh") do |pid, stdin, stdout, stderr|
  stdin.puts "openssl genrsa -des3 -out tmp_priv.pem 2048" 
  stdin.puts "1234" 
  stdin.puts "1234"
  stdin.close
end
Open4::popen4("sh") do |pid, stdin, stdout, stderr|
  stdin.puts "openssl rsa -in tmp_priv.pem -out tmp_public.pem -outform PEM -pubout"
  stdin.puts "1234"
  stdin.close
end
Open4::popen4("sh") do |pid, stdin, stdout, stderr|
  stdin.puts "cat tmp_priv.pem  tmp_public.pem >> tmp_keypair.pem" 
  stdin.close
end
+1  A: 

I'm not sure your example is going to do what you want. If run as in your question openssl is going to open /dev/tty and it will end up prompting the user despite the pipe. It won't see the 1234.

If instead you run:

openssl genrsa -passout stdin ...

then in that case it will read stdin but it will only need the output file password once. And to answer the question you asked, yes, that's a good way, though it's not a system call.

It's also quite rare on Unix-like systems to need to fake up program input in the first place. You might want to reread the openssl(1ssl) and genrsa(1ssl) man pages; they will note various different password source options.

DigitalRoss
The code does seem to run fine as it is, although -passin or -passout seem like what I need, thanks
MatthewFord
A: 

I've found that calling popen4 with the "block" syntax just doesnt work.

But what i've found works is to do this:

harp: > cat sample/simple.rb
require "open4"

pid, stdin, stdout, stderr = Open4:open4 "sh"

stdin.puts "echo 42.out"
stdin.puts "echo 42.err 1>&2"
stdin.close

ignored, status = Process::waitpid2 pid

puts "pid : #{ pid }"
puts "stdout : #{ stdout.read.strip }"
puts "stderr : #{ stderr.read.strip }"
puts "status : #{ status.inspect }"
puts "exitstatus : #{ status.exitstatus }"


harp: > ruby sample/simple.rb
pid : 17273
stdout : 42.out
stderr : 42.err
status : #<Process::Status: pid=17273,exited(0)>
exitstatus : 0

Which will work with passing the stdin. But at the same time, also giving back the stdout and stderr. And it avoided the exception:

in 'write': closed stream (IOError)

too. So this seems the best way to use popen4.

For other examples, see the README: http://github.com/ahoward/open4