[Ocfs2-tools-commits] smushran commits r642 - trunk/mount.ocfs2

svn-commits at oss.oracle.com svn-commits at oss.oracle.com
Tue Mar 15 17:25:40 CST 2005


Author: smushran
Signed-off-by: mfasheh
Date: 2005-03-15 17:25:37 -0600 (Tue, 15 Mar 2005)
New Revision: 642

Added:
   trunk/mount.ocfs2/CREDITS
   trunk/mount.ocfs2/fstab.c
   trunk/mount.ocfs2/fstab.h
   trunk/mount.ocfs2/get_label_uuid.c
   trunk/mount.ocfs2/get_label_uuid.h
   trunk/mount.ocfs2/linux_fs.h
   trunk/mount.ocfs2/mntent.c
   trunk/mount.ocfs2/mntent.h
   trunk/mount.ocfs2/mount.ocfs2.h
   trunk/mount.ocfs2/mount_constants.h
   trunk/mount.ocfs2/nls.h
   trunk/mount.ocfs2/opts.c
   trunk/mount.ocfs2/opts.h
   trunk/mount.ocfs2/realpath.c
   trunk/mount.ocfs2/realpath.h
   trunk/mount.ocfs2/sundries.c
   trunk/mount.ocfs2/sundries.h
Modified:
   trunk/mount.ocfs2/Cscope.make
   trunk/mount.ocfs2/Makefile
   trunk/mount.ocfs2/mount.ocfs2.c
Log:
mount now handles arguments and /etc/mtab
Signed-off-by: mfasheh

Added: trunk/mount.ocfs2/CREDITS
===================================================================
--- trunk/mount.ocfs2/CREDITS	2005-03-15 23:04:40 UTC (rev 641)
+++ trunk/mount.ocfs2/CREDITS	2005-03-15 23:25:37 UTC (rev 642)
@@ -0,0 +1,14 @@
+
+The following files have been copied from util-linux-2.12a/mount:
+	fstab.c/h
+	get_label_uuid.c/h
+	mntent.c/h
+	mount_constants.h
+	linux_fs.h
+	realpath.c/h
+	sundries.c/h
+
+The following files have code which has been copied from one or more files
+in util-linux-2.12a/mount: 
+	opts.c/h
+	nls.h

Modified: trunk/mount.ocfs2/Cscope.make
===================================================================
--- trunk/mount.ocfs2/Cscope.make	2005-03-15 23:04:40 UTC (rev 641)
+++ trunk/mount.ocfs2/Cscope.make	2005-03-15 23:25:37 UTC (rev 642)
@@ -3,7 +3,7 @@
 	rm -f cscope.*
 	echo "-k" >> cscope.files
 	echo "-I inc" >> cscope.files
-	find . -maxdepth 2 -name '*.c' -print >>cscope.files
+	find . -maxdepth 2 -name '*.c' -print | grep -v group.c >>cscope.files
 	find . -maxdepth 2 -name '*.h' -print >>cscope.files
 	find ../libocfs2/ -maxdepth 2 -name '*.c' -print >>cscope.files
 	find ../libocfs2/ -maxdepth 2 -name '*.h' -print >>cscope.files

Modified: trunk/mount.ocfs2/Makefile
===================================================================
--- trunk/mount.ocfs2/Makefile	2005-03-15 23:04:40 UTC (rev 641)
+++ trunk/mount.ocfs2/Makefile	2005-03-15 23:25:37 UTC (rev 642)
@@ -8,6 +8,8 @@
 	    -I$(TOPDIR)/libo2cb/include -I$(TOPDIR)/libo2dlm/include
 LIBOCFS2_LIBS = -L$(TOPDIR)/libocfs2 -locfs2
 LIBOCFS2_DEPS = $(TOPDIR)/libocfs2/libocfs2.a
+LIBO2DLM_LIBS = -L$(TOPDIR)/libo2dlm -lo2dlm
+LIBO2DLM_DEPS = $(TOPDIR)/libo2dlm/libo2dlm.a
 
 ifdef OCFS_DEBUG
 OPTS += -ggdb
@@ -18,16 +20,17 @@
 CFLAGS := $(OPTS) -Wall -Wstrict-prototypes -Wmissing-prototypes \
            -Wmissing-declarations
 
-DEFINES = -DOCFS2_FLAT_INCLUDES -DO2DLM_FLAT_INCLUDES
+DEFINES = -DOCFS2_FLAT_INCLUDES -DO2DLM_FLAT_INCLUDES -DVERSION=\"$(VERSION)\"
 
-CFILES = mount.ocfs2.c
+CFILES = opts.c mount.ocfs2.c
+CFILES += fstab.c get_label_uuid.c mntent.c sundries.c realpath.c
 
 OBJS = $(subst .c,.o,$(CFILES))
 
 DIST_FILES = $(CFILES) 
 
-mount.ocfs2: $(OBJS) $(LIBOCFS2_DEPS)
-	$(LINK) $(LIBOCFS2_LIBS) $(COM_ERR_LIBS)
+mount.ocfs2: $(OBJS) $(LIBOCFS2_DEPS) $(LIBO2DLM_DEPS)
+	$(LINK) $(LIBOCFS2_LIBS) $(LIBO2DLM_LIBS) $(COM_ERR_LIBS)
 
 group: group.o $(LIBOCFS2_DEPS)
 	$(LINK) $(LIBOCFS2_LIBS) $(COM_ERR_LIBS)

