regressions: Enable both tests for bug 576879 (not fixed).
[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, 0, 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, 0, { 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 static char **
178 mounts_or_mountpoints (int mp)
179 {
180   char *out, *err;
181   int r;
182   char **ret = NULL;
183   int size = 0, alloc = 0;
184   char *p, *pend, *p2;
185   int len;
186   char matching[5 + sysroot_len];
187   size_t i;
188
189   r = command (&out, &err, "mount", NULL);
190   if (r == -1) {
191     reply_with_error ("mount: %s", err);
192     free (out);
193     free (err);
194     return NULL;
195   }
196
197   free (err);
198
199   /* Lines have the format:
200    *   /dev/foo on /mountpoint type ...
201    */
202   snprintf (matching, 5 + sysroot_len, " on %s", sysroot);
203
204   p = out;
205   while (p) {
206     pend = strchr (p, '\n');
207     if (pend) {
208       *pend = '\0';
209       pend++;
210     }
211
212     p2 = strstr (p, matching);
213     if (p2 != NULL) {
214       *p2 = '\0';
215       if (add_string (&ret, &size, &alloc, p) == -1) {
216         free (out);
217         return NULL;
218       }
219       if (mp) {
220         p2 += 4 + sysroot_len;  /* skip " on /sysroot" */
221         len = strcspn (p2, " ");
222
223         if (len == 0)           /* .. just /sysroot, so we turn it into "/" */
224           p2 = (char *) "/";
225         else
226           p2[len] = '\0';
227
228         if (add_string (&ret, &size, &alloc, p2) == -1) {
229           free (out);
230           return NULL;
231         }
232       }
233     }
234
235     p = pend;
236   }
237
238   free (out);
239
240   if (add_string (&ret, &size, &alloc, NULL) == -1)
241     return NULL;
242
243   /* Convert /dev/mapper LV paths into canonical paths (RHBZ#646432). */
244   for (i = 0; ret[i] != NULL; i += mp ? 2 : 1) {
245     if (STRPREFIX (ret[i], "/dev/mapper/") || STRPREFIX (ret[i], "/dev/dm-")) {
246       char *canonical;
247       r = lv_canonical (ret[i], &canonical);
248       if (r == -1) {
249         free_strings (ret);
250         return NULL;
251       }
252       if (r == 1) {
253         free (ret[i]);
254         ret[i] = canonical;
255       }
256       /* Ignore the case where r == 0.  This might happen where
257        * eg. a LUKS /dev/mapper device is mounted, but that won't
258        * correspond to any LV.
259        */
260     }
261   }
262
263   return ret;
264 }
265
266 char **
267 do_mounts (void)
268 {
269   return mounts_or_mountpoints (0);
270 }
271
272 char **
273 do_mountpoints (void)
274 {
275   return mounts_or_mountpoints (1);
276 }
277
278 /* Unmount everything mounted under /sysroot.
279  *
280  * We have to unmount in the correct order, so we sort the paths by
281  * longest first to ensure that child paths are unmounted by parent
282  * paths.
283  *
284  * This call is more important than it appears at first, because it
285  * is widely used by both test and production code in order to
286  * get back to a known state (nothing mounted, everything synchronized).
287  */
288 static int
289 compare_longest_first (const void *vp1, const void *vp2)
290 {
291   char * const *p1 = (char * const *) vp1;
292   char * const *p2 = (char * const *) vp2;
293   int n1 = strlen (*p1);
294   int n2 = strlen (*p2);
295   return n2 - n1;
296 }
297
298 int
299 do_umount_all (void)
300 {
301   char *out, *err;
302   int i, r;
303   char **mounts = NULL;
304   int size = 0, alloc = 0;
305   char *p, *p2, *p3, *pend;
306   char matching[5 + sysroot_len];
307
308   r = command (&out, &err, "mount", NULL);
309   if (r == -1) {
310     reply_with_error ("mount: %s", err);
311     free (out);
312     free (err);
313     return -1;
314   }
315
316   free (err);
317
318   /* Lines have the format:
319    *   /dev/foo on /mountpoint type ...
320    */
321   snprintf (matching, 5 + sysroot_len, " on %s", sysroot);
322
323   p = out;
324   while (p) {
325     pend = strchr (p, '\n');
326     if (pend) {
327       *pend = '\0';
328       pend++;
329     }
330
331     p2 = strstr (p, matching);
332     if (p2 != NULL) {
333       p2 += 4;
334       p3 = p2 + strcspn (p2, " ");
335       *p3 = '\0';
336       if (add_string (&mounts, &size, &alloc, p2) == -1) {
337         free (out);
338         return -1;
339       }
340     }
341
342     p = pend;
343   }
344   free (out);
345
346   qsort (mounts, size, sizeof (char *), compare_longest_first);
347
348   /* Unmount them. */
349   for (i = 0; i < size; ++i) {
350     r = command (NULL, &err, "umount", mounts[i], NULL);
351     if (r == -1) {
352       reply_with_error ("umount: %s: %s", mounts[i], err);
353       free (err);
354       free_stringslen (mounts, size);
355       return -1;
356     }
357     free (err);
358   }
359
360   free_stringslen (mounts, size);
361
362   return 0;
363 }
364
365 /* Mount using the loopback device.  You can't use the generic
366  * do_mount call for this because the first parameter isn't a
367  * device.
368  */
369 int
370 do_mount_loop (const char *file, const char *mountpoint)
371 {
372   int r;
373   char *buf, *mp;
374   char *error;
375
376   /* We have to prefix /sysroot on both the filename and the mountpoint. */
377   mp = sysroot_path (mountpoint);
378   if (!mp) {
379     reply_with_perror ("malloc");
380     return -1;
381   }
382
383   buf = sysroot_path (file);
384   if (!file) {
385     reply_with_perror ("malloc");
386     free (mp);
387     return -1;
388   }
389
390   r = command (NULL, &error, "mount", "-o", "loop", buf, mp, NULL);
391   free (mp);
392   free (buf);
393   if (r == -1) {
394     reply_with_error ("%s on %s: %s", file, mountpoint, error);
395     free (error);
396     return -1;
397   }
398
399   return 0;
400 }
401
402 /* Specialized calls mkmountpoint and rmmountpoint are really
403  * variations on mkdir and rmdir which do no checking of the
404  * is_root_mounted() flag.
405  */
406 int
407 do_mkmountpoint (const char *path)
408 {
409   int r;
410
411   /* NEED_ROOT (return -1); - we don't want this test for this call. */
412   ABS_PATH (path, 0, return -1);
413
414   CHROOT_IN;
415   r = mkdir (path, 0777);
416   CHROOT_OUT;
417
418   if (r == -1) {
419     reply_with_perror ("%s", path);
420     return -1;
421   }
422
423   return 0;
424 }
425
426 int
427 do_rmmountpoint (const char *path)
428 {
429   int r;
430
431   /* NEED_ROOT (return -1); - we don't want this test for this call. */
432   ABS_PATH (path, 0, return -1);
433
434   CHROOT_IN;
435   r = rmdir (path);
436   CHROOT_OUT;
437
438   if (r == -1) {
439     reply_with_perror ("%s", path);
440     return -1;
441   }
442
443   return 0;
444 }