~ubuntu-branches/ubuntu/trusty/util-linux/trusty-proposed

« back to all changes in this revision

Viewing changes to libmount/src/context_umount.c

  • Committer: Package Import Robot
  • Author(s): LaMont Jones
  • Date: 2011-11-03 15:38:23 UTC
  • mto: (4.5.5 sid) (1.6.4)
  • mto: This revision was merged to the branch mainline in revision 85.
  • Revision ID: package-import@ubuntu.com-20111103153823-10sx16jprzxlhkqf
ImportĀ upstreamĀ versionĀ 2.20.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
 
3
 *
 
4
 * This file may be redistributed under the terms of the
 
5
 * GNU Lesser General Public License.
 
6
 */
 
7
 
 
8
/**
 
9
 * SECTION: context-umount
 
10
 * @title: Umount context
 
11
 * @short_description: high-level API to umount operation.
 
12
 */
 
13
 
 
14
#include <sys/wait.h>
 
15
#include <sys/mount.h>
 
16
 
 
17
#include "pathnames.h"
 
18
#include "strutils.h"
 
19
#include "mountP.h"
 
20
 
 
21
/*
 
22
 * umount2 flags
 
23
 */
 
24
#ifndef MNT_FORCE
 
25
# define MNT_FORCE        0x00000001    /* Attempt to forcibily umount */
 
26
#endif
 
27
 
 
28
#ifndef MNT_DETACH
 
29
# define MNT_DETACH       0x00000002    /* Just detach from the tree */
 
30
#endif
 
31
 
 
32
#ifndef UMOUNT_NOFOLLOW
 
33
# define UMOUNT_NOFOLLOW  0x00000008    /* Don't follow symlink on umount */
 
34
#endif
 
35
 
 
36
#ifndef UMOUNT_UNUSED
 
37
# define UMOUNT_UNUSED    0x80000000    /* Flag guaranteed to be unused */
 
38
#endif
 
39
 
 
40
 
 
41
static int lookup_umount_fs(struct libmnt_context *cxt)
 
42
{
 
43
        int rc;
 
44
        const char *tgt;
 
45
        struct libmnt_table *mtab = NULL;
 
46
        struct libmnt_fs *fs;
 
47
 
 
48
        assert(cxt);
 
49
        assert(cxt->fs);
 
50
 
 
51
        DBG(CXT, mnt_debug_h(cxt, "umount: lookup FS"));
 
52
 
 
53
        tgt = mnt_fs_get_target(cxt->fs);
 
54
        if (!tgt) {
 
55
                DBG(CXT, mnt_debug_h(cxt, "umount: undefined target"));
 
56
                return -EINVAL;
 
57
        }
 
58
        rc = mnt_context_get_mtab(cxt, &mtab);
 
59
        if (rc) {
 
60
                DBG(CXT, mnt_debug_h(cxt, "umount: failed to read mtab"));
 
61
                return rc;
 
62
        }
 
63
        fs = mnt_table_find_target(mtab, tgt, MNT_ITER_BACKWARD);
 
64
        if (!fs) {
 
65
                /* maybe the option is source rather than target (mountpoint) */
 
66
                fs = mnt_table_find_source(mtab, tgt, MNT_ITER_BACKWARD);
 
67
 
 
68
                if (fs) {
 
69
                        struct libmnt_fs *fs1 = mnt_table_find_target(mtab,
 
70
                                                        mnt_fs_get_target(fs),
 
71
                                                        MNT_ITER_BACKWARD);
 
72
                        if (!fs1) {
 
73
                                DBG(CXT, mnt_debug_h(cxt, "mtab is broken?!?!"));
 
74
                                return -EINVAL;
 
75
                        }
 
76
                        if (fs != fs1) {
 
77
                                /* Something was stacked over `file' on the
 
78
                                 * same mount point. */
 
79
                                DBG(CXT, mnt_debug_h(cxt,
 
80
                                                "umount: %s: %s is mounted "
 
81
                                                "over it on the same point",
 
82
                                                tgt, mnt_fs_get_source(fs1)));
 
83
                                return -EINVAL;
 
84
                        }
 
85
                }
 
86
        }
 
87
 
 
88
        if (!fs) {
 
89
                DBG(CXT, mnt_debug_h(cxt, "umount: cannot find %s in mtab", tgt));
 
90
                return 0;
 
91
        }
 
92
 
 
93
        /* copy from mtab to our FS description
 
94
         */
 
95
        mnt_fs_set_source(cxt->fs, NULL);
 
96
        mnt_fs_set_target(cxt->fs, NULL);
 
97
 
 
98
        if (!mnt_copy_fs(cxt->fs, fs)) {
 
99
                DBG(CXT, mnt_debug_h(cxt, "umount: failed to copy FS"));
 
100
                return -errno;
 
101
        }
 
102
 
 
103
        DBG(CXT, mnt_debug_h(cxt, "umount: mtab applied"));
 
104
        cxt->flags |= MNT_FL_TAB_APPLIED;
 
105
        return rc;
 
106
}
 
