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

I wonder if this can be done with perl or it has to be done with C

Can perl be used under Linux so that when a file is opened and we can specify it that either though a hook in the os or some other way I cannot think of a script is run.

Any ideas or where to start looking? I have done lots of CGI but not much OS stuff.

Replies are listed 'Best First'.
Re: Monitoring when a file opened
by ambrus (Abbot) on Jan 21, 2005 at 18:27 UTC

    It's not quite clear what you want to do, nevertheless, here are some ideas.

    Create a fifo with mkfifo. If you open it for writing, without O_NONBLOCK, the open will block until someone opens the fifo for reading. Likely open it for reading and it will block until someone opens it for writing.

    Get strace to ptrace the system calls of a process, and set it up to log open and similar calls.

    Use the fuser program to watch what processes have a certain file open.

    Use the dnotify feature of linux to watch for created, accessed, or modified files in a directory, see linux/Documentation/dnotify.txt. (Update 2006 jun 14: similar in spirit to dnotify is leases whcih is also linux-specific and is documented in the fcntl manpage. I see that traveler also noted this in his reply.)

    Update: If a file is to be appended sequentially, and you just want to wait for a write, you can use select.

      Well what I am trying to do is make a simple lock-modify-unlock file system hack. We have three people who cannot play nice. It happend about once a month that the one wipes out anothers line of text. The files are on a samba share but the end users are still using notepad and do not want to change. One of those end users signs my check and is adamant about it

      CVS is probably too hard for them and this is my last try before I say you have to use cowiki for your text files.

      My idea is

      1. User A opens file X

      2. Script is triggered

      3. Script renames file to X.1 ect and backup of old copy saved in a sub directory

      4. Script edits the existing text file to say
      User: JDoe is editing file X, so that if they open it they dont make changes

      5a. JDoe saves the file and it's therefore overwritten, script then triggered again and saves his changes as well

      5b. Cron script runs every few hours and puts the backup back.

      If boss man leaves his file open with changes for three days ( yes I am serious ) and then saves wiping out everyones work for the last two days It's sime and it should work, if I could get CVS tortise or something to basically ( on save of this file add to the repository ) I'd be golden but I cant figure out how and since they all use the same files on the share there are no sandboxes.

      Yuck huh?

        To do this absolutely properly, you neet to write a virtual filesystem. And I imagine that's quite difficult to do in perl.

        By "absolutely properly", I mean handling all possible operations on the file.

        The next best thing may be to move the samba share to a Linux server, and use the pipes, but my gut tells me there's race conditions, timeouts, etc., which would mean that in some scenarios, bossman may overwrite files.

        Actually, I take some of that back - what you really want is to pull it off the share, and make it accessable only to multi-user-editing software. Period. And tell bossman that due to the problems you've had with the file, you've found a solution that will keep all changes safe.

        To be honest, it's probably easier to quit and find a new job ;->. But that's no guarantee you'll get a brighter PHB...

        I think what really matters in this scenario are the points at which new versions of the file are saved. (Trying to detect when some arbitrary mswin samba client opens the file seems like a much harder problem.)

        Suppose you had a continuous process (or a frequent cron job) on the samba server that checked the file's modification time -- e.g. at intervals of 5 sec or less. As soon as the process detects that the file has been modified relative to the previous check, the current version of the file is copied to someplace safe with a distinctive appendage to the file name based on the current system time.

        This will drastically reduce the likelihood that the person who saves a new version after a 3-hour (or 3-day) editing session will obliterate other people's changes that were saved during the interim. The probability of two people issuing save commands within the same short interval, though not nil, is perhaps comfortably low. (At least, it'll be a big improvement over the status quo.)

        There's still the problem of detecting when two or more successive saves contain divergent changes relative to some earlier version, and then reconciling them. For this, it might suffice if the short-interval "check-for-update" process runs a backtick "diff3" command each time the file is modified, comparing the newest version just detected with the previous two. (I haven't used diff3, but it is a standard GNU utility, and I think it would do nicely for this job.)

        (Yes, I know I'm a year late here.) If you can convince them to use some other editor instead of notepad (better try with some editor with very similar appearience and feel) you may be able to write a macro hook in it to check for the file being notified. You might not even have to do any programming, as some editors already check when saving if the modification date of the file is later then when it was opened, and warn the user about it. That of course might still fail if they save almost in the same moment, but you can get over that if the editor also locks the file at saving automatically (which is also not an unknown editor feature).

        This also works partially if you can convince only some of the people, as it would still warn him if he saves the file when someone else have changed it since he's loaded it.

        (Update: note that I've also updated my reply to the parent thread.)

Re: Monitoring when a file opened
by traveler (Parson) on Jan 21, 2005 at 18:35 UTC
    perl can do fcntl(2). Leases are activated with the F_SETLEASE parameter. I have not tried using that parameter with perl, but I do not see why it cannot be sent. If you use Fcntl; and the lease constants are not there, you may have to add them or upgrade your perl.

    Leases began somewhere in 2.4 so they are not in older linuxes.

    HTH, --traveler

Re: Monitoring when a file opened
by Fletch (Bishop) on Jan 21, 2005 at 18:31 UTC

    Yeah, ambiguous question. If your OS supports it SGI::Fam might be what you're looking for.

Re: Monitoring when a file opened
by ikegami (Patriarch) on Jan 21, 2005 at 18:43 UTC
    and we can specify it

    What's "it"? Specify that the file can't be read and/or opened by another application? That would be file locking, which can be done using flock. If you flock a file in Perl script, it will prevent other applications (whether their Perl scripts or not) from also using that file. Caveat: The other applications also have to use flock. This is called an advisory locking scheme, since the lock can be ignored.

Re: Monitoring when a file opened
by zentara (Cardinal) on Jan 22, 2005 at 10:38 UTC
    I think you should look at File::MMagic - Guess file type

    You could add a MIME type for your file, then process it accordingly.

    Of course, this means that you will have to use Perl to open the files.


    I'm not really a human, but I play one on earth. flash japh