0

I have a system built using the RTAI extension to Linux. It has a process that runs as root on startup. It creates some named pipes and chmod 777 them. The pipes are owned by root and have the permissions prwxrwxrwx but none of the user processes can write to or read from them. The pipes are made (in C) like this

unlink(pipename);
mkfifo(pipename, 0777);
chmod(pipename, 0777);

If I login as the user, su to root, kill the process and restart it, come out of root, the named pipes are still owned by root and have the permissions prwxrwxrwx but this time, the user processes can read and write from them.

Question: what else do I need to do so that the named pipes are accessible if the program is run as part of the boot process.

Also, how do I make sure that it is the very last process that is executed after all the comms mechanisms have been set up.

Edit

I've changed the title (old one was Setting pipe permissions for boot process)

I have finally got it working by shifting the process into rc.local. Since the coder was using RTAI, he thought that the process had to be started at the same time as all the other RTAI processes. The other processes didn't use any of the Unix comms mechanisms so it didn't matter. When he started using pipes, it had to be shifted to the end of the multiuser level.

This is the part I cannot find an explanation for: at what point in the boot process would it be OK to use pipes? I have shifted it to the end but it could be earlier.

4

2 回答 2

0

Problem

Took a while to figure out how to find out what state the process was in. All the programs just block on open. I could try O_NONBLOCK but I don't know how well that will work. I also hate polling.

Whether a process hangs on open() depends on opening mode (O_RDONLY, O_WRONLY, O_RDWR).

  • Without O_NONBLOCK:

    • with O_RDONLY, open() will block until fifo is opened for writing from any process;
    • with O_WRONLY, open() will block until fifo is opened for reading any process;
    • with O_RDWR, open() will return immediately.
  • With O_NONBLOCK:

    • with O_RDONLY, open() will return immediately;
    • with O_WRONLY, open() will return error if fifo is not opened for reading from any process;
    • with O_RDWR, open() will return immediately.

See details in open(3) (O_NONBLOCK section) and fifo(7).

If your open() hangs, it indicates that:

  • you are using O_RDONLY or O_WRONLY without O_NONBLOCK;
  • fifo is not opened for writing or reading in any other process.

Solution

If you expected fifo to be already opened from another process, check why it's not. Probably a process that should keep it opened died, or you're starting processes in the wrong order, or there is a race condition.

Otherwise, you can do one of the following:

  • Use O_RDWR opening mode, and open() will return immediately.

    However, note that you'll never get EOF when reading from fifo (because you're keeping reading end opened) or SIGPIPE when writing to fifo (because you're keeping writing end opened).

  • Use O_RDONLY | O_NONBLOCK, and open() will return immediately.

    Note that read() will return EOF if fifo is not opened for reading from any process.

  • Open fifo later, when another process has already opened other end of fifo.

于 2016-01-28T11:49:36.370 回答
0

Finally got to the bottom of the problem.

  1. I added a delay and it made no difference.
  2. Then I found that even though I mkfifo with 666, the permissions were still 644. Since the FIFO was owned by root, no other process could write to it. As a result, I added a chmod after the mkfifo. That made the FIFO writable.
  3. The writing problem was fixed but the writer still didn't return from the open.
  4. This was a SuSE specific problem. The process was started in boot.local, which was way too early. On other systems, it can be started in rc.local but on SuSE, it had to be started on after.local. Moved the program to after.local and everything magically started working.

In short, the fix was

  1. chmod after creating the FIFO
  2. Move the executable to after.local on SuSE

The answer to my question is put it in rc.local for Ubuntu, Centos and Debian, after.local for SuSE.

于 2016-02-24T11:23:22.833 回答