Пример #1
0
/* Start the translator TRANS (of length TRANS_LEN) on NODE, which should be
   locked, and will be unlocked when this function returns.  PARENT_PORT is
   a send right to use as the parent port passed to the translator.  */
error_t
_treefs_node_start_translator (struct treefs_node *node,
			       char *trans, unsigned trans_len,
			       file_t parent_port)
{
  error_t err;
  int mode = O_READ | O_EXEC;
  struct treefs_auth *auth;
  file_t node_port;
  uid_t uid, gid;

  err = treefs_node_get_trans_auth (node, &auth);
  if (err)
    return err;

  if (!node->fsys->readonly && treefs_node_type (node) == S_IFREG)
    mode |= O_WRITE;

  /* Create the REALNODE port for the new filesystem. */
  node_port = treefs_node_make_right (node, mode, parent_port, auth);
  mach_port_insert_right (mach_task_self (), node_port, node_port,
			  MACH_MSG_TYPE_MAKE_SEND);


  mutex_unlock (&node->lock);
  
  /* XXXX Change libfshelp so that it take more than 1 uid/gid? */
  uid = auth->nuids > 0 ? auth->uids[0] : -1;
  gid = auth->ngids > 0 ? auth->gids[0] : -1;

  /* XXX this should use fshelp_start_translator_long. */
  err =
    fshelp_start_translator (&node->active_trans, NULL, trans, trans_len,
			     parent_port, node_port, uid, gid);

  treefs_node_auth_unref (node, auth);

  return err;
}
Пример #2
0
int
main(int argc, char *argv[])
{
  error_t err;

  /* The filesystem node we're putting a translator on.  */
  char *node_name = 0;
  file_t node;

  /* The translator's arg vector, in '\0' separated format.  */
  char *argz = 0;
  size_t argz_len = 0;

  /* The control port for any active translator we start up.  */
  fsys_t active_control = MACH_PORT_NULL;

  /* Flags to pass to file_set_translator.  */
  int active_flags = 0;
  int passive_flags = 0;
  int lookup_flags = O_NOTRANS;
  int goaway_flags = 0;

  /* Various option flags.  */
  int passive = 0, active = 0, keep_active = 0, pause = 0, kill_active = 0,
      orphan = 0;
  int start = 0;
  int stack = 0;
  char *pid_file = NULL;
  int excl = 0;
  int timeout = DEFAULT_TIMEOUT * 1000; /* ms */
  char *underlying_node_name = NULL;
  int underlying_lookup_flags;
  char **chroot_command = 0;
  char *chroot_chdir = "/";

  /* Parse our options...  */
  error_t parse_opt (int key, char *arg, struct argp_state *state)
    {
      switch (key)
	{
	case ARGP_KEY_ARG:
	  if (state->arg_num == 0)
	    node_name = arg;
	  else			/* command */
	    {
	      if (start)
		argp_error (state, "both --start and TRANSLATOR given");

	      error_t err =
		argz_create (state->argv + state->next - 1, &argz, &argz_len);
	      if (err)
		error(3, err, "Can't create options vector");
	      state->next = state->argc; /* stop parsing */
	    }
	  break;

	case ARGP_KEY_NO_ARGS:
	  argp_usage (state);
	  return EINVAL;

	case 'a': active = 1; break;
	case 's':
	  start = 1;
	  active = 1;	/* start implies active */
	  break;
	case OPT_STACK:
	  stack = 1;
	  active = 1;	/* stack implies active */
	  orphan = 1;	/* stack implies orphan */
	  break;
	case 'p': passive = 1; break;
	case 'k': keep_active = 1; break;
	case 'g': kill_active = 1; break;
	case 'x': excl = 1; break;
	case 'P': pause = 1; break;
	case 'F':
	  pid_file = strdup (arg);
	  if (pid_file == NULL)
	    error(3, ENOMEM, "Failed to duplicate argument");
	  break;

	case 'o': orphan = 1; break;
	case 'U':
	  underlying_node_name = strdup (arg);
	  if (underlying_node_name == NULL)
	    error(3, ENOMEM, "Failed to duplicate argument");
	  break;

	case 'C':
	  if (chroot_command)
	    {
	      argp_error (state, "--chroot given twice");
	      return EINVAL;
	    }
	  chroot_command = &state->argv[state->next];
	  while (state->next < state->argc)
	    {
	      if (!strcmp (state->argv[state->next], "--"))
		{
		  state->argv[state->next++] = 0;
		  if (chroot_command[0] == 0)
		    {
		      argp_error (state,
				  "--chroot must be followed by a command");
		      return EINVAL;
		    }
		  return 0;
		}
	      ++state->next;
	    }
	  argp_error (state, "--chroot command must be terminated with `--'");
	  return EINVAL;

	case OPT_CHROOT_CHDIR:
	  if (arg[0] != '/')
	    argp_error (state, "--chroot-chdir must be absolute");
	  chroot_chdir = arg;
	  break;

	case 'c': lookup_flags |= O_CREAT; break;
	case 'L': lookup_flags &= ~O_NOTRANS; break;

	case 'R': goaway_flags |= FSYS_GOAWAY_RECURSE; break;
	case 'S': goaway_flags |= FSYS_GOAWAY_NOSYNC; break;
	case 'f': goaway_flags |= FSYS_GOAWAY_FORCE; break;

	  /* Use atof so the user can specifiy fractional timeouts.  */
	case 't': timeout = atof (arg) * 1000.0; break;

	default:
	  return ARGP_ERR_UNKNOWN;
	}
      return 0;
    }
  struct argp argp = {options, parse_opt, args_doc, doc};

  argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0);

  if (stack)
    {
      underlying_node_name = node_name;
      underlying_lookup_flags = lookup_flags && ~O_NOTRANS;
    }
  else
    underlying_lookup_flags = lookup_flags;

  if (!active && !passive && !chroot_command)
    passive = 1;		/* By default, set the passive translator.  */

  if (passive)
    passive_flags = FS_TRANS_SET | (excl ? FS_TRANS_EXCL : 0);
  if (active)
    active_flags = FS_TRANS_SET | (excl ? FS_TRANS_EXCL : 0)
		   | (orphan ? FS_TRANS_ORPHAN : 0);

  if (passive && !active)
    {
      /* When setting just the passive, decide what to do with any active.  */
      if (kill_active)
	/* Make it go away.  */
	active_flags = FS_TRANS_SET;
      else if (! keep_active)
	/* Ensure that there isn't one.  */
	active_flags = FS_TRANS_SET | FS_TRANS_EXCL;
    }

  if (start)
    {
      /* Retrieve the passive translator record in argz.  */
      mach_port_t node = file_name_lookup (node_name, lookup_flags, 0);
      if (node == MACH_PORT_NULL)
	error (4, errno, "%s", node_name);

      char buf[1024];
      argz = buf;
      argz_len = sizeof (buf);

      err = file_get_translator (node, &argz, &argz_len);
      if (err == EINVAL)
	error (4, 0, "%s: no passive translator record found", node_name);
      if (err)
	error (4, err, "%s", node_name);

      mach_port_deallocate (mach_task_self (), node);
    }

  if ((active || chroot_command) && argz_len > 0)
    {
      /* Error during file lookup; we use this to avoid duplicating error
	 messages.  */
      error_t open_err = 0;

      /* The callback to start_translator opens NODE as a side effect.  */
      error_t open_node (int flags,
			 mach_port_t *underlying,
			 mach_msg_type_name_t *underlying_type,
			 task_t task, void *cookie)
	{
	  if (pause)
	    {
	      fprintf (stderr, "Translator pid: %d\nPausing...",
	               task2pid (task));
	      getchar ();
	    }

	  if (pid_file != NULL)
	    {
	      FILE *h;
	      h = fopen (pid_file, "w");
	      if (h == NULL)
		error (4, errno, "Failed to open pid file");

	      fprintf (h, "%i\n", task2pid (task));
	      fclose (h);
	    }

	  node = file_name_lookup (node_name, flags | lookup_flags, 0666);
	  if (node == MACH_PORT_NULL)
	    {
	      open_err = errno;
	      return open_err;
	    }

	  if (underlying_node_name)
	    {
	      *underlying = file_name_lookup (underlying_node_name,
					      flags | underlying_lookup_flags,
					      0666);
	      if (! MACH_PORT_VALID (*underlying))
		{
		  /* For the error message.  */
		  node_name = underlying_node_name;
		  open_err = errno;
		  return open_err;
		}
	    }
	  else
	    *underlying = node;
	  *underlying_type = MACH_MSG_TYPE_COPY_SEND;

	  return 0;
	}
      err = fshelp_start_translator (open_node, NULL, argz, argz, argz_len,
				     timeout, &active_control);
      if (err)
	/* If ERR is due to a problem opening the translated node, we print
	   that name, otherwise, the name of the translator.  */
	error(4, err, "%s", (err == open_err) ? node_name : argz);
    }
