summaryrefslogtreecommitdiff
path: root/libtrivfs/startup.c
blob: dcafd292ce8791268c6b35e8343317a13630954c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/* Contact parent filesystem and establish ourselves as the translator.

   Copyright (C) 1995, 2000 Free Software Foundation, Inc.

   Written by Miles Bader <miles@gnu.ai.mit.edu>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2, or (at
   your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */

#include <hurd.h>
#include <hurd/fsys.h>
#include <assert-backtrace.h>
#include <signal.h>
#include <error.h>

#include "priv.h"

/* Creates a control port for this filesystem and sends it to BOOTSTRAP with
   fsys_startup.  CONTROL_TYPE is the ports library type for the control
   port, and PROTID_TYPE is the type for ports representing opens of this
   node.  If CONTROL isn't NULL, the trivfs control port is return in it.  If
   any error occurs sending fsys_startup, it is returned, otherwise 0.
   FLAGS specifies how to open the underlying node (O_*).  */
error_t
trivfs_startup(mach_port_t bootstrap, int flags,
	       struct port_class *control_class,
	       struct port_bucket *control_bucket,
	       struct port_class *protid_class,
	       struct port_bucket *protid_bucket,
	       struct trivfs_control **control)
{
  mach_port_t underlying, right;
  struct trivfs_control *fsys;
  error_t err =
    trivfs_create_control (MACH_PORT_NULL,
			   control_class, control_bucket,
			   protid_class, protid_bucket,
			   &fsys);

  if (err)
    return err;

  right = ports_get_send_right (fsys);

  /* Contact whoever started us.  */
  err = fsys_startup (bootstrap, flags, right, MACH_MSG_TYPE_COPY_SEND,
		      &underlying);
  mach_port_deallocate (mach_task_self (), right);

  if (! err)
    fsys->underlying = underlying;

  ports_port_deref (fsys);

  /* Pass back what we got, unless the caller doesn't want it.  */
  if (!err && control)
    *control = fsys;

  /* Mark us as important.  */
  if (! err)
    {
      mach_port_t proc = getproc ();
      if (proc == MACH_PORT_NULL)
	/* /hurd/exec uses libtrivfs.  We have no handle to the proc
	   server in /hurd/exec when it does its handshake with the
	   root filesystem, so fail graciously here.  */
	return 0;

      err = proc_mark_important (proc);
      /* This might fail due to permissions or because the old proc
	 server is still running, ignore any such errors.  */
      if (err == EPERM || err == EMIG_BAD_ID)
	err = 0;

      mach_port_deallocate (mach_task_self (), proc);
    }

  return err;
}

/* Start in debug mode, no need to be called by settrans. Common options are
   the same as in trivfs_startup. FILE_NAME is the path of the node where the
   translator is set*/
error_t
trivfs_startup_debug(const char *file_name,
		     struct port_class *control_class,
		     struct port_bucket *control_bucket,
		     struct port_class *protid_class,
		     struct port_bucket *protid_bucket,
		     struct trivfs_control **control)
{
  mach_port_t underlying, right, goaway;
  struct trivfs_control *fsys;
  error_t err =
    trivfs_create_control (MACH_PORT_NULL,
			   control_class, control_bucket,
			   protid_class, protid_bucket,
			   &fsys);

  if (err)
    return err;

  right = ports_get_send_right (fsys);
  goaway = ports_get_send_right (fsys);

  /* Start ourselves as transpator instead of replying to settrans */
  underlying = file_name_lookup(file_name, 0, 0);
  if (underlying == MACH_PORT_NULL)
    err = errno;
  else
    err = file_set_translator(underlying, 0, FS_TRANS_SET, 0, "", 0,
			      right, MACH_MSG_TYPE_COPY_SEND);
  mach_port_deallocate (mach_task_self (), right);

  if (! err)
    fsys->underlying = underlying;

  ports_port_deref (fsys);

  /* Pass back what we got, unless the caller doesn't want it.  */
  if (!err && control)
    *control = fsys;

  /* don't mark us as important and install a SIGTERM handler, so we can be
   * easily killed by Ctrl-C */
  void handler_sigterm(int signum)
  {
    error_t ee;
    ee = fsys_goaway(goaway, 0);
    if (ee == ESUCCESS)
      {
	mach_port_deallocate (mach_task_self (), goaway);
      }
    else if (ee != EBUSY)
      {
	/* Not nice */
	error(99, err, "fsys_goaway");
      }
    /* else the translator is busy, please retry */
  }

  struct sigaction sa;
  memset(&sa, 0, sizeof(sa));
  sa.sa_handler = handler_sigterm;
  if (sigaction(SIGTERM, &sa, NULL) < 0)
    err = errno;
  return err;
}