098283a05f4f0a22749202f391c110736e777e95
[libguestfs.git] / daemon / mount.c
1 /* libguestfs - the guestfsd daemon
2  * Copyright (C) 2009 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <mntent.h>
28
29 #include "daemon.h"
30 #include "actions.h"
31
32 /* You must mount something on "/" first before many operations.
33  * Hence we have an internal function which can test if something is
34  * mounted on *or under* the sysroot directory.  (It has to be *or
35  * under* because of mkmountpoint and friends).
36  */
37 int
38 is_root_mounted (void)
39 {
40   FILE *fp;
41   struct mntent *m;
42
43   /* NB: Eventually we should aim to parse /proc/self/mountinfo, but
44    * that requires custom parsing code.
45    */
46   fp = setmntent ("/proc/mounts", "r");
47   if (fp == NULL) {
48     perror ("/proc/mounts");
49     exit (EXIT_FAILURE);
50   }
51
52   while ((m = getmntent (fp)) != NULL) {
53     /* Allow a mount directory like "/sysroot". */
54     if (sysroot_len > 0 && STREQ (m->mnt_dir, sysroot)) {
55     gotit:
56       endmntent (fp);
57       return 1;
58     }
59     /* Or allow a mount directory like "/sysroot/...". */
60     if (STRPREFIX (m->mnt_dir, sysroot) && m->mnt_dir[sysroot_len] == '/')
61       goto gotit;
62   }
63
64   endmntent (fp);
65   return 0;
66 }
67
68 /* The "simple mount" call offers no complex options, you can just
69  * mount a device on a mountpoint.  The variations like mount_ro,
70  * mount_options and mount_vfs let you set progressively more things.
71  *
72  * It's tempting to try a direct mount(2) syscall, but that doesn't
73  * do any autodetection, so we are better off calling out to
74  * /bin/mount.
75  */
76
77 int
78 do_mount_vfs (const char *options, const char *vfstype,
79               const char *device, const char *mountpoint)
80 {
81   int r;
82   char *mp;
83   char *error;
84   struct stat statbuf;
85
86   ABS_PATH (mountpoint, , return -1);
87
88   mp = sysroot_path (mountpoint);
89   if (!mp) {
90     reply_with_perror ("malloc");
91     return -1;
92   }
93
94   /* Check the mountpoint exists and is a directory. */
95   if (stat (mp, &statbuf) == -1) {
96     reply_with_perror ("mount: %s", mountpoint);
97     free (mp);
98     return -1;
99   }
100   if (!S_ISDIR (statbuf.st_mode)) {
101     reply_with_perror ("mount: %s: mount point is not a directory", mountpoint);
102     free (mp);
103     return -1;
104   }
105
106   if (vfstype)
107     r = command (NULL, &error,
108                  "mount", "-o", options, "-t", vfstype, device, mp, NULL);
109   else
110     r = command (NULL, &error,
111                  "mount", "-o", options, device, mp, NULL);
112   free (mp);
113   if (r == -1) {
114     reply_with_error ("%s on %s: %s", device, mountpoint, error);
115     free (error);
116     return -1;
117   }
118
119   return 0;
120 }
121
122 int
123 do_mount (const char *device, const char *mountpoint)
124 {
125   return do_mount_vfs ("sync,noatime", NULL, device, mountpoint);
126 }
127
128 int
129 do_mount_ro (const char *device, const char *mountpoint)
130 {
131   return do_mount_vfs ("ro", NULL, device, mountpoint);
132 }
133
134 int
135 do_mount_options (const char *options, const char *device,
136                   const char *mountpoint)
137 {
138   return do_mount_vfs (options, NULL, device, mountpoint);
139 }
140
141 /* Again, use the external /bin/umount program, so that /etc/mtab
142  * is kept updated.
143  */
144 int
145 do_umount (const char *pathordevice)
146 {
147   int r;
148   char *err;
149   char *buf;
150   int is_dev;
151
152   is_dev = STREQLEN (pathordevice, "/dev/", 5);
153   buf = is_dev ? strdup (pathordevice)
154                : sysroot_path (pathordevice);
155   if (buf == NULL) {
156     reply_with_perror ("malloc");
157     return -1;
158   }
159
160   if (is_dev)
161     RESOLVE_DEVICE (buf, , { free (buf); return -1; });
162
163   r = command (NULL, &err, "umount", buf, NULL);
164   free (buf);
165
166   if (r == -1) {
167     reply_with_error ("%s: %s", pathordevice, err);
168     free (err);
169     return -1;
170   }
171
172   free (err);
173
174   return 0;
175 }
176
177 /* Implement 'mounts' (mp==0) and 'mountpoints' (mp==1) calls. */
178 static char **
179 mounts_or_mountpoints (int mp)
180 {
181   FILE *fp;
182   struct mntent *m;
183   char **ret = NULL;
184   int size = 0, alloc = 0;
185   size_t i;
186   int r;
187
188   /* NB: Eventually we should aim to parse /proc/self/mountinfo, but
189    * that requires custom parsing code.
190    */
191   fp = setmntent ("/proc/mounts", "r");
192   if (fp == NULL) {
193     perror ("/proc/mounts");
194     exit (EXIT_FAILURE);
195   }
196
197   while ((m = getmntent (fp)) != NULL) {
198     /* Allow a mount directory like "/sysroot". */
199     if (sysroot_len > 0 && STREQ (m->mnt_dir, sysroot)) {
200       if (add_string (&ret, &size, &alloc, m->mnt_fsname) == -1) {
201       error:
202         endmntent (fp);
203         return NULL;
204       }
205       if (mp &&
206           add_string (&ret, &size, &alloc, "/") == -1)
207         goto error;
208     }
209     /* Or allow a mount directory like "/sysroot/...". */
210     if (STRPREFIX (m->mnt_dir, sysroot) && m->mnt_dir[sysroot_len] == '/') {
211       if (add_string (&ret, &size, &alloc, m->mnt_fsname) == -1)
212         goto error;
213       if (mp &&
214           add_string (&ret, &size, &alloc, &m->mnt_dir[sysroot_len]) == -1)
215         goto error;
216     }
217   }
218
219   endmntent (fp);
220
221   if (add_string (&ret, &size, &alloc, NULL) == -1)
222     return NULL;
223
224   /* Convert /dev/mapper LV paths into canonical paths (RHBZ#646432). */
225   for (i = 0; ret[i] != NULL; i += mp ? 2 : 1) {
226     if (STRPREFIX (ret[i], "/dev/mapper/") || STRPREFIX (ret[i], "/dev/dm-")) {
227       char *canonical;
228       r = lv_canonical (ret[i], &canonical);
229       if (r == -1) {
230         free_strings (ret);
231         return NULL;
232       }
233       if (r == 1) {
234         free (ret[i]);
235         ret[i] = canonical;
236       }
237       /* Ignore the case where r == 0.  This might happen where
238        * eg. a LUKS /dev/mapper device is mounted, but that won't
239        * correspond to any LV.
240        */
241     }
242   }
243
244   return ret;
245 }
246
247 char **
248 do_mounts (void)
249 {
250   return mounts_or_mountpoints (0);
251 }
252
253 char **
254 do_mountpoints (void)
255 {
256   return mounts_or_mountpoints (1);
257 }
258
259 /* Unmount everything mounted under /sysroot.
260  *
261  * We have to unmount in the correct order, so we sort the paths by
262  * longest first to ensure that child paths are unmounted by parent
263  * paths.
264  *
265  * This call is more important than it appears at first, because it
266  * is widely used by both test and production code in order to
267  * get back to a known state (nothing mounted, everything synchronized).
268  */
269 static int
270 compare_longest_first (const void *vp1, const void *vp2)
271 {
272   char * const *p1 = (char * const *) vp1;
273   char * const *p2 = (char * const *) vp2;
274   int n1 = strlen (*p1);
275   int n2 = strlen (*p2);
276   return n2 - n1;
277 }
278
279 int
280 do_umount_all (void)
281 {
282   FILE *fp;
283   struct mntent *m;
284   char **mounts = NULL;
285   int size = 0, alloc = 0;
286   char *err;
287   int i, r;
288
289   /* NB: Eventually we should aim to parse /proc/self/mountinfo, but
290    * that requires custom parsing code.
291    */
292   fp = setmntent ("/proc/mounts", "r");
293   if (fp == NULL) {
294     perror ("/proc/mounts");
295     exit (EXIT_FAILURE);
296   }
297
298   while ((m = getmntent (fp)) != NULL) {
299     /* Allow a mount directory like "/sysroot". */
300     if (sysroot_len > 0 && STREQ (m->mnt_dir, sysroot)) {
301       if (add_string (&mounts, &size, &alloc, m->mnt_dir) == -1) {
302         endmntent (fp);
303         return -1;
304       }
305     }
306     /* Or allow a mount directory like "/sysroot/...". */
307     if (STRPREFIX (m->mnt_dir, sysroot) && m->mnt_dir[sysroot_len] == '/') {
308       if (add_string (&mounts, &size, &alloc, m->mnt_dir) == -1) {
309         endmntent (fp);
310         return -1;
311       }
312     }
313   }
314
315   endmntent (fp);
316
317   qsort (mounts, size, sizeof (char *), compare_longest_first);
318
319   /* Unmount them. */
320   for (i = 0; i < size; ++i) {
321     r = command (NULL, &err, "umount", mounts[i], NULL);
322     if (r == -1) {
323       reply_with_error ("umount: %s: %s", mounts[i], err);
324       free (err);
325       free_stringslen (mounts, size);
326       return -1;
327     }
328     free (err);
329   }
330
331   free_stringslen (mounts, size);
332
333   return 0;
334 }
335
336 /* Mount using the loopback device.  You can't use the generic
337  * do_mount call for this because the first parameter isn't a
338  * device.
339  */
340 int
341 do_mount_loop (const char *file, const char *mountpoint)
342 {
343   int r;
344   char *buf, *mp;
345   char *error;
346
347   /* We have to prefix /sysroot on both the filename and the mountpoint. */
348   mp = sysroot_path (mountpoint);
349   if (!mp) {
350     reply_with_perror ("malloc");
351     return -1;
352   }
353
354   buf = sysroot_path (file);
355   if (!buf) {
356     reply_with_perror ("malloc");
357     free (mp);
358     return -1;
359   }
360
361   r = command (NULL, &error, "mount", "-o", "loop", buf, mp, NULL);
362   free (mp);
363   free (buf);
364   if (r == -1) {
365     reply_with_error ("%s on %s: %s", file, mountpoint, error);
366     free (error);
367     return -1;
368   }
369
370   return 0;
371 }
372
373 /* Specialized calls mkmountpoint and rmmountpoint are really
374  * variations on mkdir and rmdir which do no checking of the
375  * is_root_mounted() flag.
376  */
377 int
378 do_mkmountpoint (const char *path)
379 {
380   int r;
381
382   /* NEED_ROOT (return -1); - we don't want this test for this call. */
383   ABS_PATH (path, , return -1);
384
385   CHROOT_IN;
386   r = mkdir (path, 0777);
387   CHROOT_OUT;
388
389   if (r == -1) {
390     reply_with_perror ("%s", path);
391     return -1;
392   }
393
394   return 0;
395 }
396
397 int
398 do_rmmountpoint (const char *path)
399 {
400   int r;
401
402   /* NEED_ROOT (return -1); - we don't want this test for this call. */
403   ABS_PATH (path, , return -1);
404
405   CHROOT_IN;
406   r = rmdir (path);
407   CHROOT_OUT;
408
409   if (r == -1) {
410     reply_with_perror ("%s", path);
411     return -1;
412   }
413
414   return 0;
415 }