I have resolved this now, see inline for comments and description.  Thanks for your 
help Jim and others, looks like stepping away from the problem and the code probably 
helped me the most, but your thoughts were definitely appreciated.

------------------------------------------------
On Thu, 2 Jan 2003 09:33:23 -0500, "Kipp, James" <[EMAIL PROTECTED]> wrote:

> > 
> > > > I am making a call to gpg on the command line, a couple of
> > > > the parameters that gpg will accept are file descriptor
> > > > numbers that it then writes to, and I would like to capture
> > > > that output and then read from it.
> > > >
> > > > I have successfully made it read directly from a file on the
> > > > local file system like so:
> > > >
> > > > my $pass_fh = IO::File->new('/path/to/localfile');
> > > > fcntl $pass_fh, F_SETFD, 0; # don't close over exec
> > > > my $pass_fd = $pass_fh->fileno(); # get the file descriptor number
> > > >
> > > > and then calling gpg on the command line like so:
> > > >
> > > > gpg [other options here, etc.] --passphrase-fd $pass_fd [etc.]
> 
> Ok, let me make sure I understand. You probably know more about this stuff
> than i do, but maybe discussion will lead you to a resolution. I have
> strayed away from C since i started with perl, but i I do have a copy of
> steven's "advance Programmin..." here so maybe it can  help us.
> 
> Now when you say you are calling gpg on the command line, how does it know
> what $pass_fd is? is this a  fork and exec? and env variable ? , system
> call?  
> 

gpg takes a command line parameter --pass-fd that takes one argument, a file 
descriptor number, that it then uses to read information from, so one way to have it 
read from a file on the system rather than from stdin is to open a file directly then 
pass it the file descriptor of your open file. This is what I had working with the 
pass-fd directly opening a file. gpg also takes 2 other switches --status-fd and 
--logger-fd that it writes other output to, and again each of these takes a file 
descriptor but rather than have that output go into a file I wanted to receive it in 
my perl program from a handle.  Which is why I needed to generate a file descriptor to 
pass gpg on the command line, but without first associating it with a file.  I am 
calling the command line through a 'system' call, which basically just wraps fork/exec 
(which caused another problem since we are running this code in a daemon that preforks 
with a waitpid that had a child signal handler...eck, but worked aroun!
d that with one of the very few valid uses of a 'local').

> > > >
> > > > Which works very well. And I can successfully create a new
> > > > file handle,
> > > >
> > > > my $logger_fh = IO::Handle->new();
> > > >
> > > > And then presumably could use the same methods as above, but
> > > > the file handle has to be open to determine its number and
> > > > then to pass the file descriptor to the command line. Which I
> > > > determined is what fdopen is for, so now to my question(s)
> > > > (finally, sorry about that) how do I determine what the FD
> > > > (file descriptor number) should be that I pass to fdopen? Is
> > > > this an arbitrary number (not 0,1,2), can I have the system
> > > > suggest a number?  If the program were to choose the same
> > > > number in different forks would it matter?  Is there a better
> > > > more appropriate way of handling all of this?  (Besides using
> > > > one of the GPG modules from CPAN, which I would absolutely
> > > > love, but after spending a number of days checking them out,
> > > > each one has one or more quirks which doesn't allow it to
> > > > work in our app.)
> > > 
> 
> > I had seen that and been through it a couple times, for 
> > another issue, but went through it again, can't hurt right 
> > ;-), but all of the examples seem to open an already existing 
> > file, creating a file, or using a handle as part of a pipe.  
> > It did give me the idea of trying to open a new file handle 
> > with the "-|" syntax to open but that just errored, and left 
> > $! blank which is odd to me...
> 
> what about the part where it describes grabbing the fd from the sytem proc
> files and/or env variables. the c sys functions like dup and fnctl operate
> on the kernel's proc table-> fd table (and it gets hairy from here :-) 

After looking through and trying the F_DUPFD stuff from fcntl I came to the result 
that it still required a file descriptor on an already open filehandle, which again 
could only happen with a file at the other end or from one of the standard IO handles, 
so still back to the point of being able to create an FD from thin air.