Added: trunk/mount.ocfs2/fstab.c
===================================================================
--- trunk/mount.ocfs2/fstab.c	2005-03-15 23:04:40 UTC (rev 641)
+++ trunk/mount.ocfs2/fstab.c	2005-03-15 23:25:37 UTC (rev 642)
@@ -0,0 +1,633 @@
+/* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek at pld.ORG.PL>
+ * - added Native Language Support
+ * Sun Mar 21 1999 - Arnaldo Carvalho de Melo <acme at conectiva.com.br>
+ * - fixed strerr(errno) in gettext calls
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include "mntent.h"
+#include "fstab.h"
+#include "sundries.h"		/* for xmalloc() etc */
+#include "get_label_uuid.h"
+#include "nls.h"
+
+#define streq(s, t)	(strcmp ((s), (t)) == 0)
+
+#define PROC_MOUNTS		"/proc/mounts"
+
+
+/* Information about mtab. ------------------------------------*/
+static int have_mtab_info = 0;
+static int var_mtab_does_not_exist = 0;
+static int var_mtab_is_a_symlink = 0;
+
+static void
+get_mtab_info(void) {
+	struct stat mtab_stat;
+
+	if (!have_mtab_info) {
+		if (lstat(MOUNTED, &mtab_stat))
+			var_mtab_does_not_exist = 1;
+		else if (S_ISLNK(mtab_stat.st_mode))
+			var_mtab_is_a_symlink = 1;
+		have_mtab_info = 1;
+	}
+}
+
+int
+mtab_does_not_exist(void) {
+	get_mtab_info();
+	return var_mtab_does_not_exist;
+}
+
+int
+mtab_is_a_symlink(void) {
+	get_mtab_info();
+	return var_mtab_is_a_symlink;
+}
+
+int
+mtab_is_writable() {
+	static int ret = -1;
+
+	/* Should we write to /etc/mtab upon an update?
+	   Probably not if it is a symlink to /proc/mounts, since that
+	   would create a file /proc/mounts in case the proc filesystem
+	   is not mounted. */
+	if (mtab_is_a_symlink())
+		return 0;
+
+	if (ret == -1) {
+		int fd = open(MOUNTED, O_RDWR | O_CREAT, 0644);
+		if (fd >= 0) {
+			close(fd);
+			ret = 1;
+		} else
+			ret = 0;
+	}
+	return ret;
+}
+
+/* Contents of mtab and fstab ---------------------------------*/
+
+struct mntentchn mounttable, fstab;
+static int got_mtab = 0;
+static int got_fstab = 0;
+
+static void read_mounttable(void), read_fstab(void);
+
+struct mntentchn *
+mtab_head() {
+	if (!got_mtab)
+		read_mounttable();
+	return &mounttable;
+}
+
+struct mntentchn *
+fstab_head() {
+	if (!got_fstab)
+		read_fstab();
+	return &fstab;
+}
+
+static void
+read_mntentchn(mntFILE *mfp, const char *fnam, struct mntentchn *mc0) {
+	struct mntentchn *mc = mc0;
+	struct mntent *mnt;
+
+	while ((mnt = my_getmntent (mfp)) != NULL) {
+		if (!streq(mnt->mnt_type, MNTTYPE_IGNORE)) {
+			mc->nxt = (struct mntentchn *) xmalloc(sizeof(*mc));
+			mc->nxt->prev = mc;
+			mc = mc->nxt;
+			mc->m = *mnt;
+			mc->nxt = mc0;
+		}
+	}
+	mc0->prev = mc;
+	if (ferror (mfp->mntent_fp)) {
+		int errsv = errno;
+		error(_("warning: error reading %s: %s"),
+		      fnam, strerror (errsv));
+		mc0->nxt = mc0->prev = NULL;
+	}
+	my_endmntent(mfp);
+}
+
+/*
+ * Read /etc/mtab.  If that fails, try /proc/mounts.
+ * This produces a linked list. The list head mounttable is a dummy.
+ * Return 0 on success.
+ */
+static void
+read_mounttable() {
+	mntFILE *mfp;
+	const char *fnam;
+	struct mntentchn *mc = &mounttable;
+
+	got_mtab = 1;
+	mc->nxt = mc->prev = NULL;
+
+	fnam = MOUNTED;
+	mfp = my_setmntent (fnam, "r");
+	if (mfp == NULL || mfp->mntent_fp == NULL) {
+		int errsv = errno;
+		fnam = PROC_MOUNTS;
+		mfp = my_setmntent (fnam, "r");
+		if (mfp == NULL || mfp->mntent_fp == NULL) {
+			error(_("warning: can't open %s: %s"),
+			      MOUNTED, strerror (errsv));
+			return;
+		}
+		if (verbose)
+			printf (_("mount: could not open %s - "
+				  "using %s instead\n"),
+				MOUNTED, PROC_MOUNTS);
+	}
+	read_mntentchn(mfp, fnam, mc);
+}
+
+static void
+read_fstab() {
+	mntFILE *mfp = NULL;
+	const char *fnam;
+	struct mntentchn *mc = &fstab;
+
+	got_fstab = 1;
+	mc->nxt = mc->prev = NULL;
+
+	fnam = _PATH_FSTAB;
+	mfp = my_setmntent (fnam, "r");
+	if (mfp == NULL || mfp->mntent_fp == NULL) {
+		int errsv = errno;
+		error(_("warning: can't open %s: %s"),
+		      _PATH_FSTAB, strerror (errsv));
+		return;
+	}
+	read_mntentchn(mfp, fnam, mc);
+}
+     
+
+/* Given the name NAME, try to find it in mtab.  */ 
+struct mntentchn *
+getmntfile (const char *name) {
+	struct mntentchn *mc, *mc0;
+
+	mc0 = mtab_head();
+	for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
+		if (streq(mc->m.mnt_dir, name) ||
+		    streq(mc->m.mnt_fsname, name))
+			return mc;
+	return NULL;
+}
+
+/*
+ * Given the directory name NAME, and the place MCPREV we found it last time,
+ * try to find more occurrences.
+ */ 
+struct mntentchn *
+getmntdirbackward (const char *name, struct mntentchn *mcprev) {
+	struct mntentchn *mc, *mc0;
+
+	mc0 = mtab_head();
+	if (!mcprev)
+		mcprev = mc0;
+	for (mc = mcprev->prev; mc && mc != mc0; mc = mc->prev)
+		if (streq(mc->m.mnt_dir, name))
+			return mc;
+	return NULL;
+}
+
+/*
+ * Given the device name NAME, and the place MCPREV we found it last time,
+ * try to find more occurrences.
+ */ 
+struct mntentchn *
+getmntdevbackward (const char *name, struct mntentchn *mcprev) {
+	struct mntentchn *mc, *mc0;
+
+	mc0 = mtab_head();
+	if (!mcprev)
+		mcprev = mc0;
+	for (mc = mcprev->prev; mc && mc != mc0; mc = mc->prev)
+		if (streq(mc->m.mnt_fsname, name))
+			return mc;
+	return NULL;
+}
+
+/*
+ * Given the name NAME, check that it occurs precisely once as dir or dev.
+ */
+int
+is_mounted_once(const char *name) {
+	struct mntentchn *mc, *mc0;
+	int ct = 0;
+
+	mc0 = mtab_head();
+	for (mc = mc0->prev; mc && mc != mc0; mc = mc->prev)
+		if (streq(mc->m.mnt_dir, name) ||
+		    streq(mc->m.mnt_fsname, name))
+			ct++;
+	return (ct == 1);
+}
+
+/* Given the name FILE, try to find the option "loop=FILE" in mtab.  */ 
+struct mntentchn *
+getmntoptfile (const char *file) {
+	struct mntentchn *mc, *mc0;
+	char *opts, *s;
+	int l;
+
+	if (!file)
+		return NULL;
+
+	l = strlen(file);
+
+	mc0 = mtab_head();
+	for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
+		if ((opts = mc->m.mnt_opts) != NULL
+		    && (s = strstr(opts, "loop="))
+		    && !strncmp(s+5, file, l)
+		    && (s == opts || s[-1] == ',')
+		    && (s[l+5] == 0 || s[l+5] == ','))
+			return mc;
+	return NULL;
+}
+
+static int
+has_label(const char *device, const char *label) {
+	char devuuid[16];
+	char *devlabel;
+
+	return !get_label_uuid(device, &devlabel, devuuid) &&
+		!strcmp(label, devlabel);
+}
+
+static int
+has_uuid(const char *device, const char *uuid){
+	char devuuid[16];
+	char *devlabel;
+
+	return !get_label_uuid(device, &devlabel, devuuid) &&
+		!memcmp(uuid, devuuid, sizeof(devuuid));
+}
+
+/* Find the entry (SPEC,FILE) in fstab */
+struct mntentchn *
+getfsspecfile (const char *spec, const char *file) {
+	struct mntentchn *mc, *mc0;
+
+	mc0 = fstab_head();
+
+	/* first attempt: names occur precisely as given */
+	for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
+		if (streq(mc->m.mnt_dir, file) &&
+		    streq(mc->m.mnt_fsname, spec))
+			return mc;
+
+	/* second attempt: names found after symlink resolution */
+	for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
+		if ((streq(mc->m.mnt_dir, file) ||
+		     streq(canonicalize(mc->m.mnt_dir), file))
+		    && (streq(mc->m.mnt_fsname, spec) ||
+			streq(canonicalize(mc->m.mnt_fsname), spec)))
+			return mc;
+
+	/* third attempt: names found after LABEL= or UUID= resolution */
+	for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt) {
+		if (!strncmp (mc->m.mnt_fsname, "LABEL=", 6) &&
+		    (streq(mc->m.mnt_dir, file) ||
+		     streq(canonicalize(mc->m.mnt_dir), file))) {
+			if (has_label(spec, mc->m.mnt_fsname+6))
+				return mc;
+		}
+		if (!strncmp (mc->m.mnt_fsname, "UUID=", 5) &&
+		    (streq(mc->m.mnt_dir, file) ||
+		     streq(canonicalize(mc->m.mnt_dir), file))) {
+			if (has_uuid(spec, mc->m.mnt_fsname+5))
+				return mc;
+		}
+	}
+	return NULL;
+}
+
+/* Find the dir FILE in fstab.  */
+struct mntentchn *
+getfsfile (const char *file) {
+	struct mntentchn *mc, *mc0;
+
+	mc0 = fstab_head();
+	for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
+		if (streq(mc->m.mnt_dir, file))
+			return mc;
+	return NULL;
+}
+
+/* Find the device SPEC in fstab.  */
+struct mntentchn *
+getfsspec (const char *spec) {
+	struct mntentchn *mc, *mc0;
+
+	mc0 = fstab_head();
+	for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
+		if (streq(mc->m.mnt_fsname, spec))
+			return mc;
+	return NULL;
+}
+
+/* Find the uuid UUID in fstab. */
+struct mntentchn *
+getfsuuidspec (const char *uuid) {
+	struct mntentchn *mc, *mc0;
+
+	mc0 = fstab_head();
+	for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
+		if (strncmp (mc->m.mnt_fsname, "UUID=", 5) == 0
+		    && streq(mc->m.mnt_fsname + 5, uuid))
+			return mc;
+	return NULL;
+}
+
+/* Find the label LABEL in fstab. */
+struct mntentchn *
+getfsvolspec (const char *label) {
+	struct mntentchn *mc, *mc0;
+
+	mc0 = fstab_head();
+	for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
+		if (strncmp (mc->m.mnt_fsname, "LABEL=", 6) == 0
+		    && streq(mc->m.mnt_fsname + 6, label))
+			return mc;
+	return NULL;
+}
+
+/* Updating mtab ----------------------------------------------*/
+
+/* Flag for already existing lock file. */
+static int we_created_lockfile = 0;
+
+/* Flag to indicate that signals have been set up. */
+static int signals_have_been_setup = 0;
+
+/* Ensure that the lock is released if we are interrupted.  */
+static void
+handler (int sig) {
+     die (EX_USER, "%s", sys_siglist[sig]);
+}
+
+static void
+setlkw_timeout (int sig) {
+     /* nothing, fcntl will fail anyway */
+}
+
+/* Create the lock file.
+   The lock file will be removed if we catch a signal or when we exit. */
+/* The old code here used flock on a lock file /etc/mtab~ and deleted
+   this lock file afterwards. However, as rgooch remarks, that has a
+   race: a second mount may be waiting on the lock and proceed as
+   soon as the lock file is deleted by the first mount, and immediately
+   afterwards a third mount comes, creates a new /etc/mtab~, applies
+   flock to that, and also proceeds, so that the second and third mount
+   now both are scribbling in /etc/mtab.
+   The new code uses a link() instead of a creat(), where we proceed
+   only if it was us that created the lock, and hence we always have
+   to delete the lock afterwards. Now the use of flock() is in principle
+   superfluous, but avoids an arbitrary sleep(). */
+
+/* Where does the link point to? Obvious choices are mtab and mtab~~.
+   HJLu points out that the latter leads to races. Right now we use
+   mtab~.<pid> instead. */
+#define MOUNTLOCK_LINKTARGET	MOUNTED_LOCK "%d"
+
+void
+lock_mtab (void) {
+	int tries = 3;
+	char *linktargetfile;
+
+	if (!signals_have_been_setup) {
+		int sig = 0;
+		struct sigaction sa;
+
+		sa.sa_handler = handler;
+		sa.sa_flags = 0;
+		sigfillset (&sa.sa_mask);
+  
+		while (sigismember (&sa.sa_mask, ++sig) != -1
+		       && sig != SIGCHLD) {
+			if (sig == SIGALRM)
+				sa.sa_handler = setlkw_timeout;
+			else
+				sa.sa_handler = handler;
+			sigaction (sig, &sa, (struct sigaction *) 0);
+		}
+		signals_have_been_setup = 1;
+	}
+
+	/* somewhat clumsy, but some ancient systems do not have snprintf() */
+	/* use 20 as upper bound for the length of %d output */
+	linktargetfile = xmalloc(strlen(MOUNTLOCK_LINKTARGET) + 20);
+	sprintf(linktargetfile, MOUNTLOCK_LINKTARGET, getpid ());
+
+	/* Repeat until it was us who made the link */
+	while (!we_created_lockfile) {
+		struct flock flock;
+		int errsv, fd, i, j;
+
+		i = open (linktargetfile, O_WRONLY|O_CREAT, 0);
+		if (i < 0) {
+			int errsv = errno;
+			/* linktargetfile does not exist (as a file)
+			   and we cannot create it. Read-only filesystem?
+			   Too many files open in the system?
+			   Filesystem full? */
+			die (EX_FILEIO, _("can't create lock file %s: %s "
+			     "(use -n flag to override)"),
+			     linktargetfile, strerror (errsv));
+		}
+		close(i);
+
+		j = link(linktargetfile, MOUNTED_LOCK);
+		errsv = errno;
+
+		(void) unlink(linktargetfile);
+
+		if (j < 0 && errsv != EEXIST) {
+			die (EX_FILEIO, _("can't link lock file %s: %s "
+			     "(use -n flag to override)"),
+			     MOUNTED_LOCK, strerror (errsv));
+		}
+
+		fd = open (MOUNTED_LOCK, O_WRONLY);
+
+		if (fd < 0) {
+			int errsv = errno;
+			/* Strange... Maybe the file was just deleted? */
+			if (errno == ENOENT && tries-- > 0)
+				continue;
+			die (EX_FILEIO, _("can't open lock file %s: %s "
+			     "(use -n flag to override)"),
+			     MOUNTED_LOCK, strerror (errsv));
+		}
+
+		flock.l_type = F_WRLCK;
+		flock.l_whence = SEEK_SET;
+		flock.l_start = 0;
+		flock.l_len = 0;
+
+		if (j == 0) {
+			/* We made the link. Now claim the lock. */
+			if (fcntl (fd, F_SETLK, &flock) == -1) {
+				if (verbose) {
+				    int errsv = errno;
+				    printf(_("Can't lock lock file %s: %s\n"),
+					   MOUNTED_LOCK, strerror (errsv));
+				}
+				/* proceed anyway */
+			}
+			we_created_lockfile = 1;
+		} else {
+			static int tries = 0;
+
+			/* Someone else made the link. Wait. */
+			alarm(LOCK_TIMEOUT);
+			if (fcntl (fd, F_SETLKW, &flock) == -1) {
+				int errsv = errno;
+				die (EX_FILEIO, _("can't lock lock file %s: %s"),
+				     MOUNTED_LOCK, (errno == EINTR) ?
+				     _("timed out") : strerror (errsv));
+			}
+			alarm(0);
+			/* Limit the number of iterations - maybe there
+			   still is some old /etc/mtab~ */
+			if (tries++ > 3) {
+				if (tries > 5)
+					die (EX_FILEIO, _("Cannot create link %s\n"
+					    "Perhaps there is a stale lock file?\n"),
+					     MOUNTED_LOCK);
+				sleep(1);
+			}
+		}
+
+		close(fd);
+	}
+}
+
+/* Remove lock file.  */
+void
+unlock_mtab (void) {
+	if (we_created_lockfile) {
+		unlink (MOUNTED_LOCK);
+		we_created_lockfile = 0;
+	}
+}
+
+/*
+ * Update the mtab.
+ *  Used by umount with null INSTEAD: remove the last DIR entry.
+ *  Used by mount upon a remount: update option part,
+ *   and complain if a wrong device or type was given.
+ *   [Note that often a remount will be a rw remount of /
+ *    where there was no entry before, and we'll have to believe
+ *    the values given in INSTEAD.]
+ */
+
+void
+update_mtab (const char *dir, struct mntent *instead) {
+	mntFILE *mfp, *mftmp;
+	const char *fnam = MOUNTED;
+	struct mntentchn mtabhead;	/* dummy */
+	struct mntentchn *mc, *mc0, absent;
+
+	if (mtab_does_not_exist() || mtab_is_a_symlink())
+		return;
+
+	lock_mtab();
+
+	/* having locked mtab, read it again */
+	mc0 = mc = &mtabhead;
+	mc->nxt = mc->prev = NULL;
+
+	mfp = my_setmntent(fnam, "r");
+	if (mfp == NULL || mfp->mntent_fp == NULL) {
+		int errsv = errno;
+		error (_("cannot open %s (%s) - mtab not updated"),
+		       fnam, strerror (errsv));
+		goto leave;
+	}
+
+	read_mntentchn(mfp, fnam, mc);
+
+	/* find last occurrence of dir */
+	for (mc = mc0->prev; mc && mc != mc0; mc = mc->prev)
+		if (streq(mc->m.mnt_dir, dir))
+			break;
+	if (mc && mc != mc0) {
+		if (instead == NULL) {
+			/* An umount - remove entry */
+			if (mc && mc != mc0) {
+				mc->prev->nxt = mc->nxt;
+				mc->nxt->prev = mc->prev;
+			}
+		} else {
+			/* A remount */
+			mc->m.mnt_opts = instead->mnt_opts;
+		}
+	} else if (instead) {
+		/* not found, add a new entry */
+		absent.m = *instead;
+		absent.nxt = mc0;
+		absent.prev = mc0->prev;
+		mc0->prev = &absent;
+		if (mc0->nxt == NULL)
+			mc0->nxt = &absent;
+	}
+
+	/* write chain to mtemp */
+	mftmp = my_setmntent (MOUNTED_TEMP, "w");
+	if (mftmp == NULL || mftmp->mntent_fp == NULL) {
+		int errsv = errno;
+		error (_("cannot open %s (%s) - mtab not updated"),
+		       MOUNTED_TEMP, strerror (errsv));
+		goto leave;
+	}
+
+	for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt) {
+		if (my_addmntent(mftmp, &(mc->m)) == 1) {
+			int errsv = errno;
+			die (EX_FILEIO, _("error writing %s: %s"),
+			     MOUNTED_TEMP, strerror (errsv));
+		}
+	}
+
+	if (fchmod (fileno (mftmp->mntent_fp),
+		    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
+		int errsv = errno;
+		fprintf(stderr, _("error changing mode of %s: %s\n"),
+			MOUNTED_TEMP, strerror (errsv));
+	}
+	my_endmntent (mftmp);
+
+	{ /*
+	   * If mount is setuid and some non-root user mounts sth,
+	   * then mtab.tmp might get the group of this user. Copy uid/gid
+	   * from the present mtab before renaming.
+	   */
+	    struct stat sbuf;
+	    if (stat (MOUNTED, &sbuf) == 0)
+		chown (MOUNTED_TEMP, sbuf.st_uid, sbuf.st_gid);
+	}
+
+	/* rename mtemp to mtab */
+	if (rename (MOUNTED_TEMP, MOUNTED) < 0) {
+		int errsv = errno;
+		fprintf(stderr, _("can't rename %s to %s: %s\n"),
+			MOUNTED_TEMP, MOUNTED, strerror(errsv));
+	}
+
+ leave:
+	unlock_mtab();
+}

Added: trunk/mount.ocfs2/fstab.h
===================================================================
--- trunk/mount.ocfs2/fstab.h	2005-03-15 23:04:40 UTC (rev 641)
+++ trunk/mount.ocfs2/fstab.h	2005-03-15 23:25:37 UTC (rev 642)
@@ -0,0 +1,38 @@
+#include <mntent.h>
+#define _PATH_FSTAB	"/etc/fstab"
+#ifdef _PATH_MOUNTED
+#define MOUNTED_LOCK	_PATH_MOUNTED "~"
+#define MOUNTED_TEMP	_PATH_MOUNTED ".tmp"
+#else
+#define MOUNTED_LOCK	"/etc/mtab~"
+#define MOUNTED_TEMP	"/etc/mtab.tmp"
+#endif
+#define LOCK_TIMEOUT	10
+
+int mtab_is_writable(void);
+int mtab_does_not_exist(void);
+int mtab_is_a_symlink(void);
+int is_mounted_once(const char *name);
+
+struct mntentchn {
+	struct mntentchn *nxt, *prev;
+	struct mntent m;
+};
+
+struct mntentchn *mtab_head (void);
+struct mntentchn *getmntfile (const char *name);
+struct mntentchn *getmntoptfile (const char *file);
+struct mntentchn *getmntdirbackward (const char *dir, struct mntentchn *mc);
+struct mntentchn *getmntdevbackward (const char *dev, struct mntentchn *mc);
+
+struct mntentchn *fstab_head (void);
+struct mntentchn *getfsfile (const char *file);
+struct mntentchn *getfsspec (const char *spec);
+struct mntentchn *getfsspecfile (const char *spec, const char *file);
+struct mntentchn *getfsuuidspec (const char *uuid);
+struct mntentchn *getfsvolspec (const char *label);
+
+#include <mntent.h>
+void lock_mtab (void);
+void unlock_mtab (void);
+void update_mtab (const char *special, struct mntent *with);

