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

I have a file(init.cgi), which is supposed to set everything up for my content management system. In order for both to be portable, I want to be able to upload the two files, run init.cgi, and then just be done with it. However, I don't want any of the users to be able to access init.cgi after I have run it once. Does anyone know of a way that I would be able to have init.cgi delete itself, or rewrite itself, so that this would no longer be possible?

thanks,
Spidy

EDIT: Nevermind. I managed to do it, by doing this:
open(INIT,">init.cgi"); #read in template file while(<INIT>) { print "empty!"; } close INIT;

Replies are listed 'Best First'.
Re: Deleting a file after it runs?
by Zaxo (Archbishop) on Oct 06, 2005 at 20:44 UTC

    On unix, you can also say,

    unlink $0;
    You can say that at any point in the program, and unix will go ahead and remove the file from the directory without losing the object of the file handle. The removal is completed and disk space released once your program closes.

    $ cat > try.pl #!/usr/bin/perl print $0, $/; unlink $0; print "Feeling faint . . .\n"; $ chmod 755 try.pl $ cp try.pl try.bak $ ls try.* try.bak try.pl $ ./try.pl ./try.pl Feeling faint . . . $ ls try.* try.bak $

    After Compline,
    Zaxo

          The removal is completed and disk space released once your program closes.
      
      I believe the removal is happening even earlier -- after the program has compiled, and the Perl interpreter has started executing it, but potentially long before the program completes.  Try this to see what I mean:
      #!/usr/bin/perl -w + # Strict use strict; use warnings; + # Main program print "Check file before unlink\n"; sleep 1; system("ls $0"); print "Unlinking the file $0\n"; sleep 1; unlink $0; print "Check file after unlink\n"; sleep 1; system("ls $0"); + print "File should be now be gone from disk (but still in memory)\n"; print "Try ^Z and check it with 'ls $0' ... (come back with 'fg')\n"; sleep 10; + print "I'm still here, but the original file is long gone.\n";
      And when you run it:
      % chmod +x rmtest
      % rmtest
      Check file 'rmtest' before unlink
      rmtest
      Unlinking the file 'rmtest'
      Check file 'rmtest' after unlink
      ls: rmtest: No such file or directory
      File should be now be gone from disk (but still in memory)
      Try ^Z and check it with 'ls rmtest' ... (come back with 'fg')
       
      Suspended
      % ls rmtest
      ls: rmtest: No such file or directory
      % fg
      rmtest
      I'm still here, but the original file is long gone.
      %
      

        You're both right. Try a bit more in your sample.

        When you run this, even after the file is unlinked, the *DATA filehandle still works. That's because the file is still physically on the disk, even though it has been unlinked from the directory tree. Once the file is finally closed, the filesystem is allowed to reuse that diskspace. To prove this, I created a ram disk (thanks to a recent thread ;-}), and added a check using df to see the filesystem being used. In this case I ram it and got output like this:
        $ cp z.pl /ram; perl /ram/z.pl Check file before unlink /ram/z.pl Filesystem 1K-blocks Used Available Use% Mounted on none 100 4 96 4% /ram Unlinking the file /ram/z.pl Check file after unlink ls: /ram/z.pl: No such file or directory Filesystem 1K-blocks Used Available Use% Mounted on none 100 4 96 4% /ram File should be now be gone from disk (but still in memory) Try ^Z and check it with 'ls /ram/z.pl' ... (come back with 'fg') I'm still here, but the original file is long gone. $ df -k /ram Filesystem 1K-blocks Used Available Use% Mounted on none 100 0 100 0% /ram
        Note how the file may have disappeared from /ram, but the disk usage wasn't actually freed up until I was done with the script.

        I re-ran the script without the __END__ marker or the usage of *DATA, and found that the script is closed after compilation as the diskspace is freed immediately. Again, you're both right. :-)

Re: Deleting a file after it runs?
by liverpole (Monsignor) on Oct 06, 2005 at 20:35 UTC
    I think, since you're opening the file for write, that trying to read it in isn't really going to work. If you run it with warnings, as a standalone file, you're more liable to see that this:
    #!/usr/bin/perl -w open(INIT, ">doit"); while (<INIT>) { printf "%s\n", $_; } close INIT;
    when run gives:
        Filehandle INIT opened only for output at init.cgi line 3.
    

    How about this for an even shorter solution? -- since Perl reads the entire file into memory before compilation, by runtime, the file is no longer necessary.  Hence, you can do it like this:

    #!/usr/bin/perl -w unlink $0; # Delete myself! print "Still here!\n"; # Prove that script executes okay # Rest of code follows ...
    Now:
        % init.cgi
        Still here!
        % ls init.cgi
        ls: init.cgi: No such file or directory
    
Re: Deleting a file after it runs?
by snoopy (Curate) on Oct 06, 2005 at 22:43 UTC
    There is always, of course, Acme::Bleach :-)
    print "Goodbye World!\n"; eval "use Acme::Bleach"; die "Back from the dead: $@" if ($@);