1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/server/src/main.cc Thu Feb 07 17:30:14 2019 +0100
1.3 @@ -0,0 +1,297 @@
1.4 +/*
1.5 + * Access several filesystems.
1.6 + *
1.7 + * Copyright (C) 2018, 2019 Paul Boddie <paul@boddie.org.uk>
1.8 + *
1.9 + * This program is free software; you can redistribute it and/or
1.10 + * modify it under the terms of the GNU General Public License as
1.11 + * published by the Free Software Foundation; either version 2 of
1.12 + * the License, or (at your option) any later version.
1.13 + *
1.14 + * This program is distributed in the hope that it will be useful,
1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.17 + * GNU General Public License for more details.
1.18 + *
1.19 + * You should have received a copy of the GNU General Public License
1.20 + * along with this program; if not, write to the Free Software
1.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
1.22 + * Boston, MA 02110-1301, USA
1.23 + */
1.24 +
1.25 +#include <l4/util/util.h>
1.26 +
1.27 +#include <l4/re/c/dataspace.h>
1.28 +#include <l4/re/env.h>
1.29 +#include <l4/re/c/util/cap_alloc.h>
1.30 +#include <l4/sys/err.h>
1.31 +#include <l4/sys/kernel_object.h>
1.32 +#include <l4/sys/types.h>
1.33 +
1.34 +#include <stdlib.h>
1.35 +#include <stdio.h>
1.36 +#include <string.h>
1.37 +#include <unistd.h>
1.38 +
1.39 +#include <fsclient/fs_client.h>
1.40 +#include <fsclient/fsdesc.h>
1.41 +#include <fsclient/fs_ipc.h>
1.42 +#include <fsserver/server.h>
1.43 +#include <ipc/util_ipc.h>
1.44 +#include "fspath.h"
1.45 +
1.46 +
1.47 +
1.48 +/* Virtual filesystem server. */
1.49 +
1.50 +class Vfs_server : public Server
1.51 +{
1.52 +private:
1.53 + /* NOTE: Improvised structure! */
1.54 +
1.55 + l4_cap_idx_t _servers[10];
1.56 + const char *_mountpoints[10];
1.57 + int _mounted = 0;
1.58 +
1.59 +public:
1.60 + explicit Vfs_server()
1.61 + {
1.62 + }
1.63 +
1.64 + void dispatch(ipc_message_t *msg)
1.65 + {
1.66 + switch (l4_msgtag_label(msg->tag))
1.67 + {
1.68 + case Fs_op_mount:
1.69 + mount(msg);
1.70 + break;
1.71 +
1.72 + case Fs_op_open:
1.73 + open(Fs_op_open, msg);
1.74 + break;
1.75 +
1.76 + case Fs_op_getfs:
1.77 + open(Fs_op_getfs, msg);
1.78 + break;
1.79 +
1.80 + default:
1.81 + error(msg, -L4_EBADPROTO);
1.82 + break;
1.83 + }
1.84 + }
1.85 +
1.86 + void open(int op, ipc_message_t *msg)
1.87 + {
1.88 + l4_cap_idx_t server;
1.89 + l4re_ds_t ds;
1.90 + size_t size;
1.91 + char *buffer;
1.92 + long err;
1.93 +
1.94 + /* Obtain the dataspace. */
1.95 +
1.96 + err = import_dataspace(msg, 0, &ds, (l4_addr_t *) &buffer);
1.97 + if (err)
1.98 + {
1.99 + error(msg, -L4_EIO);
1.100 + return;
1.101 + }
1.102 +
1.103 + /* Match the path to a mountpoint. */
1.104 +
1.105 + int selected = find_mountpoint(buffer);
1.106 +
1.107 + if (selected < 0)
1.108 + {
1.109 + error(msg, -L4_ENOENT);
1.110 + return;
1.111 + }
1.112 +
1.113 + /* Rewrite the path for the selected filesystem. */
1.114 +
1.115 + rewrite_path(buffer, _mountpoints[selected]);
1.116 +
1.117 + /* Find the path within the selected filesystem. */
1.118 +
1.119 + /* Propagate the message to the identified filesystem.
1.120 + NOTE: The L4_MSGTAG_PROPAGATE flag is not supported by Fiasco.OC, so this
1.121 + NOTE: object has to act as intermediary. */
1.122 +
1.123 + err = fs_ipc_open(_servers[selected], op, ds, &server, &size);
1.124 + if (err)
1.125 + {
1.126 + error(msg, -L4_EIO);
1.127 + return;
1.128 + }
1.129 +
1.130 + /* Free the capability and buffer from this task. */
1.131 +
1.132 + discard_dataspace(ds, (l4_addr_t) buffer);
1.133 +
1.134 + /* Return the file size. */
1.135 +
1.136 + ipc_message_add_word(msg, size);
1.137 +
1.138 + /* Export and eventually free the server reference from this task. */
1.139 +
1.140 + ipc_message_propagate_item(msg, server);
1.141 + }
1.142 +
1.143 + void mount(ipc_message_t *msg)
1.144 + {
1.145 + l4_cap_idx_t server;
1.146 + l4re_ds_t ds;
1.147 + char *buffer;
1.148 + long err;
1.149 +
1.150 + /* Obtain the filesystem capability. */
1.151 +
1.152 + err = import_capability(msg, 0, &server);
1.153 + if (err)
1.154 + {
1.155 + error(msg, -L4_EIO);
1.156 + return;
1.157 + }
1.158 +
1.159 + /* Obtain the dataspace. */
1.160 +
1.161 + err = import_dataspace(msg, 1, &ds, (l4_addr_t *) &buffer);
1.162 + if (err)
1.163 + {
1.164 + error(msg, -L4_EIO);
1.165 + return;
1.166 + }
1.167 +
1.168 + /* Obtain the object's path. */
1.169 +
1.170 + char *path = buffer;
1.171 +
1.172 + /* Mount the supplied capability. */
1.173 +
1.174 + mount_at_path(server, path);
1.175 +
1.176 + /* Free the capability and buffer from this task. */
1.177 +
1.178 + discard_dataspace(ds, (l4_addr_t) buffer);
1.179 + }
1.180 +
1.181 + /* Non-exported methods. */
1.182 +
1.183 + void mount_at_path(l4_cap_idx_t server, const char *path)
1.184 + {
1.185 + /* NOTE: Should return error, terminate with path separator if absent. */
1.186 +
1.187 + if (_mounted >= 10)
1.188 + return;
1.189 +
1.190 + _servers[_mounted] = server;
1.191 + _mountpoints[_mounted] = strdup(path);
1.192 +
1.193 + _mounted++;
1.194 + }
1.195 +
1.196 + int find_mountpoint(const char *path)
1.197 + {
1.198 + int i, matching;
1.199 + size_t length, longest;
1.200 +
1.201 + if (!_mounted)
1.202 + return -1;
1.203 +
1.204 + matching = -1;
1.205 + longest = 0;
1.206 +
1.207 + /* Find the largest matching path. */
1.208 +
1.209 + for (i = 0; i < _mounted; i++)
1.210 + {
1.211 + length = strlen(_mountpoints[i]);
1.212 +
1.213 + /* The empty mountpoint always matches;
1.214 + suffixed mountpoints may match as prefixes;
1.215 + suffixed mountpoints may match unsuffixed paths;
1.216 + unsuffixed mountpoints must match exactly. */
1.217 +
1.218 + /* NOTE: Unsuffixed mountpoints might support subpaths by insisting on
1.219 + a path separator as the first subsequent character. */
1.220 +
1.221 + if (!length ||
1.222 + ((_mountpoints[i][length - 1] == '/') && !strncmp(_mountpoints[i], path, length)) ||
1.223 + ((_mountpoints[i][length - 1] == '/') && (strlen(path) == length - 1) && !strncmp(_mountpoints[i], path, length - 1)) ||
1.224 + !strcmp(_mountpoints[i], path))
1.225 + {
1.226 + if (length >= longest)
1.227 + matching = i;
1.228 + }
1.229 + }
1.230 +
1.231 + return matching;
1.232 + }
1.233 +};
1.234 +
1.235 +
1.236 +
1.237 +int main(int argc, char *argv[])
1.238 +{
1.239 + FILE *fp;
1.240 + char buffer[256], *sep;
1.241 + l4_cap_idx_t fscap, server;
1.242 +
1.243 + if (argc < 2)
1.244 + {
1.245 + printf("Need a mount table.\n");
1.246 + return 1;
1.247 + }
1.248 +
1.249 + /* Initialise and register a new server object. */
1.250 +
1.251 + Vfs_server server_obj;
1.252 +
1.253 + if (bind_to_capability("export", l4_umword_t(&server_obj), &server))
1.254 + {
1.255 + printf("Could not bind thread.\n");
1.256 + return 1;
1.257 + }
1.258 +
1.259 + /* Mount filesystems. */
1.260 +
1.261 + fp = fopen(argv[1], "r");
1.262 + if (fp == NULL)
1.263 + {
1.264 + printf("Could not open %s.\n", argv[1]);
1.265 + return 1;
1.266 + }
1.267 +
1.268 + /* Obtain capabilities for mountpoints. */
1.269 +
1.270 + while (fgets(buffer, 256, fp) != NULL)
1.271 + {
1.272 + sep = strchr(buffer, (int) '\t');
1.273 + if (sep == NULL)
1.274 + continue;
1.275 +
1.276 + /* Terminate newline-suffixed strings. */
1.277 +
1.278 + if (sep[strlen(sep) - 1] == '\n')
1.279 + sep[strlen(sep) - 1] = '\0';
1.280 +
1.281 + /* Obtain the named capability. */
1.282 +
1.283 + fscap = l4re_env_get_cap(sep + 1);
1.284 +
1.285 + if (l4_is_invalid_cap(fscap))
1.286 + continue;
1.287 +
1.288 + /* Terminate the path and register the mountpoint. */
1.289 +
1.290 + *sep = '\0';
1.291 + server_obj.mount_at_path(fscap, buffer);
1.292 + }
1.293 +
1.294 + fclose(fp);
1.295 +
1.296 + /* Enter the IPC server loop expecting at most two items. */
1.297 +
1.298 + server_loop(2);
1.299 + return 0;
1.300 +}