7

Most files on a Linux system are normal files, i.e. they are saved on disk and reading from them just reads from a specified chunk of memory on the disk. How can I make something that behaves like a file in terms of being able to read from it as one would a normal file, but is actually returning programmatically generated data instead? As a concrete example, a file that downloads the current google.com and returns it, such that cat ~/myspecialfile would output the contents of google.com to stdout?

Anthon
  • 79,293
  • 3
    If I found such an artifact on my system I would consider it hostile and anything produced by its creator would be permanently blacklisted. – Ex Umbris Sep 20 '14 at 06:04
  • 4
    @ExUmbris: I recommend you never look at the contents of /run then, or else your software choices are going to become severely constrained. :-) (That's for Ubuntu, at least: on other flavors check /var/run, /var/tmp or similar locations.) – Nate Eldredge Sep 20 '14 at 06:30
  • OK, point taken, sometimes "files" backed by kernel modules are useful. However, if I installed something expecting a file and found it unexpectely executing code when I tried to display it I'd be unhappy :-) – Ex Umbris Sep 20 '14 at 06:52
  • 3
    May we ask you why you need this? Could be a XYProblem... – Olivier Dulac Sep 20 '14 at 08:21
  • Contribute a kernel module, maybe? – Marc van Leeuwen Sep 20 '14 at 14:34

3 Answers3

8

As the other answers have indicated, you can do part of what you've asked for using named pipes. For a complete solution, you'd have to develop some kind of virtual filesystem that took the desired actions when a path on the virtual filesystem was accessed. There are a few approaches to doing this:

  • Write a kernel-mode filesystem driver, like the procfs driver.
  • Write a user-mode filesystem implementation, using FUSE for example.
  • Write a program which provides an NFS server interface or another network filesystem protocol.
  • Maybe a program that pretends to be a USB file-storage device or another piece of hardware.
Kenster
  • 3,410
7

You can conceivably do something like this with a FIFO/named pipe:

$ mkfifo ~/myspecialfile
$ wget -q -O ~/myspecialfile google.com &
[2] 26186
$ 

mkfifo creates a named pipe called ~/myspecialfile. wget then directs its output to that named pipe. You can read (once) from that named pipe as if it were a regular file. e.g. to get wc counts for that file:

$ wc ~/myspecialfile
      7     430   17738 /home/ubuntu/myspecialfile
[2]+  Done                    wget -q -O ~/myspecialfile google.com
$ 

Note that typically the writer (wget in this instance) will open() the pipe with the O_WRONLY flag. This open() call will typically block until the reader (wc in this instance) opens the other end of the pipe with the O_RDONLY flag. So here the wget process will be started immediately, but it will be doing nothing in the background until the reader (opens and) starts to read. I have verified this behaviour with wireshark on Ubuntu 14.04.

4

You can make myspecialfile a named pipe. Then you can have a script running in the background that's in a loop writing the output of the program to the pipe:

#!/bin/bash
mkfifo ~/myspecialfile
while :; do
    run program here > ~/myspecialfile
done

There's a limitation to this. If two processes both open the file at the same time, they might each get only parts of the output.

A more elaborate way to do something that doesn't have this limitation would be to implement a FUSE filesystem. ~/myfyspecialfile would be the mount point of the filesystem.

Barmar
  • 9,927