Added: trunk/mount.ocfs2/get_label_uuid.c
===================================================================
--- trunk/mount.ocfs2/get_label_uuid.c	2005-03-15 23:04:40 UTC (rev 641)
+++ trunk/mount.ocfs2/get_label_uuid.c	2005-03-15 23:25:37 UTC (rev 642)
@@ -0,0 +1,174 @@
+/*
+ * Get label. Used by both mount and umount.
+ */
+#define _GNU_SOURCE 
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <endian.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include "linux_fs.h"
+#include "get_label_uuid.h"
+
+/*
+ * See whether this device has (the magic of) a RAID superblock at the end.
+ * If so, it probably is, or has been, part of a RAID array.
+ *
+ * For the moment this test is switched off - it causes problems.
+ * "Checking for a disk label should only be done on the full raid,
+ *  not on the disks that form the raid array. This test causes a lot of
+ *  problems when run on my striped promise fasttrak 100 array."
+ */
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define INT32_FROM_LE(val)        ((unsigned int) ( \
+    (((unsigned int) (val) & (unsigned int) 0x000000ffU) << 24) | \
+    (((unsigned int) (val) & (unsigned int) 0x0000ff00U) <<  8) | \
+    (((unsigned int) (val) & (unsigned int) 0x00ff0000U) >>  8) | \
+    (((unsigned int) (val) & (unsigned int) 0xff000000U) >> 24)))
+#else
+#define INT32_FROM_LE(val) (val)
+#endif
+
+typedef struct {
+	unsigned int md_magic;
+} mdp_super_t;
+#ifndef MD_SB_MAGIC
+#define MD_SB_MAGIC		0xa92b4efc
+#endif
+#ifndef MD_RESERVED_BYTES
+#define MD_RESERVED_BYTES 65536L
+#endif
+#ifndef MD_NEW_SIZE_BYTES
+#define MD_NEW_SIZE_BYTES(x)		((x & ~(MD_RESERVED_BYTES - 1L)) - MD_RESERVED_BYTES)
+#endif
+
+static int
+is_raid_partition(int fd)
+{
+        mdp_super_t mdsb;
+        int n;
+	struct stat sbuf;
+ 	if(fstat(fd, &sbuf))
+	  return 2;
+	if(!sbuf.st_size) {
+		uint64_t bsize64;
+		unsigned int bsize32;
+		if(!ioctl(fd, BLKGETSIZE64, &bsize64))
+			sbuf.st_size = bsize64;
+		else if(!ioctl(fd, BLKGETSIZE, &bsize32))
+			sbuf.st_size = bsize32;
+	}
+	if(!sbuf.st_size) return 3;
+	/* hardcode 4096 here in various places,
+	   because that's what it's defined to be.
+	   Note that even if we used the actual kernel headers,
+	   sizeof(mdp_super_t) is slightly larger in the 2.2 kernel on 64-bit
+	   archs, so using that wouldn't work. */
+	lseek(fd, MD_NEW_SIZE_BYTES(sbuf.st_size), SEEK_SET);
+	n = 4096; if(sizeof(mdsb) < n) n = sizeof(mdsb);
+        if(read(fd, &mdsb, n) != n)
+	  return 4; /* error */
+	mdsb.md_magic = INT32_FROM_LE(mdsb.md_magic);
+	return (mdsb.md_magic == MD_SB_MAGIC); /* If this device has a
+						  RAID superblock at
+						  the end, it must be
+						  part of a RAID
+						  array. */
+}
+
+/* for now, only ext2, ext3, xfs, ocfs are supported */
+int
+get_label_uuid(const char *device, char **label, char *uuid) {
+	int fd;
+	int rv = 1;
+	size_t namesize;
+	struct ext2_super_block e2sb;
+	struct xfs_super_block xfsb;
+	struct jfs_super_block jfssb;
+	struct ocfs_volume_header ovh;	/* Oracle */
+	struct ocfs_volume_label olbl;
+	union {
+	  struct swap_header_v1_2 hdr;
+	  char swap_data[1<<16];
+	} swap_u;
+
+	fd = open(device, O_RDONLY);
+	if (fd < 0)
+		return rv;
+
+	/* If there is a RAID partition, or an error, ignore this partition */
+	if (is_raid_partition(fd)) {
+		close(fd);
+		return rv;
+	}
+
+ 	if(getpagesize() > sizeof(swap_u.swap_data)) {
+ 		errno = EFAULT;
+ 		return 1;
+ 	}
+
+	if (lseek(fd, 1024, SEEK_SET) == 1024
+	    && read(fd, (char *) &e2sb, sizeof(e2sb)) == sizeof(e2sb)
+	    && (ext2magic(e2sb) == EXT2_SUPER_MAGIC)) {
+		memcpy(uuid, e2sb.s_uuid, sizeof(e2sb.s_uuid));
+		namesize = sizeof(e2sb.s_volume_name);
+		if ((*label = calloc(namesize + 1, 1)) != NULL)
+			memcpy(*label, e2sb.s_volume_name, namesize);
+		rv = 0;
+	}
+	else if (lseek(fd, 0, SEEK_SET) == 0
+	    && read(fd, (char *) &xfsb, sizeof(xfsb)) == sizeof(xfsb)
+	    && (strncmp(xfsb.s_magic, XFS_SUPER_MAGIC, 4) == 0)) {
+		memcpy(uuid, xfsb.s_uuid, sizeof(xfsb.s_uuid));
+		namesize = sizeof(xfsb.s_fname);
+		if ((*label = calloc(namesize + 1, 1)) != NULL)
+			memcpy(*label, xfsb.s_fname, namesize);
+		rv = 0;
+	}
+	else if (lseek(fd, 0, SEEK_SET) == 0
+	    && read(fd, (char *) &ovh, sizeof(ovh)) == sizeof(ovh)
+	    && (strncmp(ovh.signature, OCFS_MAGIC, sizeof(OCFS_MAGIC)) == 0)
+	    && (lseek(fd, 512, SEEK_SET) == 512)
+	    && read(fd, (char *) &olbl, sizeof(olbl)) == sizeof(olbl)) {
+		uuid[0] = '\0';
+		namesize = ocfslabellen(olbl);
+		if ((*label = calloc(namesize + 1, 1)) != NULL)
+			memcpy(*label, olbl.label, namesize);
+		rv = 0;
+	}
+	else if (lseek(fd, JFS_SUPER1_OFF, SEEK_SET) == JFS_SUPER1_OFF
+	    && read(fd, (char *) &jfssb, sizeof(jfssb)) == sizeof(jfssb)
+	    && (strncmp(jfssb.s_magic, JFS_MAGIC, 4) == 0)) {
+		if (assemble4le(jfssb.s_version) == 1) {
+			/* old (OS/2 compatible) jfs filesystems don't
+			   have UUIDs and only have a very small label. */
+			memset(uuid, 0, 16);
+			namesize = sizeof(jfssb.s_fpack);
+			if ((*label = calloc(namesize + 1, 1)) != NULL)
+				memcpy(*label, jfssb.s_fpack, namesize);
+		} else {
+			memcpy(uuid, jfssb.s_uuid, sizeof(jfssb.s_uuid));
+			namesize = sizeof(jfssb.s_label);
+			if ((*label = calloc(namesize + 1, 1)) != NULL)
+			    memcpy(*label, jfssb.s_label, namesize);
+		}
+		rv = 0;
+	}
+	else if (lseek(fd, 0, SEEK_SET) == 0
+		 && read(fd, &swap_u, getpagesize()) == getpagesize()
+		 && !strncmp(swap_u.swap_data+getpagesize()-10, "SWAPSPACE2", strlen("SWAPSPACE2"))) {
+	  memcpy(uuid, swap_u.hdr.uuid, sizeof(swap_u.hdr.uuid));
+	  if(label)
+	    *label = swap_u.hdr.volume_name[0]?strndup(swap_u.hdr.volume_name, sizeof(swap_u.hdr.volume_name)):NULL;
+	  rv = 0;
+	}
+	  
+
+	close(fd);
+	return rv;
+}

Added: trunk/mount.ocfs2/get_label_uuid.h
===================================================================
--- trunk/mount.ocfs2/get_label_uuid.h	2005-03-15 23:04:40 UTC (rev 641)
+++ trunk/mount.ocfs2/get_label_uuid.h	2005-03-15 23:25:37 UTC (rev 642)
@@ -0,0 +1 @@
+int get_label_uuid(const char *device, char **label, char *uuid);

Added: trunk/mount.ocfs2/linux_fs.h
===================================================================
--- trunk/mount.ocfs2/linux_fs.h	2005-03-15 23:04:40 UTC (rev 641)
+++ trunk/mount.ocfs2/linux_fs.h	2005-03-15 23:25:37 UTC (rev 642)
@@ -0,0 +1,296 @@
+/* Including <linux/fs.h> became more and more painful.
+   Below a very abbreviated version of some declarations,
+   only designed to be able to check a magic number
+   in case no filesystem type was given. */
+
+#ifndef BLKGETSIZE
+#ifndef _IO
+/* pre-1.3.45 */
+#define BLKGETSIZE 0x1260		   /* return device size */
+#else
+/* same on i386, m68k, arm; different on alpha, mips, sparc, ppc */
+#define BLKGETSIZE _IO(0x12,96)
+#endif
+#endif
+
+#include <inttypes.h>
+#ifndef BLKGETSIZE64
+#include <sys/ioctl.h>
+#define BLKGETSIZE64 _IOR(0x12,114,sizeof(uint64_t))
+#endif
+
+#define MINIX_SUPER_MAGIC   0x137F         /* minix v1, 14 char names */
+#define MINIX_SUPER_MAGIC2  0x138F         /* minix v1, 30 char names */
+#define MINIX2_SUPER_MAGIC  0x2468	   /* minix v2, 14 char names */
+#define MINIX2_SUPER_MAGIC2 0x2478         /* minix v2, 30 char names */
+struct minix_super_block {
+	u_char   s_dummy[16];
+	u_char   s_magic[2];
+};
+#define minixmagic(s)	assemble2le(s.s_magic)
+
+#define ISODCL(from, to) (to - from + 1)
+#define ISO_STANDARD_ID "CD001"
+struct iso_volume_descriptor {
+	char type[ISODCL(1,1)]; /* 711 */
+	char id[ISODCL(2,6)];
+	char version[ISODCL(7,7)];
+	char data[ISODCL(8,2048)];
+};
+
+#define HS_STANDARD_ID "CDROM"
+struct  hs_volume_descriptor {
+	char foo[ISODCL (  1,   8)]; /* 733 */
+	char type[ISODCL (  9,   9)]; /* 711 */
+	char id[ISODCL ( 10,  14)];
+	char version[ISODCL ( 15,  15)]; /* 711 */
+	char data[ISODCL(16,2048)];
+};
+
+#define EXT_SUPER_MAGIC 0x137D
+struct ext_super_block {
+	u_char   s_dummy[56];
+	u_char   s_magic[2];
+};
+#define extmagic(s)	assemble2le(s.s_magic)
+
+#define EXT2_PRE_02B_MAGIC  0xEF51
+#define EXT2_SUPER_MAGIC    0xEF53
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
+struct ext2_super_block {
+	u_char 	s_dummy1[56];
+	u_char 	s_magic[2];
+	u_char	s_dummy2[34];
+	u_char	s_feature_compat[4];
+	u_char	s_feature_incompat[4];
+	u_char	s_feature_ro_compat[4];
+	u_char	s_uuid[16];
+	u_char 	s_volume_name[16];
+	u_char	s_dummy3[88];
+	u_char	s_journal_inum[4];	/* ext3 only */
+};
+#define ext2magic(s)	assemble2le(s.s_magic)
+
+struct reiserfs_super_block
+{
+	u_char		s_block_count[4];
+	u_char		s_free_blocks[4];
+	u_char		s_root_block[4];
+	u_char		s_journal_block[4];
+	u_char		s_journal_dev[4];
+	u_char		s_orig_journal_size[4];
+	u_char		s_journal_trans_max[4];
+	u_char		s_journal_block_count[4];
+	u_char		s_journal_max_batch[4];
+	u_char		s_journal_max_commit_age[4];
+	u_char		s_journal_max_trans_age[4];
+	u_char		s_blocksize[2];
+	u_char		s_oid_maxsize[2];
+	u_char		s_oid_cursize[2];
+	u_char		s_state[2];
+	u_char		s_magic[12];
+};
+#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
+#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
+#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)
+/* the spot for the super in versions 3.5 - 3.5.10 (inclusive) */
+#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024)
+
+#define _XIAFS_SUPER_MAGIC 0x012FD16D
+struct xiafs_super_block {
+    u_char     s_boot_segment[512];     /*  1st sector reserved for boot */
+    u_char     s_dummy[60];
+    u_char     s_magic[4];
+};
+#define xiafsmagic(s)	assemble4le(s.s_magic)
+
+/* From jj at sunsite.ms.mff.cuni.cz Mon Mar 23 15:19:05 1998 */
+#define UFS_SUPER_MAGIC_LE 0x00011954
+#define UFS_SUPER_MAGIC_BE 0x54190100
+struct ufs_super_block {
+    u_char     s_dummy[0x55c];
+    u_char     s_magic[4];
+};
+#define ufsmagic(s)	assemble4le(s.s_magic)
+
+/* From Richard.Russon at ait.co.uk Wed Feb 24 08:05:27 1999 */
+#define NTFS_SUPER_MAGIC "NTFS"
+struct ntfs_super_block {
+    u_char    s_dummy[3];
+    u_char    s_magic[4];
+};
+
+/* From inspection of a few FAT filesystems - aeb */
+/* Unfortunately I find almost the same thing on an extended partition;
+   it looks like a primary has some directory entries where the extended
+   has a partition table: IO.SYS, MSDOS.SYS, WINBOOT.SYS */
+struct fat_super_block {
+    u_char    s_dummy[3];
+    u_char    s_os[8];		/* "MSDOS5.0" or "MSWIN4.0" or "MSWIN4.1" */
+				/* mtools-3.9.4 writes "MTOOL394" */
+    u_char    s_dummy2[32];
+    u_char    s_label[11];	/* for DOS? */
+    u_char    s_fs[8];		/* "FAT12   " or "FAT16   " or all zero   */
+                                /* OS/2 BM has "FAT     " here. */
+    u_char    s_dummy3[9];
+    u_char    s_label2[11];	/* for Windows? */
+    u_char    s_fs2[8];	        /* garbage or "FAT32   " */
+};
+
+#define XFS_SUPER_MAGIC "XFSB"
+struct xfs_super_block {
+    u_char    s_magic[4];
+    u_char    s_dummy[28];
+    u_char    s_uuid[16];
+    u_char    s_dummy2[60];
+    u_char    s_fname[12];
+};
+
+#define CRAMFS_SUPER_MAGIC 0x28cd3d45
+#define CRAMFS_SUPER_MAGIC_BE 0x453dcd28
+struct cramfs_super_block {
+	u_char    s_magic[4];
+	u_char    s_dummy[12];
+	u_char    s_id[16];
+};
+#define cramfsmagic(s)	assemble4le(s.s_magic)
+
+#define HFS_SUPER_MAGIC 0x4244
+struct hfs_super_block {
+	u_char    s_magic[2];		/* drSigWord */
+	u_char    s_dummy[18];
+	u_char    s_blksize[4];		/* drAlBlkSiz */
+};
+#define hfsmagic(s)	assemble2be(s.s_magic)
+#define hfsblksize(s)	assemble4be(s.s_blksize)
+
+#define HPFS_SUPER_MAGIC 0xf995e849
+struct hpfs_super_block {
+	u_char    s_magic[4];
+	u_char    s_magic2[4];
+};
+#define hpfsmagic(s)	assemble4le(s.s_magic)
+
+struct adfs_super_block {
+	u_char    s_dummy[448];
+	u_char    s_blksize[1];
+	u_char    s_dummy2[62];
+	u_char    s_checksum[1];
+};
+#define adfsblksize(s)	((uint) s.s_blksize[0])
+
+/* found in first 4 bytes of block 1 */
+struct vxfs_super_block {
+	u_char	s_magic[4];
+};
+#define vxfsmagic(s)	assemble4le(s.s_magic)
+#define VXFS_SUPER_MAGIC 0xa501FCF5
+
+struct jfs_super_block {
+	char	s_magic[4];
+	u_char	s_version[4];
+	u_char	s_dummy1[93];
+	char	s_fpack[11];
+	u_char	s_dummy2[24];
+	u_char	s_uuid[16];
+	char	s_label[16];
+};
+#define JFS_SUPER1_OFF 0x8000
+#define JFS_MAGIC "JFS1"
+
+struct sysv_super_block {
+	u_char  s_dummy1[504];
+	u_char  s_magic[4];
+	u_char  type[4];
+};
+#define sysvmagic(s)		assemble4le(s.s_magic)
+#define SYSV_SUPER_MAGIC	0xfd187e20
+
+struct mdp_super_block {
+	u_char	md_magic[4];
+};
+#define MD_SB_MAGIC	0xa92b4efc
+#define mdsbmagic(s)	assemble4le(s.md_magic)
+
+struct ocfs_volume_header {
+	u_char  minor_version[4];
+	u_char  major_version[4];
+	u_char  signature[128];
+};
+
+struct ocfs_volume_label {
+	u_char  disk_lock[48];
+	u_char  label[64];
+	u_char  label_len[2];
+};
+
+#define ocfslabellen(o)	assemble2le(o.label_len)
+#define OCFS_MAGIC	"OracleCFS"
+
+struct efs_volume_directory {	/* size 16 */
+        char    vd_name[8];
+        char    vd_lbn[4];
+        char    vd_nbytes[4];
+};
+
+struct efs_partition_table {	/* size 12 */
+        char    pt_nblks[4];
+        char    pt_firstlbn[4];
+        char    pt_type[4];
+};
+
+struct efs_volume_header {	/* size 512 */
+        char    vh_magic[4];
+        short   vh_rootpt;
+        short   vh_swappt;
+        char    vh_bootfile[16];
+        char    pad[48];
+        struct efs_volume_directory vh_vd[15];
+        struct efs_partition_table  vh_pt[16];
+        int     vh_csum;
+        int     vh_fill;
+};
+
+struct efs_super {
+        char     fs_stuff[512+28];
+        char     fs_magic[4];
+        char     fs_fname[6];
+        char     fs_fpack[6];
+	/* ... */
+};
+
+#define EFS_VHMAGIC	0x0be5a941	/* big endian */
+#define EFS_SBMAGIC	0x00072959	/* idem */
+#define EFS_SBMAGIC2	0x0007295a	/* idem */
+
+static inline int
+assemble2le(unsigned char *p) {
+	return (p[0] | (p[1] << 8));
+}
+
+static inline int
+assemble2be(unsigned char *p) {
+	return (p[1] | (p[0] << 8));
+}
+
+static inline int
+assemble4le(unsigned char *p) {
+	return (p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24));
+}
+
+static inline int
+assemble4be(unsigned char *p) {
+	return (p[3] | (p[2] << 8) | (p[1] << 16) | (p[0] << 24));
+}
+
+/* Linux swap */
+struct swap_header_v1_2 {
+	char         bootbits[1024];    /* Space for disklabel etc. */
+	unsigned int version;
+	unsigned int last_page;
+	unsigned int nr_badpages;
+	char	     uuid[16];
+	char	     volume_name[16];
+	unsigned int padding[117];
+	unsigned int badpages[1];
+};