107
 
 
108
/* check if @devname is loopdev and if the device is associated
 
109
 * with a source from @fstab_fs
 
110
 *
 
111
 * TODO : move this to loopdev.c
 
112
 */
 
113
static int mnt_loopdev_associated_fs(const char *devname, struct libmnt_fs *fs)
 
114
{
 
115
        uintmax_t offset = 0;
 
116
        const char *src;
 
117
        char *val, *optstr;
 
118
        size_t valsz;
 
119
 
 
120
        /* check if it begins with /dev/loop */
 
121
        if (strncmp(devname, _PATH_DEV_LOOP, sizeof(_PATH_DEV_LOOP)))
 
122
                return 0;
 
123
 
 
124
        src = mnt_fs_get_srcpath(fs);
 
125
        if (!src)
 
126
                return 0;
 
127
 
 
128
        /* check for offset option in @fs */
 
129
        optstr = (char *) mnt_fs_get_user_options(fs);
 
130
        if (optstr && !mnt_optstr_get_option(optstr, "offset=", &val, &valsz)) {
 
131
                int rc;
 
132
 
 
133
                val = strndup(val, valsz);
 
134
                if (!val)
 
135
                        return 0;
 
136
                rc = strtosize(val, &offset);
 
137
                free(val);
 
138
                if (rc)
 
139
                        return 0;
 
140
        }
 
141
 
 
142
        /* TODO:
 
143
         * if (mnt_loopdev_associated_file(devname, src, offset))
 
144
         *      return 1;
 
145
         */
 
146
        return 0;
 
147
}
 
148
 
 
149
static int prepare_helper_from_options(struct libmnt_context *cxt,
 
150
                                       const char *name)
 
151
{
 
152
        char *suffix = NULL;
 
153
        const char *opts;
 
154
        size_t valsz;
 
155
 
 
156
        if (cxt->flags & MNT_FL_NOHELPERS)
 
157
                return 0;
 
158
 
 
159
        opts = mnt_fs_get_user_options(cxt->fs);
 
160
        if (!opts)
 
161
                return 0;
 
162
 
 
163
        if (mnt_optstr_get_option(opts, name, &suffix, &valsz))
 
164
                return 0;
 
165
 
 
166
        suffix = strndup(suffix, valsz);
 
167
        if (!suffix)
 
168
                return -ENOMEM;
 
169
 
 
170
        DBG(CXT, mnt_debug_h(cxt, "umount: umount.%s %s requested", suffix, name));
 
171
 
 
172
        return mnt_context_prepare_helper(cxt, "umount", suffix);
 
173
}
 
174
 
 
175
/*
 
176
 * Note that cxt->fs contains relevant mtab entry!
 
177
 */
 
178
static int evaluate_permissions(struct libmnt_context *cxt)
 