Пример #3
0
/* Mount one filesystem.  */
static error_t
do_mount (struct fs *fs, int remount)
{
    error_t err;
    char *fsopts, *o;
    size_t fsopts_len;
    char *mntopts;
    size_t mntopts_len;
    fsys_t mounted;

    inline void explain (const char *command)
    {
        if (verbose)
        {
            const char *o;
            printf ("%s %s", command, fs->mntent.mnt_dir);
            for (o = fsopts; o; o = argz_next (fsopts, fsopts_len, o))
                printf (" %s", o);
            putchar ('\n');
        }
    }

    err = fs_fsys (fs, &mounted);
    if (err)
    {
        error (0, err, "cannot determine if %s is already mounted",
               fs->mntent.mnt_fsname);
        return err;
    }


    /* Produce an argz of translator option arguments from the
       given FS's options and the command-line options.  */

#define ARGZ(call)							      \
  err = argz_##call;							      \
  if (err)								      \
    error (3, ENOMEM, "collecting mount options");			      \

    if (fs->mntent.mnt_opts)
    {
        /* Append the fstab options to any specified on the command line.  */
        ARGZ (create_sep (fs->mntent.mnt_opts, ',', &mntopts, &mntopts_len));

        /* Remove the `noauto' and `bind' options, since they're for us not the
           filesystem.  */
        for (o = mntopts; o; o = argz_next (mntopts, mntopts_len, o))
        {
            if (strcmp (o, MNTOPT_NOAUTO) == 0)
                argz_delete (&mntopts, &mntopts_len, o);
            if (strcmp (o, "bind") == 0)
            {
                fs->mntent.mnt_type = strdup ("firmlink");
                if (!fs->mntent.mnt_type)
                    error (3, ENOMEM, "failed to allocate memory");
                argz_delete (&mntopts, &mntopts_len, o);
            }
        }

        ARGZ (append (&mntopts, &mntopts_len, options, options_len));
    }
    else
    {
        mntopts = options;
        mntopts_len = options_len;
    }

    /* Convert the list of options into a list of switch arguments.  */
    fsopts = 0;
    fsopts_len = 0;
    for (o = mntopts; o; o = argz_next (mntopts, mntopts_len, o))
        if (*o == '-')		/* Allow letter opts `-o -r,-E', BSD style.  */
        {
            ARGZ (add (&fsopts, &fsopts_len, o));
        }
        else if ((strcmp (o, "defaults") != 0) && (strlen (o) != 0))
        {
            /* Prepend `--' to the option to make a long option switch,
               e.g. `--ro' or `--rsize=1024'.  */
            char arg[2 + strlen (o) + 1];
            arg[0] = arg[1] = '-';
            memcpy (&arg[2], o, sizeof arg - 2);
            ARGZ (add (&fsopts, &fsopts_len, arg));
        }

    if (mntopts != options)
        free (mntopts);
#undef ARGZ

    if (remount)
    {
        if (mounted == MACH_PORT_NULL)
        {
            error (0, 0, "%s not already mounted", fs->mntent.mnt_fsname);
            return EBUSY;
        }

        /* Send an RPC to request the new options, including --update.  */
        explain ("fsysopts");
        err = fsys_set_options (mounted, fsopts, fsopts_len, 0);
        if (err)
            error (0, err, "cannot remount %s", fs->mntent.mnt_fsname);
        return err;
    }
    else
    {
        /* Error during file lookup; we use this to avoid duplicating error
        messages.  */
        error_t open_err = 0;
        /* The control port for any active translator we start up.  */
        fsys_t active_control;
        file_t node;		/* Port to the underlying node.  */
        struct fstype *type;

        /* The callback to start_translator opens NODE as a side effect.  */
        error_t open_node (int flags,
                           mach_port_t *underlying,
                           mach_msg_type_name_t *underlying_type,
                           task_t task, void *cookie)
        {
            node = file_name_lookup (fs->mntent.mnt_dir,
                                     flags | O_NOTRANS, 0666);
            if (node == MACH_PORT_NULL)
            {
                open_err = errno;
                return open_err;
            }

            *underlying = node;
            *underlying_type = MACH_MSG_TYPE_COPY_SEND;

            return 0;
        }

        /* Do not fail if there is an active translator if --fake is
           given. This mimics Linux mount utility more closely which
           just looks into the mtab file. */
        if (mounted != MACH_PORT_NULL && !fake)
        {
            error (0, 0, "%s already mounted", fs->mntent.mnt_fsname);
            return EBUSY;
        }

        if (strcmp (fs->mntent.mnt_type, "auto") == 0)
        {
#if HAVE_BLKID
            char *type =
                blkid_get_tag_value (NULL, "TYPE", fs->mntent.mnt_fsname);
            if (! type)
            {
                error (0, 0, "failed to detect file system type");
                return EFTYPE;
            }
            else
            {
                if (strcmp (type, "vfat") == 0)
                    fs->mntent.mnt_type = strdup ("fat");
                else
                    fs->mntent.mnt_type = strdup (type);
                if (! fs->mntent.mnt_type)
                    error (3, ENOMEM, "failed to allocate memory");
            }
#else
            fs->mntent.mnt_type = strdup ("ext2");
            if (! fs->mntent.mnt_type)
                error (3, ENOMEM, "failed to allocate memory");
#endif
        }

        err = fs_type (fs, &type);
        if (err)
        {
            error (0, err, "%s: cannot determine filesystem type",
                   fs->mntent.mnt_fsname);
            return err;
        }
        if (type->program == 0)
        {
            error (0, 0, "%s: filesystem type `%s' unknown",
                   fs->mntent.mnt_fsname, type->name);
            return EFTYPE;
        }

        /* Stick the translator program name in front of the option switches.  */
        err = argz_insert (&fsopts, &fsopts_len, fsopts, type->program);
        /* Now stick the device name on the end as the last argument.  */
        if (!err)
            err = argz_add (&fsopts, &fsopts_len, fs->mntent.mnt_fsname);
        if (err)
            error (3, ENOMEM, "collecting mount options");

        /* Now we have a translator command line argz in FSOPTS.  */

        if (fake) {
            /* Fake the translator startup. */
            mach_port_t underlying;
            mach_msg_type_name_t underlying_type;
            err = open_node (O_READ, &underlying, &underlying_type, 0, NULL);
            if (err)
                error (1, errno, "cannot mount on %s", fs->mntent.mnt_dir);

            mach_port_deallocate (mach_task_self (), underlying);

            /* See if the translator is at least executable. */
            if (access(type->program, X_OK) == -1)
                error (1, errno, "can not execute %s", type->program);

            return 0;
        }

        explain ("settrans -a");
        err = fshelp_start_translator (open_node, NULL, fsopts,
                                       fsopts, fsopts_len, timeout,
                                       &active_control);
        /* If ERR is due to a problem opening the translated node, we print
        that name, otherwise, the name of the translator.  */
        if (open_err)
            error (0, open_err, "cannot mount on %s", fs->mntent.mnt_dir);
        else if (err)
            error (0, err, "cannot start translator %s", fsopts);
        else
        {
            err = file_set_translator (node, 0, FS_TRANS_SET|FS_TRANS_EXCL, 0,
                                       0, 0,
                                       active_control, MACH_MSG_TYPE_COPY_SEND);
            if (err == EBUSY)
                error (0, 0, "%s already mounted on", fs->mntent.mnt_dir);
            else if (err)
                error (0, err, "cannot set translator on %s", fs->mntent.mnt_dir);
            if (err)
                fsys_goaway (active_control, FSYS_GOAWAY_FORCE);
            mach_port_deallocate (mach_task_self (), active_control);
        }

        return err;
    }