Added: trunk/mount.ocfs2/mntent.c
===================================================================
--- trunk/mount.ocfs2/mntent.c	2005-03-15 23:04:40 UTC (rev 641)
+++ trunk/mount.ocfs2/mntent.c	2005-03-15 23:25:37 UTC (rev 642)
@@ -0,0 +1,224 @@
+/* Private version of the libc *mntent() routines. */
+/* Note slightly different prototypes. */
+
+/* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek at pld.ORG.PL>
+ * - added Native Language Support
+ */
+
+#include <stdio.h>
+#include <string.h>		/* for index */
+#include <ctype.h>		/* for isdigit */
+#include <sys/stat.h>		/* for umask */
+#include "mntent.h"
+#include "sundries.h"		/* for xmalloc */
+#include "nls.h"
+
+/* Unfortunately the classical Unix /etc/mtab and /etc/fstab
+   do not handle directory names containing spaces.
+   Here we mangle them, replacing a space by \040.
+   What do other Unices do? */
+
+static unsigned char need_escaping[] = { ' ', '\t', '\n', '\\' };
+
+static char *
+mangle(unsigned char *s) {
+	char *ss, *sp;
+	int n;
+
+	n = strlen(s);
+	ss = sp = xmalloc(4*n+1);
+	while(1) {
+		for (n = 0; n < sizeof(need_escaping); n++) {
+			if (*s == need_escaping[n]) {
+				*sp++ = '\\';
+				*sp++ = '0' + ((*s & 0300) >> 6);
+				*sp++ = '0' + ((*s & 070) >> 3);
+				*sp++ = '0' + (*s & 07);
+				goto next;
+			}
+		}
+		*sp++ = *s;
+		if (*s == 0)
+			break;
+	next:
+		s++;
+	}
+	return ss;
+}
+
+static int
+is_space_or_tab (char c) {
+	return (c == ' ' || c == '\t');
+}
+
+static char *
+skip_spaces(char *s) {
+	while (is_space_or_tab(*s))
+		s++;
+	return s;
+}
+
+static char *
+skip_nonspaces(char *s) {
+	while (*s && !is_space_or_tab(*s))
+		s++;
+	return s;
+}
+
+#define isoctal(a) (((a) & ~7) == '0')
+
+/* returns malloced pointer - no more strdup required */
+static char *
+unmangle(char *s) {
+	char *ret, *ss, *sp;
+
+	ss = skip_nonspaces(s);
+	ret = sp = xmalloc(ss-s+1);
+	while(s != ss) {
+		if (*s == '\\' && isoctal(s[1]) && isoctal(s[2]) && isoctal(s[3])) {
+			*sp++ = 64*(s[1] & 7) + 8*(s[2] & 7) + (s[3] & 7);
+			s += 4;
+		} else
+			*sp++ = *s++;
+	}
+	*sp = 0;
+	return ret;
+}
+
+/*
+ * fstat'ing the file and allocating a buffer holding all of it
+ * may be a bad idea: if the file is /proc/mounts, the stat
+ * returns 0.
+ * (On the other hand, mangling and unmangling is meaningless
+ *  for /proc/mounts.)
+ */
+
+mntFILE *
+my_setmntent (const char *file, char *mode) {
+	mntFILE *mfp = xmalloc(sizeof(*mfp));
+	mode_t old_umask = umask(077);
+
+	mfp->mntent_fp = fopen (file, mode);
+	umask(old_umask);
+	mfp->mntent_file = xstrdup(file);
+	mfp->mntent_errs = (mfp->mntent_fp == NULL);
+	mfp->mntent_softerrs = 0;
+	mfp->mntent_lineno = 0;
+	return mfp;
+}
+
+void
+my_endmntent (mntFILE *mfp) {
+	if (mfp) {
+		if (mfp->mntent_fp)
+			fclose(mfp->mntent_fp);
+		if (mfp->mntent_file)
+			free(mfp->mntent_file);
+		free(mfp);
+	}
+}
+
+
+int
+my_addmntent (mntFILE *mfp, struct mntent *mnt) {
+	char *m1, *m2, *m3, *m4;
+	int res;
+
+	if (fseek (mfp->mntent_fp, 0, SEEK_END))
+		return 1;			/* failure */
+
+	m1 = mangle(mnt->mnt_fsname);
+	m2 = mangle(mnt->mnt_dir);
+	m3 = mangle(mnt->mnt_type);
+	m4 = mangle(mnt->mnt_opts);
+
+	res = ((fprintf (mfp->mntent_fp, "%s %s %s %s %d %d\n",
+			 m1, m2, m3, m4, mnt->mnt_freq, mnt->mnt_passno)
+		< 0) ? 1 : 0);
+
+	free(m1);
+	free(m2);
+	free(m3);
+	free(m4);
+	return res;
+}
+
+/* Read the next entry from the file fp. Stop reading at an incorrect entry. */
+struct mntent *
+my_getmntent (mntFILE *mfp) {
+	static char buf[4096];
+	static struct mntent me;
+	char *s;
+
+ again:
+	if (mfp->mntent_errs || mfp->mntent_softerrs >= ERR_MAX)
+		return NULL;
+
+	/* read the next non-blank non-comment line */
+	do {
+		if (fgets (buf, sizeof(buf), mfp->mntent_fp) == NULL)
+			return NULL;
+
+		mfp->mntent_lineno++;
+		s = index (buf, '\n');
+		if (s == NULL) {
+			/* Missing final newline?  Otherwise extremely */
+			/* long line - assume file was corrupted */
+			if (feof(mfp->mntent_fp)) {
+				fprintf(stderr, _("[mntent]: warning: no final "
+					"newline at the end of %s\n"),
+					mfp->mntent_file);
+				s = index (buf, 0);
+			} else {
+				mfp->mntent_errs = 1;
+				goto err;
+			}
+		}
+		*s = 0;
+		if (--s >= buf && *s == '\r')
+			*s = 0;
+		s = skip_spaces(buf);
+	} while (*s == '\0' || *s == '#');
+
+	me.mnt_fsname = unmangle(s);
+	s = skip_nonspaces(s);
+	s = skip_spaces(s);
+	me.mnt_dir = unmangle(s);
+	s = skip_nonspaces(s);
+	s = skip_spaces(s);
+	me.mnt_type = unmangle(s);
+	s = skip_nonspaces(s);
+	s = skip_spaces(s);
+	me.mnt_opts = unmangle(s);
+	s = skip_nonspaces(s);
+	s = skip_spaces(s);
+
+	if(isdigit(*s)) {
+		me.mnt_freq = atoi(s);
+		while(isdigit(*s)) s++;
+	} else
+		me.mnt_freq = 0;
+	if(*s && !is_space_or_tab(*s))
+		goto err;
+
+	s = skip_spaces(s);
+	if(isdigit(*s)) {
+		me.mnt_passno = atoi(s);
+		while(isdigit(*s)) s++;
+	} else
+		me.mnt_passno = 0;
+	if(*s && !is_space_or_tab(*s))
+		goto err;
+
+	/* allow more stuff, e.g. comments, on this line */
+
+	return &me;
+
+ err:
+	mfp->mntent_softerrs++;
+	fprintf(stderr, _("[mntent]: line %d in %s is bad%s\n"),
+		mfp->mntent_lineno, mfp->mntent_file,
+		(mfp->mntent_errs || mfp->mntent_softerrs >= ERR_MAX) ?
+		_("; rest of file ignored") : "");
+	goto again;
+}

Added: trunk/mount.ocfs2/mntent.h
===================================================================
--- trunk/mount.ocfs2/mntent.h	2005-03-15 23:04:40 UTC (rev 641)
+++ trunk/mount.ocfs2/mntent.h	2005-03-15 23:25:37 UTC (rev 642)
@@ -0,0 +1,16 @@
+#include <mntent.h>		/* for struct mntent */
+
+#define ERR_MAX 5
+
+typedef struct mntFILEstruct {
+	FILE *mntent_fp;
+	char *mntent_file;
+	int mntent_lineno;
+	int mntent_errs;
+	int mntent_softerrs;
+} mntFILE;
+
+mntFILE *my_setmntent (const char *file, char *mode);
+void my_endmntent (mntFILE *mfp);
+int my_addmntent (mntFILE *mfp, struct mntent *mnt);
+struct mntent *my_getmntent (mntFILE *mfp);

Modified: trunk/mount.ocfs2/mount.ocfs2.c
===================================================================
--- trunk/mount.ocfs2/mount.ocfs2.c	2005-03-15 23:04:40 UTC (rev 641)
+++ trunk/mount.ocfs2/mount.ocfs2.c	2005-03-15 23:25:37 UTC (rev 642)
@@ -1,6 +1,8 @@
 /*
- * Copyright (C) 2004 Oracle.  All rights reserved.
+ * mount.ocfs2.c  Mounts ocfs2 volume
  *
+ * Copyright (C) 2005 Oracle.  All rights reserved.
+ *
  * 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
@@ -16,384 +18,166 @@
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 021110-1307, USA.
  *
- * Authors: Sunil Mushran
  */
 
+#include "mount.ocfs2.h"
 
-#define _LARGEFILE64_SOURCE
-#define _GNU_SOURCE /* Because libc really doesn't want us using O_DIRECT? */
+int verbose = 0;
+int mount_quiet=0;
+int nomtab = 0;
+char *progname = NULL;
+char op_buf[PAGE_SIZE];
 
-#include <sys/types.h>
-#include <asm/types.h>
-#include <inttypes.h>
+struct mount_options {
+	char *dev;
+	char *dir;
+	char *opts;
+	int flags;
+	char *xtra_opts;
+};
 