179
{
 
180
        struct libmnt_table *fstab;
 
181
        unsigned long u_flags = 0;
 
182
        const char *tgt, *src, *optstr;
 
183
        int rc, ok = 0;
 
184
        struct libmnt_fs *fs;
 
185
 
 
186
        assert(cxt);
 
187
        assert(cxt->fs);
 
188
        assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
 
189
 
 
190
        if (!cxt || !cxt->fs)
 
191
                return -EINVAL;
 
192
 
 
193
        if (!mnt_context_is_restricted(cxt))
 
194
                 return 0;              /* superuser mount */
 
195
 
 
196
        DBG(CXT, mnt_debug_h(cxt, "umount: evaluating permissions"));
 
197
 
 
198
        if (!(cxt->flags & MNT_FL_TAB_APPLIED)) {
 
199
                DBG(CXT, mnt_debug_h(cxt,
 
200
                                "cannot find %s in mtab and you are not root",
 
201
                                mnt_fs_get_target(cxt->fs)));
 
202
                goto eperm;
 
203
        }
 
204
 
 
205
        if (cxt->user_mountflags & MNT_MS_UHELPER) {
 
206
                /* on uhelper= mount option based helper */
 
207
                rc = prepare_helper_from_options(cxt, "uhelper");
 
208
                if (rc)
 
209
                        return rc;
 
210
                if (cxt->helper)
 
211
                        return 0;       /* we'll call /sbin/umount.<uhelper> */
 
212
        }
 
213
 
 
214
        /*
 
215
         * User mounts has to be in /etc/fstab
 
216
         */
 
217
        rc = mnt_context_get_fstab(cxt, &fstab);
 
218
        if (rc)
 
219
                return rc;
 
220
 
 
221
        tgt = mnt_fs_get_target(cxt->fs);
 
222
        src = mnt_fs_get_source(cxt->fs);
 
223
 
 
224
        if (mnt_fs_get_bindsrc(cxt->fs)) {
 
225
                src = mnt_fs_get_bindsrc(cxt->fs);
 
226
                DBG(CXT, mnt_debug_h(cxt,
 
227
                                "umount: using bind source: %s", src));
 
228
        }
 
229
 
 
230
        /* If fstab contains the two lines
 
231
         *      /dev/sda1 /mnt/zip auto user,noauto  0 0
 
232
         *      /dev/sda4 /mnt/zip auto user,noauto  0 0
 
233
         * then "mount /dev/sda4" followed by "umount /mnt/zip" used to fail.
 
234
         * So, we must not look for file, but for the pair (dev,file) in fstab.
 
235
          */
 
236
        fs = mnt_table_find_pair(fstab, src, tgt, MNT_ITER_FORWARD);
 
237
        if (!fs) {
 
238
                /*
 
239
                 * It's possible that there is /path/file.img in fstab and
 
240
                 * /dev/loop0 in mtab -- then we have to check releation
 
241
                 * between loopdev and the file.
 
242
                 */
 
243
                fs = mnt_table_find_target(fstab, tgt, MNT_ITER_FORWARD);
 
244
                if (fs) {
 
245
                        const char *dev = mnt_fs_get_srcpath(cxt->fs);          /* devname from mtab */
 
246
 
 
247
                        if (!dev || !mnt_loopdev_associated_fs(dev, fs))
 
248
                                fs = NULL;
 
249
                }
 
250
                if (!fs) {
 
251
                        DBG(CXT, mnt_debug_h(cxt,
 
252
                                        "umount %s: mtab disagrees with fstab",
 
253
                                        tgt));
 
254
                        goto eperm;
 
255
                }
 
256
        }
 
257
 
 
258
        /*
 
259
         * User mounting and unmounting is allowed only if fstab contains one
 
260
         * of the options `user', `users' or `owner' or `group'.
 
261
         *
 
262
         * The option `users' allows arbitrary users to mount and unmount -
 
263
         * this may be a security risk.
 
264
         *
 
265
         * The options `user', `owner' and `group' only allow unmounting by the
 
266
         * user that mounted (visible in mtab).
 
267
         */
 
268
        optstr = mnt_fs_get_user_options(fs);   /* FSTAB mount options! */
 
269
        if (!optstr)
 
270
                goto eperm;
 
271
 
 
272
        if (mnt_optstr_get_flags(optstr, &u_flags,
 
273
                                mnt_get_builtin_optmap(MNT_USERSPACE_MAP)))
 
274
                goto eperm;
 
275
 
 
276
        if (u_flags & MNT_MS_USERS) {
 
277
                DBG(CXT, mnt_debug_h(cxt,
 
278
                        "umount: promiscuous setting ('users') in fstab"));
 
279
                return 0;
 
280
        }
 
281
        /*
 
282
         * Check user=<username> setting from mtab if there is user, owner or
 
283
         * group option in /etc/fstab
 
284
         */
 
285
        if ((u_flags & MNT_MS_USER) || (u_flags & MNT_MS_OWNER) ||
 
286
            (u_flags & MNT_MS_GROUP)) {
 
287
 
 
288
                char *curr_user = NULL;
 
289
                char *mtab_user = NULL;
 
290
                size_t sz;
 
291
 
 
292
                DBG(CXT, mnt_debug_h(cxt,
 
293
                                "umount: checking user=<username> from mtab"));
 
294
 
 
295
                curr_user = mnt_get_username(getuid());
 
296
 
 
297
                if (!curr_user) {
 
298
                        DBG(CXT, mnt_debug_h(cxt, "umount %s: cannot "
 
299
                                "convert %d to username", tgt, getuid()));
 
300
                        goto eperm;
 
301
                }
 
302
 
 
303
                /* get options from mtab */
 
304
                optstr = mnt_fs_get_user_options(cxt->fs);
 
305
                if (optstr && !mnt_optstr_get_option(optstr,
 
306
                                        "user", &mtab_user, &sz) && sz)
 
307
                        ok = !strncmp(curr_user, mtab_user, sz);
 
308
        }
 
309
 
 
310
        if (ok) {
 
311
                DBG(CXT, mnt_debug_h(cxt, "umount %s is allowed", tgt));
 
312
                return 0;
 
313
        }
 
314
eperm:
 
315
        DBG(CXT, mnt_debug_h(cxt, "umount is not allowed for you"));
 
316
        return -EPERM;
 
317
}
 
