>>>>> 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 <[EMAIL PROTECTED]> //\ 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 <[EMAIL PROTECTED]>, 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: */