-#define u8   __u8
-#define s8   __s8
-#define u16  __u16
-#define s16  __s16
-#define u32  __u32
-#define s32  __s32
-#define u64  __u64
-#define s64  __s64
-#define atomic_t int
-#define spinlock_t unsigned long
-typedef unsigned short kdev_t;
-
-
-
-
-#include <asm/page.h>
-#include <sys/mount.h>
-#include <dirent.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/fd.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#define  OCFS2_FLAT_INCLUDES	1
-#include <ocfs2.h>
-#include <ocfs2_fs.h>
-#include <ocfs1_fs_compat.h>
-#include <kernel-list.h>
-
-#include "bitops.h"
-
-#include "ocfs2_nodemanager.h"
-#include "ocfs2_heartbeat.h"
-#include "ocfs2_tcp.h"
-
-#define CLUSTER_FILE   "/proc/cluster/nm/.cluster"
-#define GROUP_FILE     "/proc/cluster/nm/.group"
-#define NODE_FILE      "/proc/cluster/nm/.node"
-#define HEARTBEAT_DISK_FILE "/proc/cluster/heartbeat/.disk"
-
-
-int create_remote_group(char *group_name, __u8 node);
-int get_node_map(__u8 group_num, char *bitmap);
-int get_raw_node_map(__u8 groupnum, char *groupdev, __u32 block_bits, __u32 num_blocks, __u64 start_block, char *bitmap);
-int get_ocfs2_disk_hb_params(char *group_dev, __u32 *block_bits, __u32 *cluster_bits,
-			     __u64 *start_block, __u32 *num_clusters);
-int activate_group(char *group_name, char *group_dev, __u8 group_num, 
-		   __u32 block_bits, __u64 num_blocks, __u64 start_block);
-int add_to_local_group(char *uuid, __u8 group_num, __u8 node_num);
-int create_group(char *uuid, __u8 *group_num);
-int get_my_nodenum(__u8 *nodenum);
-int add_me_to_group(char *groupname, char *groupdev);
-int ocfs2_detect_one(char *dev, char *uuid, int uuid_size);
-static int read_options(int argc, char **argv, char **device, char **mp);
-
-char *op_buf = NULL;
-
-/* returns fs_type: 0 for unknown, 1 for ocfs, 2 for ocfs2 */
-int ocfs2_detect_one(char *dev, char *uuid, int uuid_size)
+static int get_uuid(char *dev, char *uuid)
 {
 	ocfs2_filesys *fs = NULL;
-	int fs_type = 0;
-	int fs_size = sizeof(OCFS2_RAW_SB(fs->fs_super)->s_uuid);
-	errcode_t ret;
+	errcode_t ret = 0;
+	int i;
+	char *p;
+	uint8_t *s_uuid;
 
-	if (uuid_size != fs_size)
-		goto out;
-
 	ret = ocfs2_open(dev, OCFS2_FLAG_RO, 0, 0, &fs);
 	if (ret)
 		goto out;
 
-	memcpy(uuid, OCFS2_RAW_SB(fs->fs_super)->s_uuid,
-	       uuid_size);
-	fs_type = 2;
+	s_uuid = OCFS2_RAW_SB(fs->fs_super)->s_uuid;
 
+	for (i = 0, p = uuid; i < 16; i++, p += 2)
+		sprintf(p, "%02X", s_uuid[i]);
+	*p = '\0';
+
 	ocfs2_close(fs);
 
 out:
-	return fs_type;
+	return ret;
 }
 
-/*
- * read_options()
- *
- */
-//static int read_options(int argc, char **argv, char **hbuuid, char **hbdev, char **device, char **mp)
-static int read_options(int argc, char **argv, char **device, char **mp)
+static void read_options(int argc, char **argv, struct mount_options *mo)
 {
-	int ret = 0;
 	int c;
-	char *tmp;
 
-	if (argc < 2) {
-		ret = 1;
+	progname = basename(argv[0]);
+
+	if (argc < 2)
 		goto bail;
-	}
 
 	while(1) {
-		c = getopt(argc, argv, "o:");
+		c = getopt(argc, argv, "vno:");
 		if (c == -1)
 			break;
 
 		switch (c) {
-		case 'o':	/* options */
-			ret = 1;
-			tmp = optarg;
-			while (*tmp) {
-				/* TODO: Fill me in with all the -o
-				 * options we'll honor. */
+		case 'v':
+			++verbose;
+			break;
 
-				/* unknown option, ignore
-				 * these for now, but we need
-				 * to eventually handle
-				 * them. */
-				tmp = strchr(tmp, ',');
-				if (!tmp || !*tmp)
-					break;
-				tmp++;
-			}
-			ret = 0;
+		case 'n':
+			++nomtab;
 			break;
 
+		case 'o':
+			if (optarg)
+				mo->opts = xstrdup(optarg);
+			break;
+
 		default:
 			break;
 		}
 	}
 
-	if (!ret) {
-		ret = 1;
-		/* need device and mountpoint */
-		if (optind+1 < argc && argv[optind] && argv[optind+1]) {
-			*device = strdup(argv[optind]);
-			*mp = strdup(argv[optind+1]);
-			ret = 0;
-		}
-	}
+	if (optind < argc && argv[optind])
+		mo->dev = xstrdup(argv[optind]);
 
+	++optind;
+
+	if (optind < argc && argv[optind])
+		mo->dir = xstrdup(argv[optind]);
+
 bail:
-	return ret;
+	return ;
 }
 
-
 /*
- * main()
+ * Code based on similar function in util-linux-2.12a/mount/mount.c
  *
  */
-int main(int argc, char **argv)
+static void print_one (const struct mntent *me)
 {
-	char *device = NULL, *mountpoint = NULL;
-	char *hbuuid = NULL;
-	errcode_t ret = 0;
-	ocfs2_devices *dev;
-	char *p;
-	int i;
-	unsigned long flags = 0;
-	char *args = NULL;
+	if (mount_quiet)
+		return ;
 
-	op_buf = malloc(PAGE_SIZE);
-	if (!op_buf) {
-		ret = 1;
-		goto bail;
-	}
+	printf ("%s on %s", me->mnt_fsname, me->mnt_dir);
 
-	ret = read_options (argc, argv, &device, &mountpoint);
-	if (ret) {
-		com_err("mount.ocfs2", ret, "while reading options");
-		goto bail;
-	}
+	if (me->mnt_type != NULL && *(me->mnt_type) != '\0')
+		printf (" type %s", me->mnt_type);
 
-	if (!device) {
-		ret = OCFS2_ET_BAD_DEVICE_NAME;
-		com_err("mount.ocfs2", ret, "no device specified");
-		goto bail;
-	}
-	if (!mountpoint) {
-		ret = OCFS2_ET_INVALID_ARGUMENT;
-		com_err("mount.ocfs2", ret, "no mountpoint specified");
-		goto bail;
-	}
+	if (me->mnt_opts)
+		printf (" (%s)", me->mnt_opts);
 
-	dev = calloc(1, sizeof(*dev));
-	if (dev == NULL) {
-		ret = OCFS2_ET_NO_MEMORY;
-		com_err("mount.ocfs2", ret, "while allocating a dev");
-		goto bail;
-	}
-	snprintf(dev->dev_name, sizeof(dev->dev_name), "%s", device);
-
-	ret = ocfs2_detect_one(dev->dev_name, dev->uuid, sizeof(dev->uuid));
-	if (ret != 2) {
-		com_err("mount.ocfs2", ret, "while opening the file system");
-		goto bail;
-	}
-	dev->fs_type = ret;
-
-	hbuuid = malloc(33);
-	memset(hbuuid, 0, 33);
-	for (i = 0, p = hbuuid; i < 16; i++, p += 2)
-		sprintf(p, "%02X", dev->uuid[i]);
-
-	printf("device=%s hbuuid=%s\n", device, hbuuid);
-
-	ret = add_me_to_group(hbuuid, device);
-	if (ret < 0) {
-		printf("eeek! something bad happened in add_me_to_group: "
-		       "ret=%d\n", (int)ret);
-		goto bail;
-	}
-
-	args = malloc(strlen(hbuuid) + strlen("group=") + 1);
-	if (!args) {
-		ret = OCFS2_ET_NO_MEMORY;
-		com_err("mount.ocfs2", ret, "while allocating memory");
-		goto bail;
-	}
-	sprintf(args, "group=%s", hbuuid);
-	flags = 0;
-	ret = mount(device, mountpoint, "ocfs2", flags, args);
-
-bail:
-	if (args)
-		free(args);
-	if (device)
-		free(device);
-	if (mountpoint)
-		free(mountpoint);
-	if (hbuuid)
-		free(hbuuid);
-
-	if (op_buf)
-		free(op_buf);
-
-	return ret;
+	printf ("\n");
 }
 
-
-
 /*
- * this will try to add the group (and the node to the group)
- * for every mount.  luckily, there are many shortcut paths
- * along the way, so checking for -EEXIST will save time.
+ * Code based on similar function in util-linux-2.12a/mount/mount.c
+ *
  */
-int add_me_to_group(char *groupname, char *groupdev)
+static void update_mtab_entry(char *spec, char *node, char *type, char *opts,
+			      int flags, int freq, int pass)
 {
-	int ret;
-	__u8 my_nodenum, groupnum;
-	__u32 pre_nodemap[] = {0, 0, 0, 0, 0, 0, 0, 0};
-	__u32 post_nodemap[] = {0, 0, 0, 0, 0, 0, 0, 0};
-	int start, next, i;
-	__u32 block_bits, cluster_bits, num_clusters;
-	__u64 start_block, num_blocks;
+	struct mntent mnt;
+	mntFILE *mfp;
 
-	/* either create the group or find that it already exists */
-	ret = get_my_nodenum(&my_nodenum);
-	if (ret < 0)
-		return ret;
+	mnt.mnt_fsname = canonicalize (spec);
+	mnt.mnt_dir = canonicalize (node);
+	mnt.mnt_type = type;
+	mnt.mnt_opts = opts;
+	mnt.mnt_freq = freq;
+	mnt.mnt_passno = pass;
+      
+	/* We get chatty now rather than after the update to mtab since the
+	mount succeeded, even if the write to /etc/mtab should fail.  */
+	if (verbose)
+		print_one (&mnt);
 
-	ret = get_ocfs2_disk_hb_params(groupdev, &block_bits, &cluster_bits, 
-				       &start_block, &num_clusters);
-	if (ret < 0)
-		return ret;
+	if (nomtab || !mtab_is_writable())
+		goto bail;
 
-	num_blocks = num_clusters << cluster_bits;
-	num_blocks >>= block_bits;
-	
-	ret = create_group(groupname, &groupnum);
-	if (ret != -EEXIST && ret != 0)
-		return ret;
+//	if (flags & MS_REMOUNT) {
+//		update_mtab (mnt.mnt_dir, &mnt);
+//		goto bail;
+//	}
 
-	ret = activate_group(groupname, groupdev, groupnum, block_bits, num_blocks, start_block);
-	if (ret < 0)
-		return ret;
+	lock_mtab();
 
-	ret = add_to_local_group(groupname, groupnum, my_nodenum);
-	if (ret != -EEXIST && ret != 0)
-		return ret;
-
-	/* at this point my node is heartbeating, so any other nodes 
-	 * joining right now must communicate with me */
-
-	while (1) {
-		ret = get_node_map(groupnum, (char *)pre_nodemap);
-		if (ret < 0)
-			return ret;
-		if (ocfs2_test_bit(my_nodenum, (char *)pre_nodemap)) {
-			printf("found myself (%u) in nodemap! continuing...\n", my_nodenum);
-			break;
-		} else {
-			printf("have not yet found myself (%u) in nodemap...\n", my_nodenum);
-		}
-		/* TODO: set this to the default hb interval. 2 seconds right now */
-		sleep(2);
+	mfp = my_setmntent(MOUNTED, "a+");
+	if (mfp == NULL || mfp->mntent_fp == NULL) {
+		com_err(progname, OCFS2_ET_IO, "%s, %s", MOUNTED,
+			strerror(errno));
+		goto unlock;
 	}
 
-	/* now that we see ourself heartbeating, take a look
-	 * at ALL of the nodes that seem to be heartbeating 
-	 * on this device.  add them here and have them add
-	 * me there... */
-	ret = get_raw_node_map(groupnum, groupdev, block_bits, num_blocks, start_block, (char *)pre_nodemap);
-	if (ret < 0)
-		return ret;
-
-again:
-	/* go create this group and add this node on every other node I see */	
-	start = 0;
-	while (1) {
-		next = ocfs2_find_next_bit_set((unsigned long *)pre_nodemap, NM_MAX_NODES, start);
-		if (next >= NM_MAX_NODES) {
-			break;
-		}
-		if (next != my_nodenum) {
-			/* add remote node here... */
-			ret = add_to_local_group(groupname, groupnum, next);
-			if (ret != -EEXIST && ret != 0)
-				return ret;
-
-			/* ...and add this node there */
-			ret = create_remote_group(groupname, next);
-			if (ret != 0 && ret != -EEXIST) {
-				printf("create_remote_group: node=%u returned %d!\n",
-				       next, ret);
-				break;
-			}
-		}
-		start = next + 1;
+	if ((my_addmntent (mfp, &mnt)) == 1) {
+		com_err(progname, OCFS2_ET_IO, "%s, %s", MOUNTED,
+			strerror(errno));
 	}
-	if (ret != 0 && ret != -EEXIST)
-		return ret;
 
-	printf("done creating remote groups\n");
+	my_endmntent(mfp);
 
-	/* grab the nodemap again and look for changes */
-	ret = get_raw_node_map(groupnum, groupdev, block_bits, num_blocks, start_block, (char *)post_nodemap);
-	if (ret < 0)
-		return ret;
-	
-	printf("checking raw node map again.....\n");
-
-	if (memcmp(pre_nodemap, post_nodemap, sizeof(pre_nodemap)) == 0) {
-		/* nothing changed.  we are DONE! */
-		printf("woot. nothing changed. all done\n");
-		return 0;
-	}
-		
-	printf("something changed\n");
-		
-	/* something changed */
-	for (i=0; i<8; i++) {
-		post_nodemap[i] &= ~pre_nodemap[i];
-		pre_nodemap[i] = post_nodemap[i];
-		post_nodemap[i] = 0;
-	}
-
-	/* keep going while there are still nodes to contact */
-	if (ocfs2_find_next_bit_set((unsigned long *)pre_nodemap, NM_MAX_NODES, 0) < NM_MAX_NODES)
-		goto again;
-	
-	printf("ah nothing left to care about ... leaving\n");
-
-	return 0;
+unlock:
+	unlock_mtab();
+bail:
+	return ;
 }
 
-int get_my_nodenum(__u8 *nodenum)
+static int get_my_nodenum(uint8_t *nodenum)
 {
 	FILE *file;
 	int ret = -EINVAL;
@@ -423,7 +207,7 @@
 	return ret;
 }
 
-int create_group(char *uuid, __u8 *group_num)
+static int create_group(char *uuid, uint8_t *group_num)
 {
 	FILE *file;
 	int ret = -EINVAL, retval;
@@ -473,7 +257,7 @@
 }
 
 
-int add_to_local_group(char *uuid, __u8 group_num, __u8 node_num)
+static int add_to_local_group(char *uuid, uint8_t group_num, uint8_t node_num)
 {
 	FILE *file;
 	int ret = -EINVAL, retval;
@@ -522,15 +306,16 @@
 	return ret;
 }
 
-int activate_group(char *group_name, char *group_dev, __u8 group_num, 
-		   __u32 block_bits, __u64 num_blocks, __u64 start_block)
+static int activate_group(char *group_name, char *group_dev, uint8_t group_num, 
+		   uint32_t block_bits, uint64_t num_blocks, uint64_t start_block)
 {
 	int dev_fd = -1;
 	int ret = -EINVAL, retval;
 	FILE *file;
 	hb_op *op;
 
-	printf("starting disk heartbeat...\n");
+	if (verbose)
+		printf("starting disk heartbeat...\n");
 	
 	memset(op_buf, 0, PAGE_SIZE);
 	op = (hb_op *)op_buf;
@@ -568,9 +353,8 @@
 	return 0;
 }
 
-
-int get_ocfs2_disk_hb_params(char *group_dev, __u32 *block_bits, __u32 *cluster_bits,
-			     __u64 *start_block, __u32 *num_clusters)
+static int get_ocfs2_disk_hb_params(char *group_dev, uint32_t *block_bits, uint32_t *cluster_bits,
+			     uint64_t *start_block, uint32_t *num_clusters)
 {
 	int status = -EINVAL;
 	errcode_t ret = 0;
@@ -619,17 +403,18 @@
 	return status;
 }
 
-int get_node_map(__u8 group_num, char *bitmap)
+static int get_node_map(uint8_t group_num, char *bitmap)
 {
 	FILE *file = NULL;
 	hb_op *op;
 	int ret = -EINVAL;
 	int retval;
-	u8 bytemap[NM_MAX_NODES];
+	uint8_t bytemap[NM_MAX_NODES];
 	int i;
+
+	if (verbose)	
+		printf("getting node map...\n");
 	
-	printf("getting node map...\n");
-	
 	memset(op_buf, 0, PAGE_SIZE);
 	op = (hb_op *)op_buf;
 	op->magic = HB_OP_MAGIC;
@@ -667,19 +452,19 @@
 	return ret;
 }
 
-
-int get_raw_node_map(__u8 groupnum, char *groupdev, __u32 block_bits, __u32 num_blocks, __u64 start_block, char *bitmap)
+static int get_raw_node_map(uint8_t groupnum, char *groupdev,
+			    uint32_t block_bits, uint32_t num_blocks,
+			    uint64_t start_block, char *bitmap)
 {
 	int i;
 	int ret = -EINVAL;
 	char *buf = NULL, *tmpbuf;
 	hb_disk_heartbeat_block *times = NULL;
-
 	errcode_t err;
 	io_channel *channel;
 
-	
-	printf("getting raw node map...\n");
+	if (verbose)
+		printf("getting raw node map...\n");
 
 	times = malloc(sizeof(hb_disk_heartbeat_block) * NM_MAX_NODES);
 	if (!times) {
@@ -732,11 +517,12 @@
 
 	tmpbuf = buf;
 	for (i=0; i<NM_MAX_NODES; i++) {
-		printf("node: %d: before=%"PRIu64", after=%"PRIu64"\n", i,
-			times[i].time,
-			((hb_disk_heartbeat_block *)tmpbuf)->time);
+		if (verbose)
+			printf("node: %d: before=%"PRIu64", after=%"PRIu64"\n",
+			       i, times[i].time, ((hb_disk_heartbeat_block *)tmpbuf)->time);
 		if (times[i].time != ((hb_disk_heartbeat_block *)tmpbuf)->time) {
-			printf(" >>>>>  aha node %d seems to be up!\n", i);
+			if (verbose)
+				printf(" >>>>>  aha node %d seems to be up!\n", i);
 			ocfs2_set_bit(i, bitmap);
 		}
 		tmpbuf += (1 << block_bits);
@@ -753,7 +539,7 @@
 	return ret;
 }
 
-int create_remote_group(char *group_name, __u8 node)
+static int create_remote_group(char *group_name, uint8_t node)
 {
 	int ret, fd = -1, remote_node = -1;
 	gsd_ioc ioc;
@@ -761,7 +547,8 @@
 	DIR *dir = NULL;
 	struct dirent *de = NULL;
 
-	printf("create_remote_group: name=%s, remote node=%u\n", group_name, node);
+	if (verbose)
+		printf("create_remote_group: name=%s, remote node=%u\n", group_name, node);
 
 	/* NOTE: this is a bit of a hack.  we actually normally would not
 	 * know which "global" node corresponds to this "group relative" node.
@@ -786,7 +573,8 @@
 		ret = -EINVAL;
 		goto leave;
 	}
-	printf("found file %s corresponding to node %u\n", fname, node);
+	if (verbose)
+		printf("found file %s corresponding to node %u\n", fname, node);
 
 	/* open a file descriptor to the node we want to talk to */
 	remote_node = open(fname, O_RDONLY);
@@ -794,7 +582,8 @@
 		ret = -errno;
 		goto leave;
 	}
-	printf("fd for remote node=%d\n", remote_node);
+	if (verbose)
+		printf("fd for remote node=%d\n", remote_node);
 
 	/* TODO: move this over to a transaction file on the inode, eliminate the ioctl */
 	fd = open("/proc/cluster/net", O_RDONLY);
@@ -803,7 +592,8 @@
 		goto leave;
 	}
 
-	printf("fd for net ioctl file=%d\n", fd);
+	if (verbose)
+		printf("fd for net ioctl file=%d\n", fd);
 
 	/* call an ioctl to create the group over there */
 	memset(&ioc, 0, sizeof(gsd_ioc));
@@ -815,7 +605,8 @@
 		goto leave;
 	}
 	ret = ioc.status;
-	printf("create group ioctl returned ret=%d\n", ret);
+	if (verbose)
+		printf("create group ioctl returned ret=%d\n", ret);
 
 	if (ret != 0 && ret != -EEXIST)
 		goto leave;
@@ -830,7 +621,8 @@
 		goto leave;
 	}
 	ret = ioc.status;
-	printf("add node ioctl returned ret=%d\n", ret);
+	if (verbose)
+		printf("add node ioctl returned ret=%d\n", ret);
 
 leave:
 	if (fd != -1)
@@ -839,3 +631,216 @@
 		close(remote_node);
 	return ret;
 }