318
 
 
319
static int exec_helper(struct libmnt_context *cxt)
 
320
{
 
321
        int rc;
 
322
 
 
323
        assert(cxt);
 
324
        assert(cxt->fs);
 
325
        assert(cxt->helper);
 
326
        assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
 
327
        assert(cxt->helper_exec_status == 1);
 
328
 
 
329
        DBG_FLUSH;
 
330
 
 
331
        switch (fork()) {
 
332
        case 0:
 
333
        {
 
334
                const char *args[10], *type;
 
335
                int i = 0;
 
336
 
 
337
                if (setgid(getgid()) < 0)
 
338
                        exit(EXIT_FAILURE);
 
339
 
 
340
                if (setuid(getuid()) < 0)
 
341
                        exit(EXIT_FAILURE);
 
342
 
 
343
                type = mnt_fs_get_fstype(cxt->fs);
 
344
 
 
345
                args[i++] = cxt->helper;                        /* 1 */
 
346
                args[i++] = mnt_fs_get_target(cxt->fs);         /* 2 */
 
347
 
 
348
                if (cxt->flags & MNT_FL_NOMTAB)
 
349
                        args[i++] = "-n";                       /* 3 */
 
350
                if (cxt->flags & MNT_FL_LAZY)
 
351
                        args[i++] = "-l";                       /* 4 */
 
352
                if (cxt->flags & MNT_FL_FORCE)
 
353
                        args[i++] = "-f";                       /* 5 */
 
354
                if (cxt->flags & MNT_FL_VERBOSE)
 
355
                        args[i++] = "-v";                       /* 6 */
 
356
                if (cxt->flags & MNT_FL_RDONLY_UMOUNT)
 
357
                        args[i++] = "-r";                       /* 7 */
 
358
                if (type && !endswith(cxt->helper, type)) {
 
359
                        args[i++] = "-t";                       /* 8 */
 
360
                        args[i++] = (char *) type;      /* 9 */
 
361
                }
 
362
 
 
363
                args[i] = NULL;                                 /* 10 */
 
364
#ifdef CONFIG_LIBMOUNT_DEBUG
 
365
                i = 0;
 
366
                for (i = 0; args[i]; i++)
 
367
                        DBG(CXT, mnt_debug_h(cxt, "argv[%d] = \"%s\"",
 
368
                                                        i, args[i]));
 
369
#endif
 
370
                DBG_FLUSH;
 
371
                execv(cxt->helper, (char * const *) args);
 
372
                exit(EXIT_FAILURE);
 
373
        }
 
374
        default:
 
375
        {
 
376
                int st;
 
377
                wait(&st);
 
378
                cxt->helper_status = WIFEXITED(st) ? WEXITSTATUS(st) : -1;
 
379
 
 
380
                DBG(CXT, mnt_debug_h(cxt, "%s executed [status=%d]",
 
381
                                        cxt->helper, cxt->helper_status));
 
382
                cxt->helper_exec_status = rc = 0;
 
383
                break;
 
384
        }
 
385
 
 
386
        case -1:
 
387
                cxt->helper_exec_status = rc = -errno;
 
388
                DBG(CXT, mnt_debug_h(cxt, "fork() failed"));
 
389
                break;
 
390
        }
 
391
 
 
392
        return rc;
 
393
}
 