Here
> is a snip of what part i am talking about:
> ------
> If you really want the new program to gain access to a filehandle other than
> these three, you can, but you have to do one of two things. When Perl opens
> a new file (or pipe or socket), it checks the current setting of the $^F
> ($SYSTEM_FD_MAX) variable. If the numeric file descriptor used by that new
> filehandle is greater than $^F, the descriptor is marked as one to close.
> Otherwise, Perl leaves it alone, and new programs you exec will inherit
> access.
> 
> It's not always easy to predict what file descriptor your newly opened
> filehandle will have, but you can temporarily set your maximum system file
> descriptor to some outrageously high number for the duration of the open: 
> 
> # open file and mark INPUT to be left open across execs
> { 
>     local $^F = 10_000;
>     open(INPUT, "< /etc/motd")   or die "/etc/motd: $!";
> } # old value of $^F restored on scope exit
> 
> Now all you have to do is get the new program to pay attention to the
> descriptor number of the filehandle you just opened. The cleanest solution
> (on systems that support this) is to pass a special filename that equates to
> a file descriptor. If your system has a directory called /dev/fd or
> /proc/$$/fd containing files numbered from 0 through the maximum number of
> supported descriptors, you can probably use this strategy. (Many Linux
> operating systems have both, but only the /proc version tends to be
> correctly populated. BSD and Solaris prefer /dev/fd. You'll have to poke
> around at your system to see which looks better for you.) First, open and
> mark your filehandle as one to be left open across execs as shown in the
> previous code, then fork like this: 
> if ($pid = fork) { wait } 
> else {
>     defined($pid)                or die "fork: $!";
>     $fdfile = "/dev/fd/" . fileno(INPUT);
>     exec("cat", "-n", $fdfile)   or die "exec cat: $!";
> }
> --------
> ...... 
> and a litte further down, using the env to get at it:
> 
> -----------
> 
> If your system doesn't support file descriptors named in the filesystem, and
> you want to pass a filehandle other than STDIN, STDOUT, or STDERR, you can
> still do so, but you'll have to make special arrangements with that program.
> Common strategies for this are to pass the descriptor number through an
> environment variable or a command-line option. 
> 
> If the executed program is in Perl, you can use open to convert a file
> descriptor into a filehandle. Instead of specifying a filename, use "&="
> followed by the descriptor number. 
> 
> if (defined($ENV{input_fdno}) && $ENV{input_fdno}) =~ /^\d$/) { 
>     open(INPUT, "<&=$ENV{input_fdno}")
>         or die "can't fdopen $ENV{input_fdno} for input: $!";
> }
> 
> ----------
> 
>  > 
> > Right, but I am not sure how to get an existing FD without 
> > attaching it to an actual normal file through an open call.  
> > the fdopen essentially attaches a separate handle to the 
> > existing file descriptor, but I need to know how to generate 
> > a file descriptor without attaching it to a file on the 
> > filesytem, if this can be done at all, at least at Perl's 
> > high level, as this is seemingly done by 'pipe'.
> 
> would you be open to writing this in C ?
> 
> 
> > 
> > > So i assume the open method in IO::File is really the open2
> > > system call.
> > 
> > I believe IO::File is just a sub class of IO::Handle, and 
> > fdopen just wraps a regular open call.
> 
> no, i think it wraps the actual C fdopen call
> 
> > 
> > > Also are you loading the Fcntl module in the program so you 
> > get all of the
> > > constants from cntl.h? 
> > 
> > Yes, that is how I am setting the filehandle to stay open 
> > through the exec (system in my case). But I am not familar 
> > with what that gets me as I don't make much of a C programmer 
> > (yet hopefully ;-)), any suggestions on what I can use from 
> > it for this problem?
> 
> not off the top of my head, but I just cracked open the book....
> 
> 

So basically what I determined from looking at one of the gpg modules I was trying to 
emulate was basically that I was thinking about this wrong and what I needed was 
actually a pipe. The odd part about this is that generally you have control of both 
ends of the pipe, but in this case it was up to me to create both ends of the pipe and 
then pass one end of the pipe to gpg to let it control.  So basically I created two 
file handles, turned them into a pipe, turned off buffering, turned off blocking IO, 
turned on the flag to keep them open across execs, then got the file descriptor of the 
one end of the pipe and then passed that end of the pipe to gpg on the command line. 
Then just read from the other end in the original program.  What I was struggling with 
was the notion of a pipe having two ends that I create, but where I only needed to 
read from one so it didn't seem like a pipe was appropriate, despite the fact that 
obviously it was because what I eventually realized was tha!
t I was passing off one end of the pipe.

Again thanks for the help and hopefully this description can help someone in the 
future....I know I have learned plenty in the last week or so......

http://danconia.org 

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to