+
+/*
+ * this will try to add the group (and the node to the group)
+ * for every mount.  luckily, there are many shortcut paths
+ * along the way, so checking for -EEXIST will save time.
+ */
+static int add_me_to_group(char *groupname, char *groupdev)
+{
+	int ret;
+	uint8_t my_nodenum, groupnum;
+	uint32_t pre_nodemap[] = {0, 0, 0, 0, 0, 0, 0, 0};
+	uint32_t post_nodemap[] = {0, 0, 0, 0, 0, 0, 0, 0};
+	int start, next, i;
+	uint32_t block_bits, cluster_bits, num_clusters;
+	uint64_t start_block, num_blocks;
+
+	/* either create the group or find that it already exists */
+	ret = get_my_nodenum(&my_nodenum);
+	if (ret < 0)
+		return ret;
+
+	ret = get_ocfs2_disk_hb_params(groupdev, &block_bits, &cluster_bits, 
+				       &start_block, &num_clusters);
+	if (ret < 0)
+		return ret;
+
+	num_blocks = num_clusters << cluster_bits;
+	num_blocks >>= block_bits;
+	
+	ret = create_group(groupname, &groupnum);
+	if (ret != -EEXIST && ret != 0)
+		return ret;
+
+	ret = activate_group(groupname, groupdev, groupnum, block_bits, num_blocks, start_block);
+	if (ret < 0)
+		return ret;
+
+	ret = add_to_local_group(groupname, groupnum, my_nodenum);
+	if (ret != -EEXIST && ret != 0)
+		return ret;
+
+	/* at this point my node is heartbeating, so any other nodes 
+	 * joining right now must communicate with me */
+
+	while (1) {
+		ret = get_node_map(groupnum, (char *)pre_nodemap);
+		if (ret < 0)
+			return ret;
+		if (ocfs2_test_bit(my_nodenum, (char *)pre_nodemap)) {
+			if (verbose)
+				printf("found myself (%u) in nodemap! continuing...\n", my_nodenum);
+			break;
+		} else {
+			if (verbose)
+				printf("have not yet found myself (%u) in nodemap...\n", my_nodenum);
+		}
+		/* TODO: set this to the default hb interval. 2 seconds right now */
+		sleep(2);
+	}
+
+	/* now that we see ourself heartbeating, take a look
+	 * at ALL of the nodes that seem to be heartbeating 
+	 * on this device.  add them here and have them add
+	 * me there... */
+	ret = get_raw_node_map(groupnum, groupdev, block_bits, num_blocks, start_block, (char *)pre_nodemap);
+	if (ret < 0)
+		return ret;
+
+again:
+	/* go create this group and add this node on every other node I see */	
+	start = 0;
+	while (1) {
+		next = ocfs2_find_next_bit_set((unsigned long *)pre_nodemap, NM_MAX_NODES, start);
+		if (next >= NM_MAX_NODES) {
+			break;
+		}
+		if (next != my_nodenum) {
+			/* add remote node here... */
+			ret = add_to_local_group(groupname, groupnum, next);
+			if (ret != -EEXIST && ret != 0)
+				return ret;
+
+			/* ...and add this node there */
+			ret = create_remote_group(groupname, next);
+			if (ret != 0 && ret != -EEXIST) {
+				com_err(progname, ret, "unable to create remote group");
+				break;
+			}
+		}
+		start = next + 1;
+	}
+	if (ret != 0 && ret != -EEXIST)
+		return ret;
+
+	if (verbose)
+		printf("done creating remote groups\n");
+
+	/* grab the nodemap again and look for changes */
+	ret = get_raw_node_map(groupnum, groupdev, block_bits, num_blocks, start_block, (char *)post_nodemap);
+	if (ret < 0)
+		return ret;
+
+	if (verbose)	
+		printf("checking raw node map again.....\n");
+
+	if (memcmp(pre_nodemap, post_nodemap, sizeof(pre_nodemap)) == 0) {
+		/* nothing changed.  we are DONE! */
+		if (verbose)
+			printf("woot. nothing changed. all done\n");
+		return 0;
+	}
+	
+	if (verbose)	
+		printf("something changed\n");
+		
+	/* something changed */
+	for (i=0; i<8; i++) {
+		post_nodemap[i] &= ~pre_nodemap[i];
+		pre_nodemap[i] = post_nodemap[i];
+		post_nodemap[i] = 0;
+	}
+
+	/* keep going while there are still nodes to contact */
+	if (ocfs2_find_next_bit_set((unsigned long *)pre_nodemap, NM_MAX_NODES, 0) < NM_MAX_NODES)
+		goto again;
+
+	if (verbose)
+		printf("ah nothing left to care about ... leaving\n");
+
+	return 0;
+}
+
+static int process_options(struct mount_options *mo)
+{
+	if (!mo->dev) {
+		com_err(progname, OCFS2_ET_BAD_DEVICE_NAME, " ");
+		return -1;
+	}
+
+	if (!mo->dir) {
+		com_err(progname, OCFS2_ET_INVALID_ARGUMENT, "no mountpoint specified");
+		return -1;
+	}
+
+	if (mo->opts)
+		parse_opts(mo->opts, &mo->flags, &mo->xtra_opts);
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	errcode_t ret = 0;
+	struct mount_options mo = { NULL, NULL, NULL };
+	char hbuuid[33];
+
+	initialize_ocfs_error_table();
+	initialize_o2dl_error_table();
+
+	read_options (argc, argv, &mo);
+
+	ret = process_options(&mo);
+	if (ret)
+		goto bail;
+
+	ret = get_uuid(mo.dev, hbuuid);
+	if (ret) {
+		com_err(progname, ret, "while opening the file system");
+		goto bail;
+	}
+
+	if (verbose)
+		printf("device=%s hbuuid=%s\n", mo.dev, hbuuid);
+
+	ret = add_me_to_group(hbuuid, mo.dev);
+	if (ret < 0) {
+		fprintf(stderr, "%s: Error '%d' while adding to group\n", progname, ret);
+		goto bail;
+	}
+
+	mo.xtra_opts = realloc(mo.xtra_opts, (strlen(mo.xtra_opts) +
+					      strlen(hbuuid) +
+					      strlen("group=") + 1));
+	if (!mo.xtra_opts) {
+		com_err(progname, OCFS2_ET_NO_MEMORY, " ");
+		goto bail;
+	}
+
+	if (strlen(mo.xtra_opts))
+		strcat(mo.xtra_opts, ",");
+	strcat(mo.xtra_opts, "group=");
+	strcat(mo.xtra_opts, hbuuid);
+
+	ret = mount(mo.dev, mo.dir, "ocfs2", mo.flags, mo.xtra_opts);
+	if (ret) {
+		com_err(progname, errno, "while mounting %s on %s", mo.dev, mo.dir);
+		goto bail;
+	}
+
+	update_mtab_entry(mo.dev, mo.dir, "ocfs2", mo.xtra_opts, mo.flags, 0, 0);
+
+bail:
+	if (mo.dev)
+		free(mo.dev);
+	if (mo.dir)
+		free(mo.dir);
+	if (mo.opts)
+		free(mo.opts);
+	if (mo.xtra_opts)
+		free(mo.xtra_opts);
+
+	return ret;
+}

Added: trunk/mount.ocfs2/mount.ocfs2.h
===================================================================
--- trunk/mount.ocfs2/mount.ocfs2.h	2005-03-15 23:04:40 UTC (rev 641)
+++ trunk/mount.ocfs2/mount.ocfs2.h	2005-03-15 23:25:37 UTC (rev 642)
@@ -0,0 +1,65 @@
+/*
+ * mount.ocfs2.h  Definitions, etc.
+ *
+ * Copyright (C) 2004 Oracle.  All rights reserved.
+ *
+ * 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 of the License, 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 021110-1307, USA.
+ *
+ */
+
+#define _LARGEFILE64_SOURCE
+#define _GNU_SOURCE /* Because libc really doesn't want us using O_DIRECT? */
+
+#include <sys/types.h>
+#include <asm/types.h>
+#include <inttypes.h>
+
+#include <asm/page.h>
+#include <sys/mount.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/fd.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "fstab.h"
+#include "get_label_uuid.h"
+#include "linux_fs.h"
+#include "nls.h"
+#include "realpath.h"
+#include "sundries.h"
+#include "mntent.h"
+#include "mount_constants.h"
+#include "opts.h"
+
+#include <ocfs2.h>
+#include <ocfs2_fs.h>
+#include <ocfs1_fs_compat.h>
+#include <kernel-list.h>
+
+#include "bitops.h"
+
+#include "ocfs2_nodemanager.h"
+#include "ocfs2_heartbeat.h"
+#include "ocfs2_tcp.h"
+
+#define CLUSTER_FILE   "/proc/cluster/nm/.cluster"
+#define GROUP_FILE     "/proc/cluster/nm/.group"
+#define NODE_FILE      "/proc/cluster/nm/.node"
+#define HEARTBEAT_DISK_FILE "/proc/cluster/heartbeat/.disk"

