[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
mtab translator
From: |
David Walter |
Subject: |
mtab translator |
Date: |
Fri, 16 Aug 2002 19:13:16 -0400 |
User-agent: |
Gnus/5.090007 (Oort Gnus v0.07) XEmacs/21.4 (Honest Recruiter, i386-unknown-gnu0.2) |
Well here is a translator to act as mtab. It accepts the mount point
as a path, then requests the information from the filesystem and the
active translator for options.
df works with this as does cat /var/run/mtab
As it actively reads the translators information, if a change is
issued it is updated on the next read, as in cat, and if the
translator goes away it will be removed from mtab.
I haven't modified df to handle a local translator as Marcus suggested
yet, nor have I altered mount or settrans or fsysopts to add an
--mtab path
option.
I would still like to find a way for a translator to find the node it
is on, if there is such a thing, so that they can insert themselves
when appropriate, but decided to ask for input on this while I start
working on getting mount, et al working to support this.
The included files are:
mtab.c The source for the translator.
mtab.Makefile The makefile, (it expects to be found in
a subdirectory of the hurd source directory.
I named this Makefile and had a hurd/mtab
directory.
rc.diff to patch /libexec/rc - this hasn't been
checked against the latest hurd if there
were changes in rc.
Basically
# /var/run/mtab is deleted every boot so.
# notice that mtab assumes there is a /.
# and automatically inserts this path.
settrans -fga /var/run/mtab
# insert some path.
echo /path > /var/run/mtab
/* mtab: dynamic mount table information. add path, read mount info.
Copyright (C) 2002 Free Software Foundation, Inc.
Written by David Walter <dwalter@syr.edu>
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
Thanks to everyone who contributed ideas for this translator.
I intend to just change the copyright to FSF, but didn't think it made
sense until reviewed and people think it works okay.
*/
#define _GNU_SOURCE 1
#include <hurd/trivfs.h>
#include <stdlib.h> /* exit () */
#include <error.h> /* Error numers */
#include <fcntl.h> /* O_READ etc. */
#include <sys/mman.h> /* MAP_ANON etc. */
#include <mntent.h> /* mount entry table
manipulation */
#include <store.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <argz.h>
#include <version.h>
#include <argp.h>
const char *argp_program_version = STANDARD_HURD_VERSION (mtab);
static struct argp_option options[] =
{
{0, 0}
};
static char *args_doc = "";
static char *doc = "mount table translator mtab. "
"behaves as the /etc/mtab file, "
"insert the path to a mounted filesystem and it"
"stores returns the information whenever requested."
"Automatically inserts the root '/' directory information.";
////////////////////////////////////////////////////////////////////////
// Data definitions
////////////////////////////////////////////////////////////////////////
typedef struct mtab{
char* path;
char* data;
size_t length;
struct mtab*next;
} mtab;
struct mutex mtab_update_lock;
mtab* mount_table=0; /* list of paths of registered active
mounted filesystems and their
data */
mtab* tail=0;
////////////////////////////////////////////////////////////////////////
// Prototypes
////////////////////////////////////////////////////////////////////////
error_t mtab_write_table_to_buffer(mtab *mt, char **buffer, int *buffer_size);
void mtab_free(mtab *mt);
void mtab_free_table(mtab *mt);
error_t mtab_filesystem_info(const char *path, mtab **entry);
mtab *mtab_create(void);
mtab *mtab_remove_helper(mtab *mt, const char *path);
mtab *mtab_remove(mtab **mt, const char *path);
error_t mtab_insert(mtab **mount_table, mtab *entry);
int mtab_entry_buffer_size(mtab *mt);
size_t mtab_mount_table_buffer_size(mtab *mt);
void mtab_manage_info(void);
// allocates memory and returns size in buffer size, and buffer points
// to allocated memory.
error_t
mtab_write_table_to_buffer(mtab*mt, char**buffer, int*buffer_size){
assert(buffer);
if(*buffer) free(*buffer);
*buffer = 0;
*buffer_size = 0;
*buffer_size += mtab_mount_table_buffer_size(mt);
*buffer = malloc(*buffer_size);
if(!*buffer)
return ENOMEM;
// copy all items from mount_table mt to the buffer.
size_t offset = 0;
mutex_lock(&mtab_update_lock);
while(mt){
sprintf((*buffer)+offset, "%s", mt->data);
/* mtab_entry_buffer_copy(mt, ); */
int length = mtab_entry_buffer_size(mt);
offset += length;
mt = mt->next;
}
mutex_unlock(&mtab_update_lock);
return 0;
}
void
mtab_free (mtab*mt){
assert(mt);
free(mt->path);
free(mt->data);
free(mt);
}
void
mtab_free_table(mtab*mt){
mutex_lock(&mtab_update_lock);
mtab*t;
while(mt){
t = mt;
mt = mt->next;
mtab_free(t);
}
mutex_unlock(&mtab_update_lock);
}
// mtab_remove()
// mount_table is a linked list of mount entries
// mount_point is the mount point of the entry to remove
// search mount_table for name and remove if found
// assumes a valid address for mount_table.
// no more mounts - actually shouldn't happen until reboot or remount
// of root
/*
This function actually generates the mtab-like buffer for the
read peropens to serve.
This is the /etc/mtab format according to the manpage:
fsname dir type opts freq passno
And how we populate it:
devicename path translator translatorargs 0 0
*/
error_t
mtab_filesystem_info(const char* path, mtab**entry)
{
char *transinfo = NULL;
char *toptransinfo = NULL;
file_t trans_node;
int transinfolen = 0;
struct store *storeinfo = NULL;
mtab* mt = NULL;
if(!(mt = mtab_create()))
return ENOMEM;
errno = 0;
// step 1. is there an active translator on this path?
// file_t file = file_name_lookup_carefully (path, 0, 0);
////////////////////////////////////////////////////////////////////////
// determine if this is an (actively) translated path or not.
////////////////////////////////////////////////////////////////////////
if(strcmp(path, "/") != 0) { // skip if root, special case for root.
// get the file w/o the translator
file_t file = file_name_lookup(path, O_NOTRANS, 0);
fsys_t fsys;
// get the active translator if there is one.
error_t active_trans_rc = file_get_translator_cntl(file, &fsys);
mach_port_deallocate(mach_task_self(), file);
if(active_trans_rc)
return EINVAL;
}
////////////////////////////////////////////////////////////////////////
// The root partition (in particular) needs to use the storeio info
////////////////////////////////////////////////////////////////////////
// Others (other translated nodes) require only the information from
// the translator.
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// it is actively translated, get the information re: the translation
////////////////////////////////////////////////////////////////////////
trans_node = file_name_lookup(path, 0, 0666); // get the underlying node
int s_rc;
s_rc = store_create(trans_node,
STORE_INACTIVE|STORE_NO_FILEIO, 0, &storeinfo);
int m_rc;
int f_rc;
m_rc = mach_port_deallocate(mach_task_self(), trans_node);
// get the file w/o the translator
trans_node = file_name_lookup(path, 0, 0666);
f_rc = file_get_fs_options(trans_node, &toptransinfo, &transinfolen);
m_rc = mach_port_deallocate(mach_task_self(), trans_node);
if (trans_node == MACH_PORT_NULL || f_rc != 0 ){ // || m_rc != KERN_SUCCESS){
if (toptransinfo != NULL) munmap(toptransinfo,transinfolen);
return EINVAL;
}
char* options_start = toptransinfo + strlen(toptransinfo) + 1;
argz_stringify(toptransinfo + strlen(toptransinfo)+1,
transinfolen-(strlen(toptransinfo)+1), ',');
transinfo = strrchr(toptransinfo, '/')+1;
toptransinfo[strlen(toptransinfo)] = ' ';
char*fsname=0;
if(storeinfo && storeinfo->name) // no store information (not
// active mount point?)
fsname = strdup(storeinfo->name);
else
fsname = strdup(strrchr(strchr(toptransinfo, ',')+1, '/')+1);
if(!fsname)
return ENOMEM;
mt->path = strdup(path);
if (!mt->path)
return ENOMEM;
char* type = malloc(transinfolen);
memset(type, 0, transinfolen);
char* options = malloc(transinfolen);
memset(options, 0, transinfolen);
sscanf(options_start, "%s %s", type, options);
if(!type || !options){
if(type)
free(type);
if(options)
free(options);
return ENOMEM;
}
mt->length = asprintf(&mt->data, "%s %s %s %s %i %i\n",
fsname,
path,
type,
options,
0,
0);
if (storeinfo)
store_free(storeinfo);
if (toptransinfo)
munmap(toptransinfo,transinfolen);
if(type)
free(type);
if(options)
free(options);
*entry=mt;
return 0;
}
mtab*
mtab_create (){
mtab* mt = malloc (sizeof (struct mtab));
if (mt){
mt->next=0;
return mt;
}
return 0;
}
mtab*
mtab_remove_helper(mtab* mt, const char*path)
{
if (!mt) // end of data case
return 0;
if (!mt->next)
tail = mt;
// found case
if(strcmp(path, mt->path) == 0) {
mtab* next = mt->next;
mtab_free(mt);
return next = mtab_remove_helper(next, path);
}
mt->next = mtab_remove_helper(mt->next, path);
return mt;
}
/*
mtab_remove: remove item when path matches, free memory of object.
*/
mtab*
mtab_remove(mtab**mt, const char*path){
return *mt = mtab_remove_helper(*mt, path);
}
error_t
mtab_insert(mtab**mount_table, mtab*entry){
assert(mount_table);
mutex_lock(&mtab_update_lock);
if(!*mount_table){ // empty table
tail=*mount_table=entry;
}
else{
tail->next= entry;
tail = tail->next;
}
mutex_unlock(&mtab_update_lock);
return 0;
}
int
mtab_entry_buffer_size(mtab* mt){ // struct mntent*entry){
return mt->length;
}
size_t
mtab_mount_table_buffer_size(mtab*mt){
int size=0;
while(mt){
size+=mtab_entry_buffer_size(mt);
mt=mt->next;
}
size++;
return size;
}
void mtab_manage_info(void){
static boolean_t started = FALSE;
if(!started){ // always start with
// a root
// filesystem.
started = TRUE;
char* path = "/";
mtab *mt=0;
error_t rc = mtab_filesystem_info(path, &mt);
////////////////////////////////////////////////////////////////////////
// something bad happened, if we can't instantiate the root filesystem.
////////////////////////////////////////////////////////////////////////
switch(rc){
case ENOMEM:
if(mt)
mtab_free(mt);
error(1,KERN_NO_SPACE, "mtab_filesystem_info");
break;
case EINVAL:
if(mt)
mtab_free(mt);
error(1,KERN_NO_SPACE, "mtab_filesystem_info");
break;
default:
mt->next = 0;
mtab_insert(&mount_table, mt);
break;
}
}
}
// Port bucket we service requests on.
struct port_bucket *port_bucket;
struct port_class *trivfs_protid_portclasses[1];
struct port_class *trivfs_cntl_portclasses[1];
int trivfs_protid_nportclasses = 1;
int trivfs_cntl_nportclasses = 1;
static int
mtab_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
{
extern int mtab_server (mach_msg_header_t *inp, mach_msg_header_t *outp);
return trivfs_demuxer (inp, outp);
}
char**arguments=NULL;
char*mtab_argz_string = 0;
int mtab_argz_length = 0;
int
main(int argc, char**argv){
error_t parse_opt (int key, char *arg, struct argp_state *state){
switch (key)
{
case 'v': error(1,0, argp_program_version); break;
default: break;
}
return 0;
}
struct argp argp = {options, parse_opt, args_doc, doc};
argp_parse (&argp, argc, argv, 0, 0, 0);
error_t err;
mach_port_t bootstrap;
struct trivfs_control *fsys;
// ************************************************************************
// create a translator from here.
// ************************************************************************
task_get_bootstrap_port (mach_task_self (), &bootstrap);
if (bootstrap == MACH_PORT_NULL)
error (1, 0, "Must be started as a translator");
arguments = argv;
if(mtab_argz_string==0){
if(argz_create(arguments, &mtab_argz_string, &mtab_argz_length) == ENOMEM){
error(0, ENOMEM, "argz creation failed");
}
}
// Reply to our parent
port_bucket = ports_create_bucket ();
trivfs_cntl_portclasses[0] = ports_create_class (trivfs_clean_cntl, 0);
trivfs_protid_portclasses[0] = ports_create_class (trivfs_clean_protid, 0);
// Reply to our parent.
err = trivfs_startup (bootstrap, 0,
trivfs_cntl_portclasses[0], port_bucket,
trivfs_protid_portclasses[0], port_bucket,
&fsys);
if (err)
error (1, err, "trivfs_startup failed");
// Launch.
ports_manage_port_operations_multithread (port_bucket, // fsys->pi.bucket,
mtab_demuxer,
0,
0,
mtab_manage_info);
return 0;
}
/* Trivfs hooks. */
int trivfs_fstype = FSTYPE_MISC; /* Generic trivfs server */
int trivfs_fsid = 0; /* Should always be 0 on startup */
int trivfs_allow_open = O_READ | O_WRITE;
/* Actual supported modes: */
int trivfs_support_read = 1;
int trivfs_support_write = 1;
int trivfs_support_exec = 0;
/* A hook for us to keep track of the file descriptor state. */
struct open
{
off_t offs;
char*contents;
size_t contents_length;
};
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;
op->contents = 0;
op->contents_length = 0;
peropen->hook = op;
error_t rc;
const char*path;
mtab*new_table=0;
mtab*mt=mount_table;
mtab*entry;
while(mt){
path = mt->path;
if(!(rc = mtab_filesystem_info(path, &entry)))
mtab_insert(&new_table, entry);
mt = mt->next;
}
mtab_free_table(mount_table);
mount_table = new_table;
return mtab_write_table_to_buffer(mount_table,
&op->contents,
&op->contents_length);
}
static void
close_hook (struct trivfs_peropen *peropen)
{
struct open *op = peropen->hook;
if(op && op->contents)
free(op->contents);
free (peropen->hook);
}
struct open*get_hook_from_cred(struct trivfs_protid*cred){
struct open *op;
op = cred->po->hook;
return op;
}
void
trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
{
/* Get the offset. */
st->st_mode &= ~S_IFMT; /* */
st->st_mode |= S_IFREG; /* Appear as a regular file. */
st->st_mode |= S_IATRANS; /* Say that this has an active
translator running. */
if (!cred)
return;
mutex_lock(&mtab_update_lock);
st->st_size = get_hook_from_cred(cred)->contents_length;
mutex_unlock(&mtab_update_lock);
}
error_t
trivfs_goaway (struct trivfs_control *cntl, int flags)
{
exit (EXIT_SUCCESS);
}
/*
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;
kern_return_t
trivfs_S_io_write (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t replytype,
vm_address_t data, mach_msg_type_number_t datalen,
off_t offs, mach_msg_type_number_t *amount)
{
if (!cred)
return EOPNOTSUPP;
else if (!(cred->po->openmodes & O_WRITE))
return EBADF;
boolean_t space(char c){ /* helper for clean input */
return c == ' ' || c == '\n' || c == '\t' || c == '\f';
}
/* fprintf(stderr, "%s\n", (char*)data); */
mtab *mt=0;
char* p = (char*)data+datalen-1;
while(space(*p))
*p-- = '\0';
p = strdup((char*)data);
error_t rc = mtab_filesystem_info(p, &mt);
switch(rc){
case ENOMEM:
if(mt)
mtab_free(mt);
return KERN_NO_SPACE;
case EINVAL:
if(mt)
mtab_free(mt);
return KERN_INVALID_ARGUMENT;
default:
////////////////////////////////////////////////////////////////////////
// as mtab_remove is a recursive call, it must lock prior to the
// call, unlock on return.
////////////////////////////////////////////////////////////////////////
mutex_lock(&mtab_update_lock);
mount_table = mtab_remove(&mount_table, p);
mutex_unlock(&mtab_update_lock);
mtab_insert(&mount_table, mt);
break;
}
*amount = datalen;
return KERN_SUCCESS;
}
/*
Tell how much data can be read from the object without blocking for
a "long time" (this should be the same meaning of "long time" used
by the nonblocking flag.
*/
kern_return_t
trivfs_S_io_readable (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t replytype,
mach_msg_type_number_t *amount)
{
if (!cred)
return EOPNOTSUPP;
else if (!(cred->po->openmodes & O_READ))
return EINVAL;
else
{
mutex_lock(&mtab_update_lock);
*amount = get_hook_from_cred(cred)->contents_length;
mutex_unlock(&mtab_update_lock);
}
return 0;
}
/* Truncate file. */
kern_return_t
trivfs_S_file_set_size (struct trivfs_protid *cred, off_t size)
{
if (!cred)
return EOPNOTSUPP;
else
return 0;
}
/* 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(!op)
return EINVAL;
if (offs == -1)
offs = op->offs;
mutex_lock(&mtab_update_lock);
/* Prune the amount they want to read. */
if(offs == 0){
// *FIXME* build the table here.
}
if (offs > op->contents_length)
offs = op->contents_length;
if (offs + amount > op->contents_length)
amount = op->contents_length - 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, op->contents + offs, amount);
/* Update the saved offset. */
op->offs += amount;
}
*data_len = amount;
mutex_unlock(&mtab_update_lock);
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;
mutex_lock(&mtab_update_lock);
switch (whence)
{
case SEEK_SET:
op->offs = offs; break;
case SEEK_CUR:
op->offs += offs; break;
case SEEK_END:
op->offs = get_hook_from_cred(cred)->contents_length - offs; break;
default:
err = EINVAL;
}
mutex_unlock(&mtab_update_lock);
if (! err)
*new_offs = op->offs;
return err;
}
/*
SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and
SELECT_URG. Block until one of the indicated types of i/o can be
done "quickly", and return the types that are then available.
TAG is returned as passed; it is just for the convenience of the
user in matching up reply messages with specific requests sent.
*/
kern_return_t
trivfs_S_io_select (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t replytype,
int *type, int *tag)
{
if (!cred)
return EOPNOTSUPP;
else
if (((*type & SELECT_READ) && !(cred->po->openmodes & O_READ))
|| ((*type & SELECT_WRITE) && !(cred->po->openmodes & O_WRITE)))
return EBADF;
else
*type &= ~SELECT_URG;
return 0;
}
/* Well, we have to define these four functions, so here we go: */
kern_return_t
trivfs_S_io_get_openmodes (struct trivfs_protid *cred, mach_port_t reply,
mach_msg_type_name_t replytype, int *bits)
{
if (!cred)
return EOPNOTSUPP;
else
{
*bits = cred->po->openmodes;
return 0;
}
}
error_t
trivfs_S_io_set_all_openmodes (struct trivfs_protid *cred,
mach_port_t reply,
mach_msg_type_name_t replytype,
int mode)
{
if (!cred)
return EOPNOTSUPP;
else
return 0;
}
kern_return_t
trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred,
mach_port_t reply,
mach_msg_type_name_t replytype,
int bits)
{
if (!cred)
return EOPNOTSUPP;
else
return 0;
}
kern_return_t
trivfs_S_io_clear_some_openmodes (struct trivfs_protid *cred,
mach_port_t reply,
mach_msg_type_name_t replytype,
int bits)
{
if (!cred)
return EOPNOTSUPP;
else
return 0;
}
/* return the translators command line options. */
kern_return_t
trivfs_S_file_get_translator (struct trivfs_protid *cred,
mach_port_t reply,
mach_msg_type_name_t reply_type,
char **trans, size_t *translen)
{
if (!cred)
return EOPNOTSUPP;
*trans = mmap (0, mtab_argz_length, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
bcopy (mtab_argz_string, *trans, *translen=mtab_argz_length);
return 0;
}
# mtab.Makefile
# Copyright (C) 1994,95,96,97,99,2000,2002 Free Software Foundation, Inc.
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
## To build: place this Makefile and the mtab.c source into a directory
## in the hurd source.
## From your hurd build directory run configure.
## This will create a new directory build/mtab
## The Makefile created will point to the source.
## Then make in the build/mtab will build the translator.
## the diff rc.diff is to patch the /libexec/rc file for use.
## As long as the filesystem translators don't know how to auto insert
## themselves, you have to manually write to the /var/run/mtab when a
## new translator is started.
## The proposed fix for this is to have the translators have an option
## to store their mount path.
## as in the example in rc you can just:
## echo /home > /var/run/mtab
## only the path is required. If the path is not an active translator
## then the entry is not inserted.
## if the translator dies, the next request for the list of
## translators (e.g. cat /var/run/mtab or df) the inactive point will
## be removed.
dir := mtab
makemode := servers
CFLAGS += -D__HURD__ -I../../hurd
targets = mtab
SRCS = mtab.c
OBJS = $(SRCS:.c=.o)
LCLHDRS = mtab.h
HURDLIBS = threads trivfs ports fshelp ihash shouldbeinlibc store
include ../Makeconf
vpath elfcore.c $(top_srcdir)/exec $(top_srcdir)/hurd $(top_srcdir)/libstore
mtab: mtab.o
mtab: \
../libthreads/libthreads.a \
../libports/libports.a \
../libthreads/libthreads.a \
../libtrivfs/libtrivfs.a \
../libstore/libstore.a \
../libfshelp/libfshelp.a
$(targets): ../libshouldbeinlibc/libshouldbeinlibc.a
$(targets): %: %.o
diff --unified -wi /libexec/rc.orig /libexec/rc
--- /libexec/rc.orig Thu Aug 15 09:21:00 2002
+++ /libexec/rc Thu Aug 15 09:21:00 2002
@@ -7,6 +7,10 @@
# Set up swap space. This will complain if no default pager is functioning.
swapon -a
+# initiate mount table
+# root filesystem is auto inserted by mtab
+settrans -fgca /var/run/mtab /hurd/mtab
+
# Check filesystems.
if [ -r /fastboot ]
then
@@ -99,7 +103,13 @@
echo done
# This file must exist for e2fsck to work. XXX
-touch /var/run/mtab
+# touch /var/run/mtab
+# initiate mount table /var/run/mtab
+# mtab translator automatically adds '/'
+settrans -fgca /var/run/mtab /hurd/mtab
+# dummy insertion of mounted filesystems for now
+echo /home > /var/run/mtab
+echo /opt > /var/run/mtab
#echo -n restoring pty permissions...
#chmod 666 /dev/tty[pqrs]*
--
/^\
\ / ASCII RIBBON CAMPAIGN
X AGAINST HTML MAIL
/ \
- mtab translator,
David Walter <=