Add a new internal-autosync API to perform autosync.
[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   fp = setmntent ("/etc/mtab", "r");
44   if (fp == NULL) {
45     perror ("/etc/mtab");
46     exit (EXIT_FAILURE);
47   }
48
49   while ((m = getmntent (fp)) != NULL) {
50     /* Allow a mount directory like "/sysroot". */
51     if (sysroot_len > 0 && STREQ (m->mnt_dir, sysroot)) {
52     gotit:
53       endmntent (fp);
54       return 1;
55     }
56     /* Or allow a mount directory like "/sysroot/...". */
57     if (STRPREFIX (m->mnt_dir, sysroot) && m->mnt_dir[sysroot_len] == '/')
58       goto gotit;
59   }
60
61   endmntent (fp);
62   return 0;
63 }
64
65 /* The "simple mount" call offers no complex options, you can just
66  * mount a device on a mountpoint.  The variations like mount_ro,
67  * mount_options and mount_vfs let you set progressively more things.
68  *
69  * It's tempting to try a direct mount(2) syscall, but that doesn't
70  * do any autodetection, so we are better off calling out to
71  * /bin/mount.
72  */
73
74 int
75 do_mount_vfs (const char *options, const char *vfstype,
76               const char *device, const char *mountpoint)
77 {
78   int r;
79   char *mp;
80   char *error;
81   struct stat statbuf;
82
83   ABS_PATH (mountpoint, 0, return -1);
84
85   mp = sysroot_path (mountpoint);
86   if (!mp) {
87     reply_with_perror ("malloc");
88     return -1;
89   }
90
91   /* Check the mountpoint exists and is a directory. */
92   if (stat (mp, &statbuf) == -1) {
93     reply_with_perror ("mount: %s", mountpoint);
94     free (mp);
95     return -1;
96   }
97   if (!S_ISDIR (statbuf.st_mode)) {
98     reply_with_perror ("mount: %s: mount point is not a directory", mountpoint);
99     free (mp);
100     return -1;
101   }
102
103   if (vfstype)
104     r = command (NULL, &error,
105                  "mount", "-o", options, "-t", vfstype, device, mp, NULL);
106   else
107     r = command (NULL, &error,
108                  "mount", "-o", options, device, mp, NULL);
109   free (mp);
110   if (r == -1) {
111     reply_with_error ("%s on %s: %s", device, mountpoint, error);
112     free (error);
113     return -1;
114   }
115
116   return 0;
117 }
118
119 int
120 do_mount (const char *device, const char *mountpoint)
121 {
122   return do_mount_vfs ("sync,noatime", NULL, device, mountpoint);
123 }
124
125 int
126 do_mount_ro (const char *device, const char *mountpoint)
127 {
128   return do_mount_vfs ("ro", NULL, device, mountpoint);
129 }
130
131 int
132 do_mount_options (const char *options, const char *device,
133                   const char *mountpoint)
134 {
135   return do_mount_vfs (options, NULL, device, mountpoint);
136 }
137
138 /* Again, use the external /bin/umount program, so that /etc/mtab
139  * is kept updated.
140  */
141 int
142 do_umount (const char *pathordevice)
143 {
144   int r;
145   char *err;
146   char *buf;
147   int is_dev;
148
149   is_dev = STREQLEN (pathordevice, "/dev/", 5);
150   buf = is_dev ? strdup (pathordevice)
151                : sysroot_path (pathordevice);
152   if (buf == NULL) {
153     reply_with_perror ("malloc");
154     return -1;
155   }
156
157   if (is_dev)
158     RESOLVE_DEVICE (buf, 0, { free (buf); return -1; });
159
160   r = command (NULL, &err, "umount", buf, NULL);
161   free (buf);
162
163   if (r == -1) {
164     reply_with_error ("%s: %s", pathordevice, err);
165     free (err);
166     return -1;
167   }
168
169   free (err);
170
171   return 0;
172 }
173
174 static char **
175 mounts_or_mountpoints (int mp)
176 {
177   char *out, *err;
178   int r;
179   char **ret = NULL;
180   int size = 0, alloc = 0;
181   char *p, *pend, *p2;
182   int len;
183   char matching[5 + sysroot_len];
184   size_t i;
185
186   r = command (&out, &err, "mount", NULL);
187   if (r == -1) {
188     reply_with_error ("mount: %s", err);
189     free (out);
190     free (err);
191     return NULL;
192   }
193
194   free (err);
195
196   /* Lines have the format:
197    *   /dev/foo on /mountpoint type ...
198    */
199   snprintf (matching, 5 + sysroot_len, " on %s", sysroot);
200
201   p = out;
202   while (p) {
203     pend = strchr (p, '\n');
204     if (pend) {
205       *pend = '\0';
206       pend++;
207     }
208
209     p2 = strstr (p, matching);
210     if (p2 != NULL) {
211       *p2 = '\0';
212       if (add_string (&ret, &size, &alloc, p) == -1) {
213         free (out);
214         return NULL;
215       }
216       if (mp) {
217         p2 += 4 + sysroot_len;  /* skip " on /sysroot" */
218         len = strcspn (p2, " ");
219
220         if (len == 0)           /* .. just /sysroot, so we turn it into "/" */
221           p2 = (char *) "/";
222         else
223           p2[len] = '\0';
224
225         if (add_string (&ret, &size, &alloc, p2) == -1) {
226           free (out);
227           return NULL;
228         }
229       }
230     }
231
232     p = pend;
233   }
234
235   free (out);
236
237   if (add_string (&ret, &size, &alloc, NULL) == -1)
238     return NULL;
239
240   /* Convert /dev/mapper LV paths into canonical paths (RHBZ#646432). */
241   for (i = 0; ret[i] != NULL; i += mp ? 2 : 1) {
242     if (STRPREFIX (ret[i], "/dev/mapper/") || STRPREFIX (ret[i], "/dev/dm-")) {
243       char *canonical;
244       r = lv_canonical (ret[i], &canonical);
245       if (r == -1) {
246         free_strings (ret);
247         return NULL;
248       }
249       if (r == 1) {
250         free (ret[i]);
251         ret[i] = canonical;
252       }
253       /* Ignore the case where r == 0.  This might happen where
254        * eg. a LUKS /dev/mapper device is mounted, but that won't
255        * correspond to any LV.
256        */
257     }
258   }
259
260   return ret;
261 }
262
263 char **
264 do_mounts (void)
265 {
266   return mounts_or_mountpoints (0);
267 }
268
269 char **
270 do_mountpoints (void)
271 {
272   return mounts_or_mountpoints (1);
273 }
274
275 /* Unmount everything mounted under /sysroot.
276  *
277  * We have to unmount in the correct order, so we sort the paths by
278  * longest first to ensure that child paths are unmounted by parent
279  * paths.
280  *
281  * This call is more important than it appears at first, because it
282  * is widely used by both test and production code in order to
283  * get back to a known state (nothing mounted, everything synchronized).
284  */
285 static int
286 compare_longest_first (const void *vp1, const void *vp2)
287 {
288   char * const *p1 = (char * const *) vp1;
289   char * const *p2 = (char * const *) vp2;
290   int n1 = strlen (*p1);
291   int n2 = strlen (*p2);
292   return n2 - n1;
293 }
294
295 int
296 do_umount_all (void)
297 {
298   char *out, *err;
299   int i, r;
300   char **mounts = NULL;
301   int size = 0, alloc = 0;
302   char *p, *p2, *p3, *pend;
303   char matching[5 + sysroot_len];
304
305   r = command (&out, &err, "mount", NULL);
306   if (r == -1) {
307     reply_with_error ("mount: %s", err);
308     free (out);
309     free (err);
310     return -1;
311   }
312
313   free (err);
314
315   /* Lines have the format:
316    *   /dev/foo on /mountpoint type ...
317    */
318   snprintf (matching, 5 + sysroot_len, " on %s", sysroot);
319
320   p = out;
321   while (p) {
322     pend = strchr (p, '\n');
323     if (pend) {
324       *pend = '\0';
325       pend++;
326     }
327
328     p2 = strstr (p, matching);
329     if (p2 != NULL) {
330       p2 += 4;
331       p3 = p2 + strcspn (p2, " ");
332       *p3 = '\0';
333       if (add_string (&mounts, &size, &alloc, p2) == -1) {
334         free (out);
335         return -1;
336       }
337     }
338
339     p = pend;
340   }
341   free (out);
342
343   qsort (mounts, size, sizeof (char *), compare_longest_first);
344
345   /* Unmount them. */
346   for (i = 0; i < size; ++i) {
347     r = command (NULL, &err, "umount", mounts[i], NULL);
348     if (r == -1) {
349       reply_with_error ("umount: %s: %s", mounts[i], err);
350       free (err);
351       free_stringslen (mounts, size);
352       return -1;
353     }
354     free (err);
355   }
356
357   free_stringslen (mounts, size);
358
359   return 0;
360 }
361
362 /* Mount using the loopback device.  You can't use the generic
363  * do_mount call for this because the first parameter isn't a
364  * device.
365  */
366 int
367 do_mount_loop (const char *file, const char *mountpoint)
368 {
369   int r;
370   char *buf, *mp;
371   char *error;
372
373   /* We have to prefix /sysroot on both the filename and the mountpoint. */
374   mp = sysroot_path (mountpoint);
375   if (!mp) {
376     reply_with_perror ("malloc");
377     return -1;
378   }
379
380   buf = sysroot_path (file);
381   if (!file) {
382     reply_with_perror ("malloc");
383     free (mp);
384     return -1;
385   }
386
387   r = command (NULL, &error, "mount", "-o", "loop", buf, mp, NULL);
388   free (mp);
389   free (buf);
390   if (r == -1) {
391     reply_with_error ("%s on %s: %s", file, mountpoint, error);
392     free (error);
393     return -1;
394   }
395
396   return 0;
397 }
398
399 /* Specialized calls mkmountpoint and rmmountpoint are really
400  * variations on mkdir and rmdir which do no checking of the
401  * is_root_mounted() flag.
402  */
403 int
404 do_mkmountpoint (const char *path)
405 {
406   int r;
407
408   /* NEED_ROOT (return -1); - we don't want this test for this call. */
409   ABS_PATH (path, 0, return -1);
410
411   CHROOT_IN;
412   r = mkdir (path, 0777);
413   CHROOT_OUT;
414
415   if (r == -1) {
416     reply_with_perror ("%s", path);
417     return -1;
418   }
419
420   return 0;
421 }
422
423 int
424 do_rmmountpoint (const char *path)
425 {
426   int r;
427
428   /* NEED_ROOT (return -1); - we don't want this test for this call. */
429   ABS_PATH (path, 0, return -1);
430
431   CHROOT_IN;
432   r = rmdir (path);
433   CHROOT_OUT;
434
435   if (r == -1) {
436     reply_with_perror ("%s", path);
437     return -1;
438   }
439
440   return 0;
441 }