Added: trunk/mount.ocfs2/mount_constants.h
===================================================================
--- trunk/mount.ocfs2/mount_constants.h	2005-03-15 23:04:40 UTC (rev 641)
+++ trunk/mount.ocfs2/mount_constants.h	2005-03-15 23:25:37 UTC (rev 642)
@@ -0,0 +1,68 @@
+#ifndef MS_RDONLY
+#define MS_RDONLY	 1	/* Mount read-only */
+#endif
+#ifndef MS_NOSUID
+#define MS_NOSUID	 2	/* Ignore suid and sgid bits */
+#endif
+#ifndef MS_NODEV
+#define MS_NODEV	 4	/* Disallow access to device special files */
+#endif
+#ifndef MS_NOEXEC
+#define MS_NOEXEC	 8	/* Disallow program execution */
+#endif
+#ifndef MS_SYNCHRONOUS
+#define MS_SYNCHRONOUS	16	/* Writes are synced at once */
+#endif
+#ifndef MS_REMOUNT
+#define MS_REMOUNT	32	/* Alter flags of a mounted FS */
+#endif
+#ifndef MS_MANDLOCK
+#define MS_MANDLOCK	64	/* Allow mandatory locks on an FS */
+#endif
+#ifndef MS_DIRSYNC
+#define MS_DIRSYNC	128	/* Directory modifications are synchronous */
+#endif
+
+#ifndef MS_ACTION_MASK
+#define	MS_ACTION_MASK	0x380
+/* Remount, but new filesystem may be different from old. Atomic
+   (i.e. there is no interval when nothing is mounted at the mountpoint).
+   If new fs differs from the old one and old is busy - -EBUSY. */
+#define	MS_REPLACE	0x080	/* 128 */
+/* After, Before: as soon as we get unions these will add a new member
+   in the end or beginning of the chain. Fail if there is a stack
+   on the mountpoint. */
+#define	MS_AFTER	0x100	/* 256 */
+#define	MS_BEFORE	0x180
+/* Over: if nothing mounted on a mountpoint - same as if none of these
+flags had been set; if we have a union with more than one element - fail;
+if we have a stack or plain mount - mount atop of it, forming a stack. */
+#define	MS_OVER		0x200	/* 512 */
+#endif
+#ifndef MS_NOATIME
+#define MS_NOATIME	0x400	/* 1024: Do not update access times. */
+#endif
+#ifndef MS_NODIRATIME
+#define MS_NODIRATIME   0x800	/* 2048: Don't update directory access times */
+#endif
+#ifndef MS_BIND
+#define	MS_BIND		0x1000	/* 4096: Mount existing tree also elsewhere */
+#endif
+#ifndef MS_MOVE
+#define MS_MOVE		0x2000	/* 8192: Atomically move tree */
+#endif
+#ifndef MS_REC
+#define MS_REC		0x4000	/* 16384: Recursive loopback */
+#endif
+#ifndef MS_VERBOSE
+#define MS_VERBOSE	0x8000	/* 32768 */
+#endif
+/*
+ * Magic mount flag number. Had to be or-ed to the flag values.
+ */
+#ifndef MS_MGC_VAL
+#define MS_MGC_VAL 0xC0ED0000	/* magic flag number to indicate "new" flags */
+#endif
+#ifndef MS_MGC_MSK
+#define MS_MGC_MSK 0xffff0000	/* magic flag number mask */
+#endif

Added: trunk/mount.ocfs2/nls.h
===================================================================
--- trunk/mount.ocfs2/nls.h	2005-03-15 23:04:40 UTC (rev 641)
+++ trunk/mount.ocfs2/nls.h	2005-03-15 23:25:37 UTC (rev 642)
@@ -0,0 +1,30 @@
+/*
+ * nls.h
+ *
+ * Code extracted from util-linux-2.12a/mount/nls.h
+ *
+ * Copyright (C) 2005 Oracle.  All rights reserved.
+ *
+ * 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 of the License, 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 021110-1307, USA.
+ *
+ */
+
+# undef bindtextdomain
+# define bindtextdomain(Domain, Directory) /* empty */
+# undef textdomain
+# define textdomain(Domain) /* empty */
+# define _(Text) (Text)
+# define N_(Text) (Text)

Added: trunk/mount.ocfs2/opts.c
===================================================================
--- trunk/mount.ocfs2/opts.c	2005-03-15 23:04:40 UTC (rev 641)
+++ trunk/mount.ocfs2/opts.c	2005-03-15 23:25:37 UTC (rev 642)
@@ -0,0 +1,235 @@
+/*
+ * opts.c  Parses options for mount.ocfs2.c
+ *
+ * Code has been extracted from util-linux-2.12a/mount/mount.c
+ *
+ * Copyright (C) 2005 Oracle.  All rights reserved.
+ *
+ * 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 of the License, 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 021110-1307, USA.
+ *
+ */
+
+#include "mount.ocfs2.h"
+
+#include <ctype.h>
+#include <grp.h>
+#include <pwd.h>
+
+/* Custom mount options for our own purposes.  */
+/* Maybe these should now be freed for kernel use again */
+#define MS_NOAUTO	0x80000000
+#define MS_USERS	0x40000000
+#define MS_USER		0x20000000
+#define MS_OWNER	0x10000000
+#define MS_PAMCONSOLE   0x08000000
+#define MS_NETDEV	0x00020000
+#define MS_LOOP		0x00010000
+
+/* Options that we keep the mount system call from seeing.  */
+#define MS_NOSYS	(MS_NOAUTO|MS_USERS|MS_USER|MS_NETDEV|MS_LOOP|MS_PAMCONSOLE)
+
+/* Options that we keep from appearing in the options field in the mtab.  */
+#define MS_NOMTAB	(MS_REMOUNT|MS_NOAUTO|MS_USERS|MS_USER|MS_PAMCONSOLE)
+
+/* Options that we make ordinary users have by default.  */
+#define MS_SECURE	(MS_NOEXEC|MS_NOSUID|MS_NODEV)
+
+/* Options that we make owner-mounted devices have by default */
+#define MS_OWNERSECURE	(MS_NOSUID|MS_NODEV)
+
+struct opt_map {
+  const char *opt;		/* option name */
+  int  skip;			/* skip in mtab option string */
+  int  inv;			/* true if flag value should be inverted */
+  int  mask;			/* flag mask value */
+};
+
+static const struct opt_map opt_map[] = {
+  { "defaults",	0, 0, 0		},	/* default options */
+  { "ro",	1, 0, MS_RDONLY	},	/* read-only */
+  { "rw",	1, 1, MS_RDONLY	},	/* read-write */
+  { "exec",	0, 1, MS_NOEXEC	},	/* permit execution of binaries */
+  { "noexec",	0, 0, MS_NOEXEC	},	/* don't execute binaries */
+  { "suid",	0, 1, MS_NOSUID	},	/* honor suid executables */
+  { "nosuid",	0, 0, MS_NOSUID	},	/* don't honor suid executables */
+  { "dev",	0, 1, MS_NODEV	},	/* interpret device files  */
+  { "nodev",	0, 0, MS_NODEV	},	/* don't interpret devices */
+  { "sync",	0, 0, MS_SYNCHRONOUS},	/* synchronous I/O */
+  { "async",	0, 1, MS_SYNCHRONOUS},	/* asynchronous I/O */
+  { "dirsync",	0, 0, MS_DIRSYNC},	/* synchronous directory modifications */
+  { "remount",  0, 0, MS_REMOUNT},      /* Alter flags of mounted FS */
+  { "bind",	0, 0, MS_BIND   },	/* Remount part of tree elsewhere */
+  { "auto",	0, 1, MS_NOAUTO	},	/* Can be mounted using -a */
+  { "noauto",	0, 0, MS_NOAUTO	},	/* Can  only be mounted explicitly */
+  { "users",	0, 0, MS_USERS	},	/* Allow ordinary user to mount */
+  { "nousers",	0, 1, MS_USERS	},	/* Forbid ordinary user to mount */
+  { "user",	0, 0, MS_USER	},	/* Allow ordinary user to mount */
+  { "nouser",	0, 1, MS_USER	},	/* Forbid ordinary user to mount */
+  { "owner",	0, 0, MS_OWNER  },	/* Let the owner of the device mount */
+  { "noowner",	0, 1, MS_OWNER  },	/* Device owner has no special privs */
+  { "_netdev",	0, 0, MS_NETDEV },	/* Device accessible only via network */
+  { "pamconsole",   0, 0, MS_PAMCONSOLE }, /* Allow users at console to mount */
+  { "nopamconsole", 0, 1, MS_PAMCONSOLE }, /* Console user has no special privs */
+#ifdef MS_NOSUB
+  { "sub",	0, 1, MS_NOSUB	},	/* allow submounts */
+  { "nosub",	0, 0, MS_NOSUB	},	/* don't allow submounts */
+#endif
+#ifdef MS_SILENT
+  { "quiet",	0, 0, MS_SILENT    },	/* be quiet  */
+  { "loud",	0, 1, MS_SILENT    },	/* print out messages. */
+#endif
+#ifdef MS_MANDLOCK
+  { "mand",	0, 0, MS_MANDLOCK },	/* Allow mandatory locks on this FS */
+  { "nomand",	0, 1, MS_MANDLOCK },	/* Forbid mandatory locks on this FS */
+#endif
+  { "loop",	1, 0, MS_LOOP	},	/* use a loop device */
+#ifdef MS_NOATIME
+  { "atime",	0, 1, MS_NOATIME },	/* Update access time */
+  { "noatime",	0, 0, MS_NOATIME },	/* Do not update access time */
+#endif
+#ifdef MS_NODIRATIME
+  { "diratime",	0, 1, MS_NODIRATIME },	/* Update dir access times */
+  { "nodiratime", 0, 0, MS_NODIRATIME },/* Do not update dir access times */
+#endif
+  { "kudzu",	0, 0, 0 },		/* Silently remove this option (backwards compat use only) */
+  { "managed",	0, 0, 0 },		/* Silently remove this option */
+  { NULL,	0, 0, 0	}
+};
+
+
+static char *opt_loopdev, *opt_vfstype, *opt_offset, *opt_encryption,
+  *opt_speed;
+
+static struct string_opt_map {
+  char *tag;
+  int skip;
+  char **valptr;
+} string_opt_map[] = {
+  { "loop=",	0, &opt_loopdev },
+  { "vfs=",	1, &opt_vfstype },
+  { "offset=",	0, &opt_offset },
+  { "encryption=", 0, &opt_encryption },
+  { "speed=", 0, &opt_speed },
+  { NULL, 0, NULL }
+};
+
+static void clear_string_opts(void)
+{
+	struct string_opt_map *m;
+
+	for (m = &string_opt_map[0]; m->tag; m++)
+		*(m->valptr) = NULL;
+}
+
+static int parse_string_opt(char *s)
+{
+	struct string_opt_map *m;
+	int lth;
+
+	for (m = &string_opt_map[0]; m->tag; m++) {
+		lth = strlen(m->tag);
+		if (!strncmp(s, m->tag, lth)) {
+			*(m->valptr) = xstrdup(s + lth);
+			return 1;
+		}
+	}
+	return 0;
+}
+/*
+ * Look for OPT in opt_map table and return mask value.
+ * If OPT isn't found, tack it onto extra_opts (which is non-NULL).
+ * For the options uid= and gid= replace user or group name by its value.
+ */
+static inline void parse_opt (const char *opt, int *mask, char *extra_opts)
+{
+	const struct opt_map *om;
+
+	for (om = opt_map; om->opt != NULL; om++)
+		if (streq (opt, om->opt)) {
+			if (om->inv)
+				*mask &= ~om->mask;
+			else
+				*mask |= om->mask;
+			if ((om->mask == MS_USER || om->mask == MS_USERS || om->mask == MS_PAMCONSOLE)
+			    && !om->inv)
+				*mask |= MS_SECURE;
+			if ((om->mask == MS_OWNER) && !om->inv)
+				*mask |= MS_OWNERSECURE;
+
+#ifdef MS_SILENT
+			if (om->mask == MS_SILENT && om->inv)  {
+				mount_quiet = 1;
+				verbose = 0;
+			}
+#endif
+			return;
+		}
+
+	if (*extra_opts)
+		strcat(extra_opts, ",");
+
+	/* convert nonnumeric ids to numeric */
+	if (!strncmp(opt, "uid=", 4) && !isdigit(opt[4])) {
+		struct passwd *pw = getpwnam(opt+4);
+		char uidbuf[20];
+
+		if (pw) {
+			sprintf(uidbuf, "uid=%d", pw->pw_uid);
+			strcat(extra_opts, uidbuf);
+			return;
+		}
+	}
+	if (!strncmp(opt, "gid=", 4) && !isdigit(opt[4])) {
+		struct group *gr = getgrnam(opt+4);
+		char gidbuf[20];
+
+		if (gr) {
+			sprintf(gidbuf, "gid=%d", gr->gr_gid);
+			strcat(extra_opts, gidbuf);
+			return;
+		}
+	}
+
+	strcat(extra_opts, opt);
+}
+  
+/* Take -o options list and compute 4th and 5th args to mount(2).  flags
+   gets the standard options (indicated by bits) and extra_opts all the rest */
+void parse_opts (char *opts, int *flags, char **extra_opts)
+{
+	char *opt;
+
+	*flags = 0;
+	*extra_opts = NULL;
+
+	clear_string_opts();
+
+	if (opts != NULL) {
+		*extra_opts = xmalloc (strlen (opts) + 1); 
+		**extra_opts = '\0';
+
+		for (opt = strtok (opts, ","); opt; opt = strtok (NULL, ","))
+			if (!parse_string_opt (opt))
+				parse_opt (opt, flags, *extra_opts);
+	}
+#if 0
+	if (readonly)
+		*flags |= MS_RDONLY;
+	if (readwrite)
+		*flags &= ~MS_RDONLY;
+	*flags |= mounttype;
+#endif
+}

Added: trunk/mount.ocfs2/opts.h
===================================================================
--- trunk/mount.ocfs2/opts.h	2005-03-15 23:04:40 UTC (rev 641)
+++ trunk/mount.ocfs2/opts.h	2005-03-15 23:25:37 UTC (rev 642)
@@ -0,0 +1,23 @@
+/*
+ * opts.h  Definitions, function prototypes, etc.
+ *
+ * Copyright (C) 2005 Oracle.  All rights reserved.
+ *
+ * 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 of the License, 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 021110-1307, USA.
+ *
+ */
+
+void parse_opts (char *opts, int *flags, char **extra_opts);

