[comp.unix.xenix] How to determine file being redirected to in C

rac@sherpa.UUCP (Roger A. Cornelius) (02/27/89)

I've been searching for the past several days for references to this,
but haven't been able to find it.  I know I've read it somewhere, or
maybe saw it here.  Anyway, can someone tell me how to determine (in C)
if output is being redirected, or more precisely, how to determine the
file output is being redirected to.  The cat command does this (at
least the Xenix version of cat, I don't think the BSD version does),
i.e.:

	cat catfile > catfile

produces the error "cat: input catfile is output".
Any help appreciated.

Roger      rac@sherpa
           uunet!sherpa!rac

klee@daisy.UUCP (Ken Lee) (02/28/89)

In article <10@sherpa.UUCP> rac@sherpa.UUCP (Roger A. Cornelius) writes:
>  Anyway, can someone tell me how to determine (in C)
>if output is being redirected, or more precisely, how to determine the
>file output is being redirected to.

In BSD UNIX, you can fstat(2) stdout to determine if the output is a
file or terminal (or whatever) and, what inode number it has.  Since
several file names can have the same inode, you can't tell exactly
what file name was specified, but the inode number should be enough
information for cat and other such applications.

Ken Lee
-- 
klee@daisy.uucp
Daisy Systems Corp., Interactive Graphics Tools Dept.

curci@stat.uucp (Ray Curci (scri)) (02/28/89)

In article <10@sherpa.UUCP> rac@sherpa.UUCP (Roger A. Cornelius) writes:
>...  Anyway, can someone tell me how to determine (in C)
>if output is being redirected, or more precisely, how to determine the
>file output is being redirected to.  
>Roger      rac@sherpa
>           uunet!sherpa!rac

You may want to investigate the isatty() function call.  I believe that
you can use something like:  isatty(stdout)  which will tell you if
standard out is going to a terminal (the usual case), or if it has been
redirected via a pipe or into a file.

ray curci
florida state university supercomputer institute
curci@stat.fsu.edu,  curci@nu.cs.fsu.edu

guy@auspex.UUCP (Guy Harris) (02/28/89)

>Anyway, can someone tell me how to determine (in C) if output is being
>redirected, or more precisely, how to determine the file output is
>being redirected to.  The cat command does this (at
>least the Xenix version of cat, I don't think the BSD version does),

Yes, the BSD version does.  So does the System V Release 3 version, and
I think every version since the V7 version does. 

However:

	1) It doesn't "determine that output is being redirected"; all
	   it does is determine that one of the input files is the same
	   as the output file.

	2) It doesn't do the latter by finding the path name for any of
	   the files; it does an "fstat" on the file (descriptor) in
	   question, and compares the "st_dev" and "st_ino" fields of
	   the results.  That's all it needs to do, since the "st_dev"
	   and "st_ino" fields are sufficient to uniquely identify a
	   file; it doesn't have to find the file's name (and that
	   wouldn't help anyway, since the same file can have more than
	   one name).

So if you really want the name of the file, you'll have to work *very*
hard to get it (you basically have to scan all mounted file systems, or
at least the ones whose mount points have an "st_dev" that matches that
of the file in question), and you may not get it anyway if the input is
a pipe, or a file that has been unlinked.

jbayer@ispi.UUCP (Jonathan Bayer) (02/28/89)

