Simple trivfs translator [was: A few other problems]
>>>>> Daniel Burrows writes:
DB> Would it be possible for someone (preferably someone who knows
DB> something about this topic ;-) ) to write some quick
DB> documentation on how to write a very simple translator?
Ding ding ding ding ding!
Congratulations, you just asked the winning question!
DB> A "hello, world!" type of program, for example, would be very
DB> useful; perhaps a tiny translator that just prints the above
DB> message when 'cat'ed
This is the former, because it is a libtrivfs-based translator
(i.e. only provides operations for a single non-directory node).
The secret to writing such translators rests mainly in reading
<hurd/trivfs.h> and staring at a similar example.
The trivfs_S_* functions may seem confusing and arbitrary until you
realize that they're called by the libtrivfs demuxer routines that are
compiled by MiG from the Hurd RPC interfaces. They begin with
`trivfs_S' in order to avoid name clashes.
In this case, libtrivfs implements the interface described by
<hurd/io.defs>. There are default trivfs_S_* implementations in
libtrivfs, which you can override to get a functioning filesystem.
DB> or shows a file containing "Hello, world!" when "ls"'ed?
This kind of translator doesn't really have a simple framework right
now... libtreefs is a (untested) attempt by Miles Bader, but nothing
uses it. devnull (Joel N. Weber) worked on improving it, but I don't
know if his changes ever got folded back into the mainline.
So, until then, libdiskfs and libnetfs are the only really functional
hierarchical filesystem frameworks (for store-based and network-based
filesystems, respectively).
--
Gordon Matzigkeit <gord@fig.org> //\ I'm a FIG (http://www.fig.org/)
Committed to freedom and diversity \// I use GNU (http://www.gnu.org/)
/* thello.c - A trivial single-file translator
Copyright (C) 1998, 1999 Free Software Foundation, Inc.
Gordon Matzigkeit <gord@fig.org>, 1999
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Peek at the end for the compile-command if you're not using Emacs. */
#define _GNU_SOURCE 1
#include <argp.h>
#include <stdio.h>
#include <hurd/trivfs.h>
#include <fcntl.h>
#include <sys/mman.h>
/* The message we return when we are read. */
static char hello[] = "Hello, world!\n";
/* Trivfs hooks. */
int trivfs_fstype = FSTYPE_MISC;
int trivfs_fsid = 0;
int trivfs_allow_open = O_READ;
int trivfs_support_read = 1;
int trivfs_support_write = 0;
int trivfs_support_exec = 0;
/* NOTE: This example is not robust: it is possible to trigger some
assertion failures because we don't implement the following:
$ grep -l 'assert.*!trivfs_support_read' /src/hurd/libtrivfs/*.c |
xargs grep '^trivfs_S_' | sed 's/^[^:]*:\([^ ]*\).*$/\1/'
trivfs_S_io_get_icky_async_id
trivfs_S_io_async
trivfs_S_io_map
trivfs_S_io_get_openmodes
trivfs_S_io_clear_some_openmodes
trivfs_S_io_set_some_openmodes
trivfs_S_io_set_all_openmodes
trivfs_S_io_get_owner
trivfs_S_io_mod_owner
trivfs_S_io_readable
trivfs_S_io_select
$
For that reason, you should run this as an active translator
`settrans -ac testnode /path/to/thello' so that you can see the
error messages when they appear. */
/* A hook for us to keep track of the file descriptor state. */
struct open
{
off_t offs;
};
void
trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
{
/* Mark the node as a read-only plain file. */
st->st_mode &= ~(S_IFMT | ALLPERMS);
st->st_mode |= (S_IFREG | S_IRUSR | S_IRGRP | S_IROTH);
st->st_size = sizeof (hello) - 1;
}
error_t
trivfs_goaway (struct trivfs_control *cntl, int flags)
{
exit (0);
}
static error_t
open_hook (struct trivfs_peropen *peropen)
{
struct open *op = malloc (sizeof (struct open));
if (op == NULL)
return ENOMEM;
/* Initialize the offset. */
op->offs = 0;
peropen->hook = op;
return 0;
}
static void
close_hook (struct trivfs_peropen *peropen)
{
free (peropen->hook);
}
/* Read data from an IO object. If offset is -1, read from the object
maintained file pointer. If the object is not seekable, offset is
ignored. The amount desired to be read is in AMOUNT. */
error_t
trivfs_S_io_read (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t reply_type,
vm_address_t *data, mach_msg_type_number_t *data_len,
off_t offs, mach_msg_type_number_t amount)
{
struct open *op;
/* Deny access if they have bad credentials. */
if (! cred)
return EOPNOTSUPP;
else if (! (cred->po->openmodes & O_READ))
return EBADF;
/* Get the offset. */
op = cred->po->hook;
if (offs == -1)
offs = op->offs;
/* Prune the amount they want to read. */
if (offs > sizeof (hello) - 1)
offs = sizeof (hello) - 1;
if (offs + amount > sizeof (hello) - 1)
amount = sizeof (hello) - 1 - offs;
if (amount > 0)
{
/* Possibly allocate a new buffer. */
if (*data_len < amount)
*data = (vm_address_t) mmap (0, amount, PROT_READ|PROT_WRITE,
MAP_ANON, 0, 0);
/* Copy the constant data into the buffer. */
memcpy ((char *) *data, hello + offs, amount);
/* Update the saved offset. */
op->offs += amount;
}
*data_len = amount;
return 0;
}
/* Change current read/write offset */
error_t
trivfs_S_io_seek (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t reply_type,
off_t offs, int whence, off_t *new_offs)
{
struct open *op;
error_t err = 0;
if (! cred)
return EOPNOTSUPP;
op = cred->po->hook;
switch (whence)
{
case SEEK_SET:
op->offs = offs; break;
case SEEK_CUR:
op->offs += offs; break;
case SEEK_END:
op->offs = sizeof (hello) - 1 - offs; break;
default:
err = EINVAL;
}
if (! err)
*new_offs = op->offs;
return err;
}
/* If this variable is set, it is called every time a new peropen
structure is created and initialized. */
error_t (*trivfs_peropen_create_hook)(struct trivfs_peropen *) = open_hook;
/* If this variable is set, it is called every time a peropen structure
is about to be destroyed. */
void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *) = close_hook;
int
main (int argc, char **argv)
{
error_t err;
mach_port_t bootstrap;
struct trivfs_control *fsys;
argp_parse (0, argc, argv, 0, 0, 0);
task_get_bootstrap_port (mach_task_self (), &bootstrap);
if (bootstrap == MACH_PORT_NULL)
error (1,0, "Must be started as a translator");
/* Reply to our parent */
err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
mach_port_deallocate (mach_task_self (), bootstrap);
if (err)
error (3, err, "trivfs_startup");
/* Launch. */
ports_manage_port_operations_one_thread (fsys->pi.bucket, trivfs_demuxer, 0);
return 0;
}
/*
Local variables:
compile-command:"gcc -g -o thello thello.c -ltrivfs -lfshelp -lports -lthreads"
End:
*/
Reply to: