From ea557a340a869ce2abda5fbd652f1419d278c12e Mon Sep 17 00:00:00 2001
From: Roland McGrath <roland@gnu.org>
Date: Sun, 24 Mar 2002 02:51:22 +0000
Subject: 2002-03-23  Roland McGrath  <roland@frob.com>

	* tmpfs.c (options): New static const variable.  Add --mode/-m.
	(struct option_values): New type.
	(parse_opt): Use that for VALUES.  Grok -m to set VALUES->mode.
	Grok ARGP_KEY_FINI and free our data structure.
	(tmpfs_root_mode): New variable, set by -m.
	(main): If -m was given, use that instead of underlying node's
	permissions.
---
 tmpfs/tmpfs.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 54 insertions(+), 12 deletions(-)

(limited to 'tmpfs/tmpfs.c')

diff --git a/tmpfs/tmpfs.c b/tmpfs/tmpfs.c
index b7268282..b691f718 100644
--- a/tmpfs/tmpfs.c
+++ b/tmpfs/tmpfs.c
@@ -50,6 +50,7 @@ struct node *diskfs_root_node;
 mach_port_t default_pager;
 
 off_t tmpfs_page_limit, tmpfs_space_used;
+mode_t tmpfs_root_mode = -1;
 
 error_t
 diskfs_set_statfs (struct statfs *st)
@@ -95,6 +96,17 @@ diskfs_reload_global_state ()
 
 int diskfs_synchronous = 0;
 
+static const struct argp_option options[] =
+{
+  {"mode", 'm', "MODE", 0, "Permissions (octal) for root directory"},
+  {NULL,}
+};
+
+struct option_values
+{
+  off_t size;
+  mode_t mode;
+};
 
 /* Parse a command line option.  */
 static error_t
@@ -102,10 +114,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
 {
   /* We save our parsed values in this structure, hung off STATE->hook.
      Only after parsing all options successfully will we use these values.  */
-  struct
-  {
-    off_t size;
-  } *values = state->hook;
+  struct option_values *values = state->hook;
 
   switch (key)
     {
@@ -115,7 +124,30 @@ parse_opt (int key, char *arg, struct argp_state *state)
       if (values == 0)
 	return ENOMEM;
       state->hook = values;
-      bzero (values, sizeof *values);
+      values->size = 0;
+      values->mode = -1;
+      break;
+    case ARGP_KEY_FINI:
+      free (values);
+      state->hook = 0;
+      break;
+
+    case 'm':			/* --mode=OCTAL */
+      {
+	char *end = NULL;
+	mode_t mode = strtoul (state->argv[state->next], &end, 8);
+	if (end == NULL || end == arg)
+	  {
+	    argp_error (state, "argument must be an octal number");
+	    return EINVAL;
+	  }
+	if (mode & S_IFMT)
+	  {
+	    argp_error (state, "invalid bits in mode");
+	    return EINVAL;
+	  }
+	values->mode = mode;
+      }
       break;
 
     case ARGP_KEY_NO_ARGS:
@@ -168,6 +200,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
     case ARGP_KEY_SUCCESS:
       /* All options parse successfully, so implement ours if possible.  */
       tmpfs_page_limit = values->size / vm_page_size;
+      tmpfs_root_mode = values->mode;
       break;
 
     default:
@@ -261,6 +294,7 @@ main (int argc, char **argv)
      set properly, it is safe to export our fsys control port to the
      outside world.  */
   realnode = diskfs_startup_diskfs (bootstrap, 0);
+  diskfs_root_node->dn_stat.st_mode = S_IFDIR;
 
   /* Propagate permissions, owner, etc. from underlying node to
      the root directory of the new (empty) filesystem.  */
@@ -268,19 +302,27 @@ main (int argc, char **argv)
   if (err)
     {
       error (0, err, "cannot stat underlying node");
-      diskfs_root_node->dn_stat.st_mode = S_IFDIR | 0777 | S_ISVTX;
+      if (tmpfs_root_mode == -1)
+	diskfs_root_node->dn_stat.st_mode |= 0777 | S_ISVTX;
+      else
+	diskfs_root_node->dn_stat.st_mode |= tmpfs_root_mode;
       diskfs_root_node->dn_set_ctime = 1;
       diskfs_root_node->dn_set_mtime = 1;
       diskfs_root_node->dn_set_atime = 1;
     }
   else
     {
-      diskfs_root_node->dn_stat.st_mode = S_IFDIR | (st.st_mode &~ S_IFMT);
-      if (S_ISREG(st.st_mode) && (st.st_mode & 0111) == 0)
-	/* There are no execute bits set, as by default on a plain file.
-	   For the virtual directory, set execute bits where read bits are
-	   set on the underlying plain file.  */
-	diskfs_root_node->dn_stat.st_mode |= (st.st_mode & 0444) >> 2;
+      if (tmpfs_root_mode == -1)
+	{
+	  diskfs_root_node->dn_stat.st_mode |= st.st_mode &~ S_IFMT;
+	  if (S_ISREG (st.st_mode) && (st.st_mode & 0111) == 0)
+	    /* There are no execute bits set, as by default on a plain file.
+	       For the virtual directory, set execute bits where read bits are
+	       set on the underlying plain file.  */
+	    diskfs_root_node->dn_stat.st_mode |= (st.st_mode & 0444) >> 2;
+	}
+      else
+	diskfs_root_node->dn_stat.st_mode |= tmpfs_root_mode;
       diskfs_root_node->dn_stat.st_uid = st.st_uid;
       diskfs_root_node->dn_stat.st_author = st.st_author;
       diskfs_root_node->dn_stat.st_gid = st.st_gid;
-- 
cgit v1.2.3