Sixtease has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks, I need to test the open function. So I need a file that I'm quite certain that exists (or can be created) and that I have proper permissions to. I use $0 to open for reading. Is it a portable, safe practice?
use strict; use warnings; print "Just Another Perl Hacker\n";

Replies are listed 'Best First'.
Re: an ever-available file for opening
by thparkth (Beadle) on Jan 15, 2008 at 17:32 UTC
    I can only think of two minor potential problems with $0.

    Firstly, there are many circumstances where it can end up holding a relative path to the script, rather than an absolute one. If you then chdir, the relative path won't make sense. So don't do that.

    Secondly, $0 is meaningless when perl is interpreting standard input. So don't do that either.

    Other than that, I think you're golden. By definition the current process *must* have sufficient permission to read the script file, or it can't run it. So unless there's some bizarre suid situation I'm not considering, it should always be safe to open.

      There will be a small race condition if you assume your script file still exists.
      Some operating systems will let you delete scripts from disk while they run.
      example of a problem
Re: an ever-available file for opening
by cdarke (Prior) on Jan 15, 2008 at 17:58 UTC
    Not only will $0 be there, you can read and write to it as well:
    package blanket; use strict; END { open (IN, '<', "$0") || die "$0: $!"; my $new = "$0.new"; open (OUT, '>', "$new") || die "$new $!"; while (<IN>) { print OUT map {' ' x (ord() - 1), "\n"} (split '') } close IN; close OUT; rename $new,$0 } 1; package unblanket; use strict; BEGIN { open (IN, '<', "$0") || die "$0: $!"; my $new = "$0.new"; open (OUT, '>', "$new") || die "$new $!"; while (<IN>) { print OUT chr(length($_)) } close IN; close OUT; do "$new"; unlink "$new"; } 1;
Re: an ever-available file for opening
by kyle (Abbot) on Jan 15, 2008 at 17:01 UTC

    I would expect $0 always to be available. The documentation for it in perlvar is all about what happens if you try to modify it and nothing about any situation where it's not there or not correct.

    I'm trying to think of a situation where you'd be running a program and not have access to the file that it's in. Basically this would be a strange security/permissions situation. For example, your program ran as root and then dropped privileges.

    All that having been said, if I were testing open, I'd probably use -r to make sure I could open the file first. See also stat.

Re: an ever-available file for opening
by zentara (Cardinal) on Jan 15, 2008 at 19:32 UTC
    See /dev/null /dev/zero /dev/random /dev/full

    If you want something that never runs out, or can't be overfilled.

    #!/usr/bin/perl use warnings; use strict; $|++; open(RH, "/dev/urandom") or die "$!\n"; #always some to read #while (<RH>){print "$_\n";} open(ZH, "> /dev/zero") or die "$!\n"; #can always write to it while (<RH>){ print "chunk"; print ZH "$_\n"; }

    I'm not really a human, but I play one on earth. Cogito ergo sum a bum
Re: an ever-available file for opening
by andyford (Curate) on Jan 15, 2008 at 18:08 UTC

    What if your turn it around and say "Does there exist a file that I can open?"

    Start at the root directory and recurse till you find a file that your can open.

    This thinking will strip out any dependence on a particular file and replace it with the seemingly broader assumption that "somewhere on this system, there exists a file that I can open".

Re: an ever-available file for opening
by BrowserUk (Patriarch) on Jan 15, 2008 at 18:31 UTC
      A very, very good question. I need to test whether the :encoding(utf8) directive works and I feel that trying it out is more reliable than just checking the perl version.
      use strict; use warnings; print "Just Another Perl Hacker\n";

        Hm. I'm not sure that your justification stands up to scrutiny, but if you must, how about:

        my $utfData = "\x..."; open UTF, '<:encoding(utf8)', \$utfData or die 'Must be pre-5,8'; die 'Bad stuff happened' unless <UTF> eq 'Whatever you expect';

        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: an ever-available file for opening
by ambrus (Abbot) on Jan 16, 2008 at 10:09 UTC
Re: an ever-available file for opening
by grinder (Bishop) on Jan 16, 2008 at 11:26 UTC
    I need to test the open function

    I think it's slightly pointless to test the open function itself. If you think there's a chance that it may fail of its own accord (other than for resource acquisition issues) then you're probably worrying too hard. The test suite of perl itself ensures that it works correctly. At some point you have to take it as a given that the foundation is solid, and build upon it.

    That said...

    I need a file that I'm quite certain that exists

    A better idea than $0 would be to open the null device (that's what it's there for). This can be done portably with the File::Spec module. You can read or write to it to your heart's content.

    my $devnull = File::Spec->devnull(); open my $in, '<', $devnull or die "failed to open $devnull: $!\n";

    • another intruder with the mooring in the heart of the Perl

      Is the null device accessible in a chroot with no /dev/ mounted? I'd guess not...

      And I had some weird bugs once where /dev/null was not readable (a bug in the linux kernel Makefile had replaced /dev/null with a regular file owned by root and was not readable).

      I know these are corner cases, but that's what the question is all about, isn't it?

Re: an ever-available file for opening
by hipowls (Curate) on Jan 16, 2008 at 13:06 UTC

    On solaris (since at least 2.8), a script with the SUID bit set, $0 is /dev/fd/3, a file handle that was opened and passed to the perl interpreter. You will not be able to open and read $0.