In article <10@sherpa.UUCP> rac@sherpa.UUCP (Roger A. Cornelius) writes:
>I've been searching for the past several days for references to this,
>but haven't been able to find it.  I know I've read it somewhere, or
>maybe saw it here.  Anyway, can someone tell me how to determine (in C)
>if output is being redirected, or more precisely, how to determine the
>file output is being redirected to.  The cat command does this (at



Use the stat() and fstat() functions, then compare the inode numbers 
in the structure.  If they are the same then the two files are identical.


JB
-- 
Jonathan Bayer			      Beware: The light at the end of the
Intelligent Software Products, Inc.	      tunnel may be an oncoming dragon
19 Virginia Ave.				...uunet!ispi!jbayer
Rockville Centre, NY 11570  (516) 766-2867    jbayer@ispi.UUCP

frankb@usource.UUCP (Frank Bicknell) (02/28/89)

In article <10@sherpa.UUCP>, rac@sherpa.UUCP (Roger A. Cornelius) writes:
> ... can someone tell me how to determine (in C) if output is
> being redirected, or more precisely, how to determine the
> file output is being redirected to. ...  

I presume you know how to determine whether the std* is directed
to a terminal with isatty().

Your request seemed to hint at being able to determine whether
the stdout and a file given in *argv[] were the same file.
One way which comes to mind (this might be the hard way) is
to use stat() on the file and fstat() on stdout.  Then you
compare st_ino and st_dev in both returned structures.  If both
sets match (ie r.st_ino == f.st_ino && r.st_dev == f.st_dev)
then they must be the same file.  (Network fans: is this true
for remotely-mounted filesystems?)

As for the general case of finding out the name of the file to
which output (input) has been redirected to (from), that's more
difficult, I think.  The only way which comes to mind is to take
that inode number and device id from fstat() and run system
("ncheck -i inode filesystem") on them.  This takes a while, but
beats rewriting the code to search through the directory
structure (and your code would take as long as theirs, I would
assume).
-- 
Frank Bicknell; 1405 Main St, Ste 709; Sarasota, FL 34236-5701
killer!usource!frankb

md@sco.COM (Michael Davidson) (03/01/89)

In article <10@sherpa.UUCP> rac@sherpa.UUCP (Roger A. Cornelius) writes:
>Anyway, can someone tell me how to determine (in C)
>if output is being redirected, or more precisely, how to determine the
>file output is being redirected to.

You can determine the type of file associated with your
standard output (or any other file descriptor) by using
fstat(). This will tell you the type of file (regular,
block special, character special, fifo) and the device
and inode #.

There is no easy way of going from a device and inode #
to a pathname, short of searching through the entire
directory hierarchy on the appropriate filesystem (or
invoking ncheck to do it for you) - remember also that
the file may have many links to it or, by the time you
go looking for the path name, it may have none....

cat simply checks whether it's output has been redirected
to a regular file and, if it has, does a stat() of each of
it's input files, comparing device and inode # with that
of the output file - if it finds a match it reports the
error "cat: input foo is output".

daveh@marob.MASA.COM (Dave Hammond) (03/01/89)

In article <10@sherpa.UUCP> rac@sherpa.UUCP (Roger A. Cornelius) writes:
>..................  Anyway, can someone tell me how to determine (in C)
>if output is being redirected, or more precisely, how to determine the
>file output is being redirected to.  The cat command does this [...]
>
>	cat catfile > catfile
>produces the error "cat: input catfile is output".

1. Determine if your stdout has been redirected (isatty(fileno(stdout)) will
   fail if stdout is redirected).

2. Do an fstat() on fileno(stdout), and a stat() on the other file in question.

3. Compare the st_ino and st_dev members of the two stat structures.  If the
   inode (st_ino) and device-of-directory-entry (st_dev) for the two match,
   your standard output and the other file are the same.

Hope this helps.

--
Dave Hammond
daveh@marob.masa.com

arnold@mathcs.emory.edu (Arnold D. Robbins {EUCC}) (03/02/89)

>In article <10@sherpa.UUCP> rac@sherpa.UUCP (Roger A. Cornelius) writes:
>>  Anyway, can someone tell me how to determine (in C)
>>if output is being redirected, or more precisely, how to determine the
>>file output is being redirected to.  The cat command does this (at

In article <475@ispi.UUCP> jbayer@ispi.UUCP (Jonathan Bayer) writes:
>Use the stat() and fstat() functions, then compare the inode numbers 
>in the structure.  If they are the same then the two files are identical.

Rather, compare the device and inode numbers, and if both are the same
the two files are really the same file.  Two files on two different
filesystems (i.e. devices) can both have the same inode numbers.
-- 
"Unix is a Registered  | Arnold Robbins -- Emory University Computing Center
Bell of AT&T Trademark | DOMAIN: arnold@unix.cc.emory.edu		
Laboratories."         | UUCP: gatech!emory!arnold	PHONE:	+1 404 727-7636
        -- Donn Seeley | BITNET: arnold@emoryu1		FAX:	+1 404 727-2599

guy@auspex.UUCP (Guy Harris) (03/02/89)

>In BSD UNIX, you can fstat(2) stdout to determine if the output is a
>file or terminal (or whatever) and, what inode number it has.

In *any* UNIX worth of the name, you can do that; I know of none so
feeble-minded that they don't allow that.

>Since several file names can have the same inode, you can't tell exactly
>what file name was specified, but the inode number should be enough
>information for cat and other such applications.

It's certainly almost enough for "cat", since all it cares about is
whether any of the input files are the same as the output file or not. 
The inode number isn't enough, however; you also need the file system
identifier, which is in the "st_dev" field.  If two files have the same
"st_dev" and "st_ino", they're the same file, otherwise not.

guy@auspex.UUCP (Guy Harris) (03/02/89)

 >You may want to investigate the isatty() function call.  I believe that
 >you can use something like:  isatty(stdout)  which will tell you if
 >standard out is going to a terminal (the usual case), or if it has been
 >redirected via a pipe or into a file.

We've been here before.  No, "isatty(stdout)" won't tell you anything of
the sort.  "isatty" takes a file descriptor, *not* a standard I/O
"FILE *".  "isatty(fileno(stdout))", or "isatty(1)", will tell you
whether the standard output is a tty or not.

guy@auspex.UUCP (Guy Harris) (03/02/89)

 >Use the stat() and fstat() functions, then compare the inode numbers 
 >in the structure.  If they are the same then the two files are identical.

Wrong.  If the inode numbers (st_ino) *AND* the file system IDs (st_dev)
are the same, then the two files are identical.  If just the inode
numbers are the same, you can't conclude anything about whether the
files are the same or not.  They could have the same inode number but be
on two different file systems; inode numbers are *not* unique across
file systems.

jbayer@ispi.UUCP (Jonathan Bayer) (03/02/89)

In article <1105@auspex.UUCP> guy@auspex.UUCP (Guy Harris) writes:
}
} }Use the stat() and fstat() functions, then compare the inode numbers 
} }in the structure.  If they are the same then the two files are identical.
}
}Wrong.  If the inode numbers (st_ino) *AND* the file system IDs (st_dev)
}are the same, then the two files are identical.  If just the inode
}numbers are the same, you can't conclude anything about whether the
}files are the same or not.  They could have the same inode number but be
}on two different file systems; inode numbers are *not* unique across
}file systems.

