l4vfs and stdin/stdout handles

Valery V. Sedletski _valerius at mail.ru
Tue Jun 22 22:35:02 CEST 2010

On Mon, 21 Jun 2010 17:29:00 +0200, Martin Pohlack wrote:

>> I checked init_io(), it seems to do the same as a fragment in term_con_test example -- it opens a terminal device
>> and checks the file descriptors to be 0, 1, 2 (with unessential details). I forgot to mention that my program is an API
>> server which implements an API and starts a client program using that API. I load the client program, all needed libraries
>> for it. Then I start a function called trampoline() in a separate task, prepare an environment for the program in that 
>> function (including file descriptors). Then I just setup registers, push params for C startup code on stack, and call an
>> entry point in a client program.
>I think it is not so easy to transfer these FDs into another task, as
>server state is associated with many FDs (depending on the server).

Yes, transfer to another task is difficult but I meant to execute the same startup code as in init_io() but for client task, not a server.
Now I specified '--stdin /dev/vc0 --stdout /dev/vc0 --stderr /dev/vc0' in server command line and mounted term_con at /dev. -- After that
I got one l4con tab opened and all terminal i/o got in there. So, it works but the server owns the terminal. But it is desirable to do the same
for client program. I start it using task server, so I cannot specify command line, so I must init terminal i/o other way.

>> I tried to add "--stdin /dev/vc0" to API server's command line. The init_io() function opens all file descriptors successfully. 
>> Then these file descriptors seem to be inherited by a client program (if I try to open /dev/vc0 in trampoline(), it returns a fd equal 
>> to 3, 4, 5, so 0, 1, 2 are already used). But when I try calling read(0, ...); (I call it in the API call from the client program, so the task 
>> id at the moment is from the client program) it says that 

I changed now the app behaviour, so all terminal reads and writes are performed in server stub but not in the context of a client. The server 
owns a terminal and works with it. But it is not the intended way. Of course, I need each client program have its own std* file descriptors.

>I looked again in operations.c:init_io()
>If you do not provide "--stdin x" etc. argument, dummy FDs are put into
>place in the local FD table, e.g., here:
>        ft_fill_entry(1, file_desc);      // fill in dummy entry
>I vaguely recall doing this to prevent accidents with printf() etc. in
>dietlibc which had no error checking regarding invalid FDs.  I have not
>revisited this code since we switched to uclibc years ago ...

So, they're just dummy. I didn't know that ft_fill_entry() fills the local descriptor table. So, it is also needed besides just open()'ing it. But how can I
get the file descriptor got from open() to be in a range of 0..2? It seems they are already predefined at the moment, though are dummy..

>If you want to have nice support for fork etc. (which requires FD
>inheritance amongst other things) you will need to extend l4vfs to
>inform all relevant servers of resource transfers.  This may be
>initiated from the client program, but some generic functions in servers
>to support transferring resource seems in order.
>This may prove to be a challenging design if you want to do it securely

Yes, that may be challenging and interesting task :) but for now I need just to assign the descriptors to the client from the very beginning

>Have you checked out the loader?  I think you may not want to use the
>task server directly.

Yes, I checked. But at the moment the loader uses ldso and can parse ELF only. There was an extra exec layer besides loader itself, so there 
was a potential possibility to add support of other formats to the loader. But now it seems to be not possible (ELF only). I need support of OS/2 LX
format executables, so we implemented support for it ourself. Now the server parses LX format executable, loads all needed libraries, applies
fixups and gets a ready for execute binary image. That image is executed by calling its entry point from trampoline() which starts in a separate task.
For that, a task server is used. We cannot use loader server because the format is not ELF. We think the previous design with separate exec and
loader server was better with possibility to add more executable parsers.


More information about the l4-hackers mailing list