Added: trunk/mount.ocfs2/realpath.c
===================================================================
--- trunk/mount.ocfs2/realpath.c	2005-03-15 23:04:40 UTC (rev 641)
+++ trunk/mount.ocfs2/realpath.c	2005-03-15 23:25:37 UTC (rev 642)
@@ -0,0 +1,132 @@
+/*
+ * realpath.c -- canonicalize pathname by removing symlinks
+ * Copyright (C) 1993 Rick Sladkey <jrs at world.std.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library 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 Library Public License for more details.
+ */
+
+#define resolve_symlinks
+
+/*
+ * This routine is part of libc.  We include it nevertheless,
+ * since the libc version has some security flaws.
+ */
+
+#include <limits.h>		/* for PATH_MAX */
+#ifndef PATH_MAX
+#define PATH_MAX 8192
+#endif
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include "realpath.h"
+#include "sundries.h"		/* for xstrdup */
+
+#define MAX_READLINKS 32
+
+/* this leaks some memory - unimportant for mount */
+char *
+myrealpath(const char *path, char *resolved_path, int maxreslth) {
+	int readlinks = 0;
+	char *npath;
+	char link_path[PATH_MAX+1];
+	int n;
+#ifdef resolve_symlinks
+	char *buf;
+	int m;
+#endif
+
+	npath = resolved_path;
+
+	/* If it's a relative pathname use getcwd for starters. */
+	if (*path != '/') {
+		if (!getcwd(npath, maxreslth-2))
+			return NULL;
+		npath += strlen(npath);
+		if (npath[-1] != '/')
+			*npath++ = '/';
+	} else {
+		*npath++ = '/';
+		path++;
+	}
+
+	/* Expand each slash-separated pathname component. */
+	while (*path != '\0') {
+		/* Ignore stray "/" */
+		if (*path == '/') {
+			path++;
+			continue;
+		}
+		if (*path == '.' && (path[1] == '\0' || path[1] == '/')) {
+			/* Ignore "." */
+			path++;
+			continue;
+		}
+		if (*path == '.' && path[1] == '.' &&
+		    (path[2] == '\0' || path[2] == '/')) {
+			/* Backup for ".." */
+			path += 2;
+			while (npath > resolved_path+1 &&
+			       (--npath)[-1] != '/')
+				;
+			continue;
+		}
+		/* Safely copy the next pathname component. */
+		while (*path != '\0' && *path != '/') {
+			if (npath-resolved_path > maxreslth-2) {
+				errno = ENAMETOOLONG;
+				return NULL;
+			}
+			*npath++ = *path++;
+		}
+
+		/* Protect against infinite loops. */
+		if (readlinks++ > MAX_READLINKS) {
+			errno = ELOOP;
+			return NULL;
+		}
+
+		/* See if last pathname component is a symlink. */
+		*npath = '\0';
+		n = readlink(resolved_path, link_path, PATH_MAX);
+		if (n < 0) {
+			/* EINVAL means the file exists but isn't a symlink. */
+			if (errno != EINVAL)
+				return NULL;
+		} else {
+#ifdef resolve_symlinks		/* Richard Gooch dislikes sl resolution */
+			/* Note: readlink doesn't add the null byte. */
+			link_path[n] = '\0';
+			if (*link_path == '/')
+				/* Start over for an absolute symlink. */
+				npath = resolved_path;
+			else
+				/* Otherwise back up over this component. */
+				while (*(--npath) != '/')
+					;
+
+			/* Insert symlink contents into path. */
+			m = strlen(path);
+			buf = xmalloc(m + n + 1);
+			memcpy(buf, link_path, n);
+			memcpy(buf + n, path, m + 1);
+			path = buf;
+#endif
+		}
+		*npath++ = '/';
+	}
+	/* Delete trailing slash but don't whomp a lone slash. */
+	if (npath != resolved_path+1 && npath[-1] == '/')
+		npath--;
+	/* Make sure it's null terminated. */
+	*npath = '\0';
+	return resolved_path;
+}

Added: trunk/mount.ocfs2/realpath.h
===================================================================
--- trunk/mount.ocfs2/realpath.h	2005-03-15 23:04:40 UTC (rev 641)
+++ trunk/mount.ocfs2/realpath.h	2005-03-15 23:25:37 UTC (rev 642)
@@ -0,0 +1 @@
+extern char *myrealpath(const char *path, char *resolved_path, int m);

Added: trunk/mount.ocfs2/sundries.c
===================================================================
--- trunk/mount.ocfs2/sundries.c	2005-03-15 23:04:40 UTC (rev 641)
+++ trunk/mount.ocfs2/sundries.c	2005-03-15 23:25:37 UTC (rev 642)
@@ -0,0 +1,287 @@
+/*
+ * Support functions.  Exported functions are prototyped in sundries.h.
+ * sundries.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
+ *
+ * added fcntl locking by Kjetil T. (kjetilho at math.uio.no) - aeb, 950927
+ *
+ * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek at pld.ORG.PL>
+ * - added Native Language Support
+ *
+ */
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <mntent.h>		/* for MNTTYPE_SWAP */
+#include "fstab.h"
+#include "sundries.h"
+#include "realpath.h"
+//#include "nfsmount.h"
+#include "nls.h"
+
+void *
+xmalloc (size_t size) {
+     void *t;
+
+     if (size == 0)
+          return NULL;
+
+     t = malloc (size);
+     if (t == NULL)
+          die (EX_SYSERR, _("not enough memory"));
+
+     return t;
+}
+
+char *
+xstrdup (const char *s) {
+     char *t;
+
+     if (s == NULL)
+          return NULL;
+
+     t = strdup (s);
+
+     if (t == NULL)
+          die (EX_SYSERR, _("not enough memory"));
+
+     return t;
+}
+
+char *
+xstrndup (const char *s, int n) {
+     char *t;
+
+     if (s == NULL)
+	  die (EX_SOFTWARE, _("bug in xstrndup call"));
+
+     t = xmalloc(n+1);
+     strncpy(t,s,n);
+     t[n] = 0;
+
+     return t;
+}
+
+char *
+xstrconcat2 (const char *s, const char *t) {
+     char *res;
+
+     if (!s) s = "";
+     if (!t) t = "";
+     res = xmalloc(strlen(s) + strlen(t) + 1);
+     strcpy(res, s);
+     strcat(res, t);
+     return res;
+}
+
+char *
+xstrconcat3 (const char *s, const char *t, const char *u) {
+     char *res;
+
+     if (!s) s = "";
+     if (!t) t = "";
+     if (!u) u = "";
+     res = xmalloc(strlen(s) + strlen(t) + strlen(u) + 1);
+     strcpy(res, s);
+     strcat(res, t);
+     strcat(res, u);
+     return res;
+}
+
+char *
+xstrconcat4 (const char *s, const char *t, const char *u, const char *v) {
+     char *res;
+
+     if (!s) s = "";
+     if (!t) t = "";
+     if (!u) u = "";
+     if (!v) v = "";
+     res = xmalloc(strlen(s) + strlen(t) + strlen(u) + strlen(v) + 1);
+     strcpy(res, s);
+     strcat(res, t);
+     strcat(res, u);
+     strcat(res, v);
+     return res;
+}
+
+/* Call this with SIG_BLOCK to block and SIG_UNBLOCK to unblock.  */
+void
+block_signals (int how) {
+     sigset_t sigs;
+
+     sigfillset (&sigs);
+     sigdelset(&sigs, SIGTRAP);
+     sigdelset(&sigs, SIGSEGV);
+     sigprocmask (how, &sigs, (sigset_t *) 0);
+}
+
+
+/* Non-fatal error.  Print message and return.  */
+/* (print the message in a single printf, in an attempt
+    to avoid mixing output of several threads) */
+void
+error (const char *fmt, ...) {
+     va_list args;
+     char *fmt2;
+
+     if (mount_quiet)
+	  return;
+     fmt2 = xstrconcat2 (fmt, "\n");
+     va_start (args, fmt);
+     vfprintf (stderr, fmt2, args);
+     va_end (args);
+     free (fmt2);
+}
+
+/* Fatal error.  Print message and exit.  */
+void
+die (int err, const char *fmt, ...) {
+     va_list args;
+
+     va_start (args, fmt);
+     vfprintf (stderr, fmt, args);
+     fprintf (stderr, "\n");
+     va_end (args);
+
+     unlock_mtab ();
+     exit (err);
+}
+
+/* True if fstypes match.  Null *TYPES means match anything,
+   except that swap types always return false. */
+/* Accept nonfs,proc,devpts and nonfs,noproc,nodevpts
+   with the same meaning. */
+int
+matching_type (const char *type, const char *types) {
+     int no;			/* negated types list */
+     int len;
+     const char *p;
+
+     if (streq (type, MNTTYPE_SWAP))
+	  return 0;
+     if (types == NULL)
+	  return 1;
+
+     no = 0;
+     if (!strncmp(types, "no", 2)) {
+	  no = 1;
+	  types += 2;
+     }
+
+     /* Does type occur in types, separated by commas? */
+     len = strlen(type);
+     p = types;
+     while(1) {
+	     if (!strncmp(p, "no", 2) && !strncmp(p+2, type, len) &&
+		 (p[len+2] == 0 || p[len+2] == ','))
+		     return 0;
+	     if (strncmp(p, type, len) == 0 &&
+		 (p[len] == 0 || p[len] == ','))
+		     return !no;
+	     p = index(p,',');
+	     if (!p)
+		     break;
+	     p++;
+     }
+     return no;
+}
+
+/* Returns 1 if needle found or noneedle not found in haystack
+ * Otherwise returns 0
+ */
+static int
+check_option(const char *haystack, const char *needle) {
+     const char *p, *r;
+     int len, needle_len, this_len;
+     int no;
+
+     no = 0;
+     if (!strncmp(needle, "no", 2)) {
+	  no = 1;
+	  needle += 2;
+     }
+     needle_len = strlen(needle);
+     len = strlen(haystack);
+
+     for (p = haystack; p < haystack+len; p++) {
+	  r = strchr(p, ',');
+	  if (r) {
+	       this_len = r-p;
+	  } else {
+	       this_len = strlen(p);
+	  }
+	  if (this_len != needle_len) {
+	       p += this_len;
+	       continue;
+	  }
+	  if (strncmp(p, needle, this_len) == 0)
+	       return !no; /* foo or nofoo was found */
+	  p += this_len;
+     }
+
+     return no;  /* foo or nofoo was not found */
+}
+
+
+/* Returns 1 if each of the test_opts options agrees with the entire
+ * list of options.
+ * Returns 0 if any noopt is found in test_opts and opt is found in options.
+ * Returns 0 if any opt is found in test_opts but is not found in options.
+ * Unlike fs type matching, nonetdev,user and nonetdev,nouser have
+ * DIFFERENT meanings; each option is matched explicitly as specified.
+ */
+int
+matching_opts (const char *options, const char *test_opts) {
+     const char *p, *r;
+     char *q;
+     int len, this_len;
+
+     if (test_opts == NULL)
+	  return 1;
+
+     len = strlen(test_opts);
+     q = alloca(len+1);
+     if (q == NULL)
+          die (EX_SYSERR, _("not enough memory"));
+     
+     for (p = test_opts; p < test_opts+len; p++) {
+	  r = strchr(p, ',');
+	  if (r) {
+	       this_len = r-p;
+	  } else {
+	       this_len = strlen(p);
+	  }
+	  if (!this_len) continue; /* if two ',' appear in a row */
+	  strncpy(q, p, this_len);
+	  q[this_len] = '\0';
+	  if (!check_option(options, q))
+	       return 0; /* any match failure means failure */
+	  p += this_len;
+     }
+
+     /* no match failures in list means success */
+     return 1;
+}
+
+/* Make a canonical pathname from PATH.  Returns a freshly malloced string.
+   It is up the *caller* to ensure that the PATH is sensible.  i.e.
+   canonicalize ("/dev/fd0/.") returns "/dev/fd0" even though ``/dev/fd0/.''
+   is not a legal pathname for ``/dev/fd0''.  Anything we cannot parse
+   we return unmodified.   */
+char *
+canonicalize (const char *path) {
+     char *canonical;
+
+     if (path == NULL)
+	  return NULL;
+
+     if (streq(path, "none") || streq(path, "proc") || streq(path, "devpts"))
+	  return xstrdup(path);
+
+     canonical = xmalloc (PATH_MAX+2);
+  
+     if (myrealpath (path, canonical, PATH_MAX+1))
+	  return canonical;
+
+     free(canonical);
+     return xstrdup(path);
+}

Added: trunk/mount.ocfs2/sundries.h
===================================================================
--- trunk/mount.ocfs2/sundries.h	2005-03-15 23:04:40 UTC (rev 641)
+++ trunk/mount.ocfs2/sundries.h	2005-03-15 23:25:37 UTC (rev 642)
@@ -0,0 +1,54 @@
+/*
+ * sundries.h
+ * Support function prototypes.  Functions are in sundries.c.
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#if !defined(bool_t) && !defined(__GLIBC__)
+#include <rpc/types.h>
+#endif
+
+extern int mount_quiet;
+extern int verbose;
+extern int sloppy;
+
+#define streq(s, t)	(strcmp ((s), (t)) == 0)
+
+/* Functions in sundries.c that are used in mount.c and umount.c  */ 
+void block_signals (int how);
+char *canonicalize (const char *path);
+void error (const char *fmt, ...);
+int matching_type (const char *type, const char *types);
+int matching_opts (const char *options, const char *test_opts);
+void *xmalloc (size_t size);
+char *xstrdup (const char *s);
+char *xstrndup (const char *s, int n);
+char *xstrconcat2 (const char *, const char *);
+char *xstrconcat3 (const char *, const char *, const char *);
+char *xstrconcat4 (const char *, const char *, const char *, const char *);
+
+void die (int errcode, const char *fmt, ...);
+
+#ifdef HAVE_NFS
+int nfsmount (const char *spec, const char *node, int *flags,
+	      char **orig_opts, char **opt_args, int *version, int running_bg);
+int nfs4mount (const char *spec, const char *node, int *flags,
+		char **orig_opts, char **opt_args, int running_bg);
+int nfsumount(const char *spec, const char *opts);
+#endif
+
+/* exit status - bits below are ORed */
+#define EX_USAGE	1	/* incorrect invocation or permission */
+#define EX_SYSERR	2	/* out of memory, cannot fork, ... */
+#define EX_SOFTWARE	4	/* internal mount bug or wrong version */
+#define EX_USER		8	/* user interrupt */
+#define EX_FILEIO      16	/* problems writing, locking, ... mtab/fstab */
+#define EX_FAIL	       32	/* mount failure */
+#define EX_SOMEOK      64	/* some mount succeeded */
+
+#define EX_BG         256       /* retry in background (internal only) */



More information about the Ocfs2-tools-commits mailing list