I stand corrected.  Working on one filesystem for a while tends to make
one forget that the inodes can come from multiple filesystems.


JB
-- 
Jonathan Bayer			      Beware: The light at the end of the
Intelligent Software Products, Inc.	      tunnel may be an oncoming dragon
19 Virginia Ave.				...uunet!ispi!jbayer
Rockville Centre, NY 11570  (516) 766-2867    jbayer@ispi.UUCP

guy@auspex.UUCP (Guy Harris) (03/03/89)

>One way which comes to mind (this might be the hard way) is
>to use stat() on the file and fstat() on stdout.

The only "easier" way might be to open the file first and do an "fstat"
on it as well; it's probably slightly more efficient.

>Then you compare st_ino and st_dev in both returned structures.  If both
>sets match (ie r.st_ino == f.st_ino && r.st_dev == f.st_dev)
>then they must be the same file.  (Network fans: is this true
>for remotely-mounted filesystems?)

It's true of the SunOS NFS implementation, and probably on all NFS
implementations derived from it.  The AT&T S5R3 RFS implementation looks
as if it attempts to preserve this property, also.  Any file system
implementation that *doesn't* preserve that property is broken; POSIX
quite explicitly says that "st_dev" and "st_ino" uniquely identify a file.

david@wubios.wustl.edu (David J. Camp) (03/04/89)

In article <7419@pyr.gatech.EDU> curci@stat.fsu.edu (Ray Curci (scri)) writes:
:>In article <10@sherpa.UUCP> rac@sherpa.UUCP (Roger A. Cornelius) writes:
:>>...  Anyway, can someone tell me how to determine (in C)
:>>if output is being redirected, or more precisely, how to determine the
:>>file output is being redirected to.  
:>>Roger      rac@sherpa
:>>           uunet!sherpa!rac
:>
:>You may want to investigate the isatty() function call.  I believe that
:>you can use something like:  isatty(stdout)  which will tell you if
:>standard out is going to a terminal (the usual case), or if it has been
:>redirected via a pipe or into a file.
:>
:>ray curci

I just received umpteen replies about this.  The function call is
isatty(fileno(stdout));
-David-
-- 
Bitnet:   david@wubios.wustl                ^      Mr. David J. Camp
Internet: david%wubios@wucs1.wustl.edu    < * >    Box 8067, Biostatistics
uucp:     uunet!wucs1!wubios!david          v      660 South Euclid
Washington University Medical School               Saint Louis, MO 63110

les@chinet.chi.il.us (Leslie Mikesell) (03/05/89)

In article <1111@auspex.UUCP> guy@auspex.UUCP (Guy Harris) writes:
>>Then you compare st_ino and st_dev in both returned structures.  If both
>>sets match (ie r.st_ino == f.st_ino && r.st_dev == f.st_dev)
>>then they must be the same file.  (Network fans: is this true
>>for remotely-mounted filesystems?)

>It's true of the SunOS NFS implementation, and probably on all NFS
>implementations derived from it.  The AT&T S5R3 RFS implementation looks
>as if it attempts to preserve this property, also. 

Does st_dev become unique for each remote filesystem or does it just
get a bit set to indicate that it is remote?  If the latter case is true
then the test above might falsely indicate that files on two different
remote systems were the same file.  Hmmm, cpio and tar might get confused
also and think the files should be linked - something to consider with the
versions that only store the first copy in the archive (GNUtar, PAX, perhaps
others).

Les Mikesell