394
 
 
395
/*
 
396
 * mnt_context_helper_setopt() backend.
 
397
 *
 
398
 * This function applies umount.<type> command line option (for example parsed
 
399
 * by getopt() or getopt_long()) to @cxt. All unknown options are ignored and
 
400
 * then 1 is returned.
 
401
 *
 
402
 * Returns: negative number on error, 1 if @c is unknown option, 0 on success.
 
403
 */
 
404
int mnt_context_umount_setopt(struct libmnt_context *cxt, int c, char *arg)
 
405
{
 
406
        int rc = -EINVAL;
 
407
 
 
408
        assert(cxt);
 
409
        assert(cxt->action == MNT_ACT_UMOUNT);
 
410
 
 
411
        switch(c) {
 
412
        case 'n':
 
413
                rc = mnt_context_disable_mtab(cxt, TRUE);
 
414
                break;
 
415
        case 'l':
 
416
                rc = mnt_context_enable_lazy(cxt, TRUE);
 
417
                break;
 
418
        case 'f':
 
419
                rc = mnt_context_enable_force(cxt, TRUE);
 
420
                break;
 
421
        case 'v':
 
422
                rc = mnt_context_enable_verbose(cxt, TRUE);
 
423
                break;
 
424
        case 'r':
 
425
                rc = mnt_context_enable_rdonly_umount(cxt, TRUE);
 
426
                break;
 
427
        case 't':
 
428
                if (arg)
 
429
                        rc = mnt_context_set_fstype(cxt, arg);
 
430
                break;
 
431
        default:
 
432
                return 1;
 
433
                break;
 
434
        }
 
435
 
 
436
        return rc;
 
437
}
 
438
 
 
439
/* Check whether the kernel supports UMOUNT_NOFOLLOW flag */
 
440
static int umount_nofollow_support(void)
 
441
{
 
442
        int res = umount2("", UMOUNT_UNUSED);
 
443
        if (res != -1 || errno != EINVAL)
 
444
                return 0;
 
445
 
 
446
        res = umount2("", UMOUNT_NOFOLLOW);
 
447
        if (res != -1 || errno != ENOENT)
 
448
                return 0;
 
449
 
 
450
        return 1;
 
451
}
 
452
 
 
453
static int do_umount(struct libmnt_context *cxt)
 
