1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <fs-management/mount.h>
6 
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <string.h>
10 #include <unistd.h>
11 
12 #include <fbl/algorithm.h>
13 #include <fbl/alloc_checker.h>
14 #include <fbl/auto_call.h>
15 #include <fbl/unique_fd.h>
16 #include <fbl/unique_ptr.h>
17 #include <fs/client.h>
18 #include <fuchsia/io/c/fidl.h>
19 #include <lib/fdio/limits.h>
20 #include <lib/fdio/util.h>
21 #include <lib/fdio/vfs.h>
22 #include <lib/fzl/fdio.h>
23 #include <lib/zx/channel.h>
24 #include <zircon/compiler.h>
25 #include <zircon/device/block.h>
26 #include <zircon/device/vfs.h>
27 #include <zircon/processargs.h>
28 #include <zircon/syscalls.h>
29 
30 #include <utility>
31 
32 namespace {
33 
34 using fbl::unique_fd;
35 
MountFs(int fd,zx_handle_t root)36 zx_status_t MountFs(int fd, zx_handle_t root) {
37     zx_status_t status;
38     fzl::FdioCaller caller{fbl::unique_fd(fd)};
39     zx_status_t io_status = fuchsia_io_DirectoryAdminMount(caller.borrow_channel(),
40                                                            root, &status);
41     caller.release().release();
42     if (io_status != ZX_OK) {
43         return io_status;
44     }
45     return status;
46 }
47 
UnmountHandle(zx_handle_t root,bool wait_until_ready)48 void UnmountHandle(zx_handle_t root, bool wait_until_ready) {
49     // We've entered a failure case where the filesystem process (which may or may not be alive)
50     // had a *chance* to be spawned, but cannot be attached to a vnode (for whatever reason).
51     // Rather than abandoning the filesystem process (maybe causing dirty bits to be set), give it a
52     // chance to shutdown properly.
53     //
54     // The unmount process is a little atypical, since we're just sending a signal over a handle,
55     // rather than detaching the mounted filesystem from the "parent" filesystem.
56     vfs_unmount_handle(root, wait_until_ready ? ZX_TIME_INFINITE : 0);
57 }
58 
59 // Performs the actual work of mounting a volume.
60 class Mounter {
61 public:
62     // The mount point is either a path (to be created) or an existing fd.
Mounter(int fd)63     explicit Mounter(int fd) : path_(nullptr), fd_(fd) {}
Mounter(const char * path)64     explicit Mounter(const char* path) : path_(path), fd_(-1) {}
~Mounter()65     ~Mounter() {}
66 
67     // Mounts the given device.
68     zx_status_t Mount(unique_fd device, disk_format_t format, const mount_options_t& options,
69                       LaunchCallback cb);
70 
71     DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Mounter);
72 
73 private:
74     zx_status_t PrepareHandles(unique_fd device);
75     zx_status_t MakeDirAndMount(const mount_options_t& options);
76     zx_status_t LaunchAndMount(LaunchCallback cb, const mount_options_t& options, const char** argv,
77                                int argc);
78     zx_status_t MountNativeFs(const char* binary, unique_fd device, const mount_options_t& options,
79                               LaunchCallback cb);
80     zx_status_t MountFat(unique_fd device, const mount_options_t& options, LaunchCallback cb);
81 
82     zx_handle_t root_ = ZX_HANDLE_INVALID;
83     const char* path_;
84     int fd_;
85     uint32_t flags_ = 0; // Currently not used.
86     size_t num_handles_ = 0;
87     zx_handle_t handles_[FDIO_MAX_HANDLES * 2];
88     uint32_t ids_[FDIO_MAX_HANDLES * 2];
89 };
90 
91 // Initializes 'handles_' and 'ids_' with the root handle and block device handle.
PrepareHandles(unique_fd device)92 zx_status_t Mounter::PrepareHandles(unique_fd device) {
93     zx_handle_t mountee_handle;
94     zx_status_t status = zx_channel_create(0, &mountee_handle, &root_);
95     if (status != ZX_OK) {
96         return status;
97     }
98     handles_[0] = mountee_handle;
99     ids_[0] = PA_USER0;
100     num_handles_ = 1;
101 
102     int device_fd = device.release();
103     status = fdio_transfer_fd(device_fd, FS_FD_BLOCKDEVICE, &handles_[1], &ids_[1]);
104     if (status < 0) {
105         // Note that fdio_transfer_fd returns > 0 on success :(.
106         fprintf(stderr, "Failed to access device handle\n");
107         zx_handle_close(mountee_handle);
108         zx_handle_close(root_);
109         device.reset(device_fd);
110         return status != 0 ? status : ZX_ERR_BAD_STATE;
111     }
112     num_handles_ += status;
113     return ZX_OK;
114 }
115 
MakeDirAndMount(const mount_options_t & options)116 zx_status_t Mounter::MakeDirAndMount(const mount_options_t& options) {
117     auto cleanup =
118         fbl::MakeAutoCall([this, options]() { UnmountHandle(root_, options.wait_until_ready); });
119 
120     // Open the parent path as O_ADMIN, and sent the mkdir+mount command
121     // to that directory.
122     char parent_path[PATH_MAX];
123     const char* name;
124     strcpy(parent_path, path_);
125     char* last_slash = strrchr(parent_path, '/');
126     if (last_slash == NULL) {
127         strcpy(parent_path, ".");
128         name = path_;
129     } else {
130         *last_slash = '\0';
131         name = last_slash + 1;
132         if (*name == '\0') {
133             return ZX_ERR_INVALID_ARGS;
134         }
135     }
136 
137     unique_fd parent(open(parent_path, O_RDONLY | O_DIRECTORY | O_ADMIN));
138     if (!parent) {
139         return ZX_ERR_IO;
140     }
141 
142     cleanup.cancel();
143 
144     zx_status_t status;
145     fzl::FdioCaller caller(std::move(parent));
146     zx_status_t io_status = fuchsia_io_DirectoryAdminMountAndCreate(
147             caller.borrow_channel(), root_, name, strlen(name), flags_, &status);
148     if (io_status != ZX_OK) {
149         return io_status;
150     }
151     return status;
152 }
153 
154 // Calls the 'launch callback' and mounts the remote handle to the target vnode, if successful.
LaunchAndMount(LaunchCallback cb,const mount_options_t & options,const char ** argv,int argc)155 zx_status_t Mounter::LaunchAndMount(LaunchCallback cb, const mount_options_t& options,
156                                     const char** argv, int argc) {
157     auto cleanup =
158         fbl::MakeAutoCall([this, options]() { UnmountHandle(root_, options.wait_until_ready); });
159 
160     zx_status_t status = cb(argc, argv, handles_, ids_, num_handles_);
161     if (status != ZX_OK) {
162         return status;
163     }
164 
165     if (options.wait_until_ready) {
166         // Wait until the filesystem is ready to take incoming requests
167         zx_signals_t observed;
168         status = zx_object_wait_one(root_, ZX_USER_SIGNAL_0 | ZX_CHANNEL_PEER_CLOSED,
169                                     ZX_TIME_INFINITE, &observed);
170         if ((status != ZX_OK) || (observed & ZX_CHANNEL_PEER_CLOSED)) {
171             status = (status != ZX_OK) ? status : ZX_ERR_BAD_STATE;
172             return status;
173         }
174     }
175     cleanup.cancel();
176 
177     // Install remote handle.
178     if (options.create_mountpoint) {
179         return MakeDirAndMount(options);
180     }
181     return MountFs(fd_, root_);
182 }
183 
MountNativeFs(const char * binary,unique_fd device,const mount_options_t & options,LaunchCallback cb)184 zx_status_t Mounter::MountNativeFs(const char* binary, unique_fd device,
185                                    const mount_options_t& options, LaunchCallback cb) {
186     zx_status_t status = PrepareHandles(std::move(device));
187     if (status != ZX_OK) {
188         return status;
189     }
190 
191     if (options.verbose_mount) {
192         printf("fs_mount: Launching %s\n", binary);
193     }
194 
195     // 1. binary
196     // 2. (optional) readonly
197     // 3. (optional) verbose
198     // 4. (optional) metrics
199     // 5. command
200     const char* argv[5] = {binary};
201     int argc = 1;
202     if (options.readonly) {
203         argv[argc++] = "--readonly";
204     }
205     if (options.verbose_mount) {
206         argv[argc++] = "--verbose";
207     }
208     if (options.collect_metrics) {
209         argv[argc++] = "--metrics";
210     }
211     if (options.enable_journal) {
212         argv[argc++] = "--journal";
213     }
214     argv[argc++] = "mount";
215     return LaunchAndMount(cb, options, argv, argc);
216 }
217 
MountFat(unique_fd device,const mount_options_t & options,LaunchCallback cb)218 zx_status_t Mounter::MountFat(unique_fd device, const mount_options_t& options, LaunchCallback cb) {
219     zx_status_t status = PrepareHandles(std::move(device));
220     if (status != ZX_OK) {
221         return status;
222     }
223 
224     char readonly_arg[64];
225     snprintf(readonly_arg, sizeof(readonly_arg), "-readonly=%s",
226              options.readonly ? "true" : "false");
227     char blockfd_arg[64];
228     snprintf(blockfd_arg, sizeof(blockfd_arg), "-blockFD=%d", FS_FD_BLOCKDEVICE);
229 
230     if (options.verbose_mount) {
231         printf("fs_mount: Launching ThinFS\n");
232     }
233     const char* argv[] = {
234         "/system/bin/thinfs",
235         readonly_arg,
236         blockfd_arg,
237         "mount",
238     };
239     return LaunchAndMount(cb, options, argv, fbl::count_of(argv));
240 }
241 
Mount(unique_fd device,disk_format_t format,const mount_options_t & options,LaunchCallback cb)242 zx_status_t Mounter::Mount(unique_fd device, disk_format_t format, const mount_options_t& options,
243                            LaunchCallback cb) {
244     switch (format) {
245     case DISK_FORMAT_MINFS:
246         return MountNativeFs("/boot/bin/minfs", std::move(device), options, cb);
247     case DISK_FORMAT_BLOBFS:
248         return MountNativeFs("/boot/bin/blobfs", std::move(device), options, cb);
249     case DISK_FORMAT_FAT:
250         return MountFat(std::move(device), options, cb);
251     default:
252         return ZX_ERR_NOT_SUPPORTED;
253     }
254 }
255 
256 } // namespace
257 
258 const mount_options_t default_mount_options = {
259     .readonly = false,
260     .verbose_mount = false,
261     .collect_metrics = false,
262     .wait_until_ready = true,
263     .create_mountpoint = false,
264     .enable_journal = false,
265 };
266 
267 const mkfs_options_t default_mkfs_options = {
268     .fvm_data_slices = 1,
269     .verbose = false,
270 };
271 
272 const fsck_options_t default_fsck_options = {
273     .verbose = false,
274     .never_modify = false,
275     .always_modify = false,
276     .force = false,
277 };
278 
detect_disk_format(int fd)279 disk_format_t detect_disk_format(int fd) {
280     if (lseek(fd, 0, SEEK_SET) != 0) {
281         fprintf(stderr, "detect_disk_format: Cannot seek to start of device.\n");
282         return DISK_FORMAT_UNKNOWN;
283     }
284 
285     block_info_t info;
286     ssize_t r;
287     if ((r = ioctl_block_get_info(fd, &info)) < 0) {
288         fprintf(stderr, "detect_disk_format: Could not acquire block device info\n");
289         return DISK_FORMAT_UNKNOWN;
290     }
291 
292     // We expect to read HEADER_SIZE bytes, but we may need to read
293     // extra to read a multiple of the underlying block size.
294     const size_t buffer_size = fbl::round_up(static_cast<size_t>(HEADER_SIZE),
295                                              static_cast<size_t>(info.block_size));
296 
297     uint8_t data[buffer_size];
298     if (read(fd, data, buffer_size) != static_cast<ssize_t>(buffer_size)) {
299         fprintf(stderr, "detect_disk_format: Error reading block device.\n");
300         return DISK_FORMAT_UNKNOWN;
301     }
302 
303     if (!memcmp(data, fvm_magic, sizeof(fvm_magic))) {
304         return DISK_FORMAT_FVM;
305     }
306 
307     if (!memcmp(data, zxcrypt_magic, sizeof(zxcrypt_magic))) {
308         return DISK_FORMAT_ZXCRYPT;
309     }
310 
311     if (!memcmp(data + 0x200, gpt_magic, sizeof(gpt_magic))) {
312         return DISK_FORMAT_GPT;
313     }
314 
315     if (!memcmp(data, minfs_magic, sizeof(minfs_magic))) {
316         return DISK_FORMAT_MINFS;
317     }
318 
319     if (!memcmp(data, blobfs_magic, sizeof(blobfs_magic))) {
320         return DISK_FORMAT_BLOBFS;
321     }
322 
323     if ((data[510] == 0x55 && data[511] == 0xAA)) {
324         if ((data[38] == 0x29 || data[66] == 0x29)) {
325             // 0x55AA are always placed at offset 510 and 511 for FAT filesystems.
326             // 0x29 is the Boot Signature, but it is placed at either offset 38 or
327             // 66 (depending on FAT type).
328             return DISK_FORMAT_FAT;
329         }
330         return DISK_FORMAT_MBR;
331     }
332     return DISK_FORMAT_UNKNOWN;
333 }
334 
fmount(int device_fd,int mount_fd,disk_format_t df,const mount_options_t * options,LaunchCallback cb)335 zx_status_t fmount(int device_fd, int mount_fd, disk_format_t df, const mount_options_t* options,
336                    LaunchCallback cb) {
337     Mounter mounter(mount_fd);
338     return mounter.Mount(unique_fd(device_fd), df, *options, cb);
339 }
340 
mount(int device_fd,const char * mount_path,disk_format_t df,const mount_options_t * options,LaunchCallback cb)341 zx_status_t mount(int device_fd, const char* mount_path, disk_format_t df,
342                   const mount_options_t* options, LaunchCallback cb) {
343     if (!options->create_mountpoint) {
344         // Open mountpoint; use it directly.
345         unique_fd mount_point(open(mount_path, O_RDONLY | O_DIRECTORY | O_ADMIN));
346         if (!mount_point) {
347             return ZX_ERR_BAD_STATE;
348         }
349         return fmount(device_fd, mount_point.get(), df, options, cb);
350     }
351 
352     Mounter mounter(mount_path);
353     return mounter.Mount(unique_fd(device_fd), df, *options, cb);
354 }
355 
fumount(int mount_fd)356 zx_status_t fumount(int mount_fd) {
357     zx_handle_t h;
358     zx_status_t status;
359     fzl::FdioCaller caller{fbl::unique_fd(mount_fd)};
360     zx_status_t io_status = fuchsia_io_DirectoryAdminUnmountNode(caller.borrow_channel(),
361                                                                  &status, &h);
362     caller.release().release();
363     if (io_status != ZX_OK) {
364         return io_status;
365     }
366     zx::channel c(h);
367     if (status != ZX_OK) {
368         return status;
369     }
370     return vfs_unmount_handle(c.release(), ZX_TIME_INFINITE);
371 }
372 
umount(const char * mount_path)373 zx_status_t umount(const char* mount_path) {
374     unique_fd fd(open(mount_path, O_DIRECTORY | O_NOREMOTE | O_ADMIN));
375     if (!fd) {
376         fprintf(stderr, "Could not open directory: %s\n", strerror(errno));
377         return ZX_ERR_BAD_STATE;
378     }
379     zx_status_t status = fumount(fd.get());
380     return status;
381 }
382