454
{
 
455
        int rc = 0, flags = 0;
 
456
        const char *src, *target;
 
457
        char *tgtbuf = NULL;
 
458
 
 
459
        assert(cxt);
 
460
        assert(cxt->fs);
 
461
        assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
 
462
        assert(cxt->syscall_status == 1);
 
463
 
 
464
        if (cxt->helper)
 
465
                return exec_helper(cxt);
 
466
 
 
467
        src = mnt_fs_get_srcpath(cxt->fs);
 
468
        target = mnt_fs_get_target(cxt->fs);
 
469
 
 
470
        if (!target)
 
471
                return -EINVAL;
 
472
 
 
473
        if (cxt->flags & MNT_FL_FAKE)
 
474
                return 0;
 
475
 
 
476
        DBG(CXT, mnt_debug_h(cxt, "do umount"));
 
477
 
 
478
        if (cxt->restricted) {
 
479
                /*
 
480
                 * extra paranoa for non-root users
 
481
                 * -- chdir to the parent of the mountpoint and use NOFOLLOW
 
482
                 *    flag to avoid races and symlink attacks.
 
483
                 */
 
484
                if (umount_nofollow_support())
 
485
                        flags |= UMOUNT_NOFOLLOW;
 
486
 
 
487
                rc = mnt_chdir_to_parent(target, &tgtbuf);
 
488
                if (rc)
 
489
                        return rc;
 
490
                target = tgtbuf;
 
491
        }
 
492
 
 
493
        if (cxt->flags & MNT_FL_LAZY)
 
494
                flags |= MNT_DETACH;
 
495
 
 
496
        else if (cxt->flags & MNT_FL_FORCE)
 
497
                flags |= MNT_FORCE;
 
498
 
 
499
        DBG(CXT, mnt_debug_h(cxt, "umount(2) [target='%s', flags=0x%08x]",
 
500
                                target, flags));
 
501
 
 
502
        rc = flags ? umount2(target, flags) : umount(target);
 
503
        if (rc < 0)
 
504
                cxt->syscall_status = -errno;
 
505
 
 
506
        free(tgtbuf);
 
507
 
 
508
        /*
 
509
         * try remount read-only
 
510
         */
 
511
        if (rc < 0 && cxt->syscall_status == -EBUSY &&
 
512
            (cxt->flags & MNT_FL_RDONLY_UMOUNT) && src) {
 
513
 
 
514
                cxt->mountflags |= MS_REMOUNT | MS_RDONLY;
 
515
                cxt->flags &= ~MNT_FL_LOOPDEL;
 
516
                DBG(CXT, mnt_debug_h(cxt,
 
517
                        "umount(2) failed [errno=%d] -- tring remount read-only",
 
518
                        -cxt->syscall_status));
 
519
 
 
520
                rc = mount(src, mnt_fs_get_target(cxt->fs), NULL,
 
521
                            MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
 
522
                if (rc < 0) {
 
523
                        cxt->syscall_status = -errno;
 
524
                        DBG(CXT, mnt_debug_h(cxt,
 
525
                                "read-only re-mount(2) failed [errno=%d]",
 
526
                                -cxt->syscall_status));
 
527
 
 
528
                        return -cxt->syscall_status;
 
529
                }
 
530
                cxt->syscall_status = 0;
 
531
                DBG(CXT, mnt_debug_h(cxt, "read-only re-mount(2) success"));
 
532
                return 0;
 
533
        }
 
534
 
 
535
        if (rc < 0) {
 
536
                DBG(CXT, mnt_debug_h(cxt, "umount(2) failed [errno=%d]",
 
537
                        -cxt->syscall_status));
 
538
                return -cxt->syscall_status;
 
539
        }
 
540
 
 
541
        cxt->syscall_status = 0;
 
542
        DBG(CXT, mnt_debug_h(cxt, "umount(2) success"));
 
543
        return 0;
 
544
}
 
545
 
 
546
/**
 
547
 * mnt_context_prepare_umount:
 
548
 * @cxt: mount context
 
549
 *
 
550
 * Prepare context for umounting, unnecessary for mnt_context_umount().
 
551
 *
 
552
 * Returns: 0 on success, and negative number in case of error.
 
553
 */
 
554
int mnt_context_prepare_umount(struct libmnt_context *cxt)
 
555
{
 
556
        int rc;
 
557
 
 
558
        assert(cxt);
 
559
        assert(cxt->fs);
 
560
        assert(cxt->helper_exec_status == 1);
 
561
        assert(cxt->syscall_status == 1);
 
562
 
 
563
        if (!cxt || !cxt->fs || (cxt->fs->flags & MNT_FS_SWAP))
 
564
                return -EINVAL;
 
565
        if (!mnt_fs_get_source(cxt->fs) && !mnt_fs_get_target(cxt->fs))
 
566
                return -EINVAL;
 
567
        if (cxt->flags & MNT_FL_PREPARED)
 
568
                return 0;
 
569
 
 
570
        free(cxt->helper);      /* be paranoid */
 
571
        cxt->helper = NULL;
 
572
        cxt->action = MNT_ACT_UMOUNT;
 
573
 
 
574
        rc = lookup_umount_fs(cxt);
 
575
        if (!rc)
 
576
                rc = mnt_context_merge_mflags(cxt);
 
577
        if (!rc)
 
578
                rc = evaluate_permissions(cxt);
 
579
        if (!rc)
 
580
               rc = mnt_context_prepare_target(cxt);
 
581
 
 
582
        if (!rc && !cxt->helper) {
 
583
 
 
584
                if (cxt->user_mountflags & MNT_MS_HELPER)
 
585
                        /* on helper= mount option based helper */
 
586
                        rc = prepare_helper_from_options(cxt, "helper");
 
587
 
 
588
                if (!rc && !cxt->helper)
 
589
                        /* on fstype based helper */
 
590
                        rc = mnt_context_prepare_helper(cxt, "umount", NULL);
 
591
        }
 
592
 
 
593
/* TODO
 
594
        if ((cxt->flags & MNT_FL_LOOPDEL) &&
 
595
            (!mnt_is_loopdev(src) || mnt_loopdev_is_autoclear(src)))
 
596
                cxt->flags &= ~MNT_FL_LOOPDEL;
 
597
*/
 
598
        if (rc) {
 
599
                DBG(CXT, mnt_debug_h(cxt, "umount: preparing failed"));
 
600
                return rc;
 
601
        }
 
602
        cxt->flags |= MNT_FL_PREPARED;
 
603
        return rc;
 
604
}
 
605
 
 
606
/**
 
607
 * mnt_context_do_umount:
 
608
 * @cxt: mount context
 
609
 *
 
610
 * Umount filesystem by umount(2) or fork()+exec(/sbin/umount.type).
 
611
 * Unnecessary for mnt_context_umount().
 
612
 *
 
613
 * See also mnt_context_disable_helpers().
 
614
 *
 
615
 * WARNING: non-zero return code does not mean that umount(2) syscall or
 
616
 *          umount.type helper wasn't sucessfully called.
 
617
 *
 
618
 *          Check mnt_context_get_status() after error!
 
619
*
 
620
 * Returns: 0 on success;
 
621
 *         >0 in case of umount(2) error (returns syscall errno),
 
622
 *         <0 in case of other errors.
 
623
 */
 
624
int mnt_context_do_umount(struct libmnt_context *cxt)
 
625
{
 
626
        int rc;
 
627
 
 
628
        assert(cxt);
 
629
        assert(cxt->fs);
 
630
        assert(cxt->helper_exec_status == 1);
 
631
        assert(cxt->syscall_status == 1);
 
632
        assert((cxt->flags & MNT_FL_PREPARED));
 
633
        assert((cxt->action == MNT_ACT_UMOUNT));
 
634
        assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
 
635
 
 
636
        rc = do_umount(cxt);
 
637
        if (rc)
 
638
                return rc;
 
639
/* TODO
 
640
        if (cxt->flags & MNT_FL_LOOPDEL)
 
641
                rc = mnt_loopdev_clean(mnt_fs_get_source(cxt->fs));
 
642
*/
 
643
        if (cxt->flags & MNT_FL_NOMTAB)
 
644
                return rc;
 
645
 
 
646
        if ((cxt->flags & MNT_FL_RDONLY_UMOUNT) &&
 
647
            (cxt->mountflags & (MS_RDONLY | MS_REMOUNT))) {
 
648
                /*
 
649
                 * fix options, remount --> read-only mount
 
650
                 */
 
651
                const char *o = mnt_fs_get_options(cxt->fs);
 
652
                char *n = o ? strdup(o) : NULL;
 
653
 
 
654
                DBG(CXT, mnt_debug_h(cxt, "fix remount-on-umount update"));
 
655
 
 
656
                if (n)
 
657
                        mnt_optstr_remove_option(&n, "rw");
 
658
                rc = mnt_optstr_prepend_option(&n, "ro", NULL);
 
659
                if (!rc)
 
660
                        rc = mnt_fs_set_options(cxt->fs, n);
 
661
 
 
662
                /* use "remount" instead of "umount" in /etc/mtab */
 
663
                if (!rc && cxt->update && cxt->mtab_writable)
 
664
                        rc = mnt_update_set_fs(cxt->update,
 
665
                                               cxt->mountflags, NULL, cxt->fs);
 
666
        }
 
667
 
 
668
        return rc;
 
669
}
 
670
 
 
671
/**
 
672
 * mnt_context_finalize_umount:
 
673
 * @cxt: context
 
674
 *
 
675
 * Mtab update, etc. Unnecessary for mnt_context_umount(), but should be called
 
676
 * after mnt_context_do_umount(). See also mnt_context_set_syscall_status().
 
677
 *
 
678
 * Returns: negative number on error, 0 on success.
 
679
 */
 
680
int mnt_context_finalize_umount(struct libmnt_context *cxt)
 
681
{
 
682
        int rc;
 
683
 
 
684
        assert(cxt);
 
685
        assert(cxt->fs);
 
686
        assert((cxt->flags & MNT_FL_PREPARED));
 
687
        assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
 
688
 
 
689
        rc = mnt_context_prepare_update(cxt);
 
690
        if (!rc)
 
691
                rc = mnt_context_update_tabs(cxt);;
 
692
        return rc;
 
693
}
 
694
 
 
695
 
 
696
/**
 
697
 * mnt_context_umount:
 
698
 * @cxt: umount context
 
699
 *
 
700
 * High-level, umounts filesystem by umount(2) or fork()+exec(/sbin/umount.type).
 
701
 *
 
702
 * This is similar to:
 
703
 *
 
704
 *      mnt_context_prepare_umount(cxt);
 
705
 *      mnt_context_do_umount(cxt);
 
706
 *      mnt_context_finalize_umount(cxt);
 
707
 *
 
708
 * See also mnt_context_disable_helpers().
 
709
 *
 
710
 * WARNING: non-zero return code does not mean that umount(2) syscall or
 
711
 *          umount.type helper wasn't sucessfully called.
 
712
 *
 
713
 *          Check mnt_context_get_status() after error!
 
714
 *
 
715
 * Returns: 0 on success;
 
716
 *         >0 in case of umount(2) error (returns syscall errno),
 
717
 *         <0 in case of other errors.
 
718
 */
 
719
int mnt_context_umount(struct libmnt_context *cxt)
 
720
{
 
721
        int rc;
 
722
 
 
723
        assert(cxt);
 
724
        assert(cxt->fs);
 
725
        assert(cxt->helper_exec_status == 1);
 
726
        assert(cxt->syscall_status == 1);
 
727
 
 
728
        rc = mnt_context_prepare_umount(cxt);
 
729
        if (!rc)
 
730
                rc = mnt_context_prepare_update(cxt);
 
731
        if (!rc)
 
732
                rc = mnt_context_do_umount(cxt);
 
733
        if (!rc)
 
734
                rc = mnt_context_update_tabs(cxt);
 
735
        return rc;
 
736
}