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

« back to all changes in this revision

Viewing changes to shlibs/mount/src/context.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Langasek
  • Date: 2011-06-20 22:31:50 UTC
  • mfrom: (1.6.3 upstream) (4.5.1 sid)
  • Revision ID: james.westby@ubuntu.com-20110620223150-lz8wrv0946ihcz3z
Tags: 2.19.1-2ubuntu1
* Merge from Debian unstable, remaining changes:
  - Build for multiarch.
  - Add pre-depends on multiarch-support.
  - configure.ac: don't try to be clever about extracting a path name from
    $libdir to append to /usr in a way that's not overridable; instead,
    reuse the built-in configurable libexecdir.
  - Fix up the .pc.in files to know about libexecdir, so our substitutions
    don't leave us with unusable pkg-config files.
  - Install custom blkid.conf to use /dev/.blkid.tab since we don't
    expect device names to survive a reboot
  - Mention mountall(8) in fstab(5) manpages, along with its special
    options.
  - Since upstart is required in Ubuntu, the hwclock.sh init script is not
    called on startup and the hwclockfirst.sh init script is removed.
  - Drop depends on initscripts for the above.
  - Replace hwclock udev rule with an Upstart job.
  - For the case where mount is called with a directory to mount, look
    that directory up in mountall's /lib/init/fstab if we couldn't find
    it mentioned anywhere else.  This means "mount /proc", "mount /sys",
    etc. work.
  - mount.8 points to the cifs-utils package, not the obsolete smbfs one. 
* Dropped changes:
  - mount.preinst: lsb_release has been fixed in lucid and above to be
    usable without configuration, so we don't have to diverge from Debian
    here anymore.
* Changes merged upstream:
  - sfdisk support for '+' with '-N'
  - mount/umount.c: fix a segfault on umount with empty mtab entry
  - Fix arbitrary unmount with fuse security issue

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
 
10
 * @title: Mount/umount context
 
11
 * @short_description: high-level API to mount/umount devices.
 
12
 *
 
13
 * <informalexample>
 
14
 *   <programlisting>
 
15
 *      struct libmnt_context *cxt = mnt_new_context();
 
16
 *
 
17
 *      mnt_context_set_options(cxt, "aaa,bbb,ccc=CCC");
 
18
 *      mnt_context_set_mflags(cxt, MS_NOATIME|MS_NOEXEC);
 
19
 *      mnt_context_set_target(cxt, "/mnt/foo");
 
20
 *
 
21
 *      if (!mnt_context_mount(cxt))
 
22
 *              printf("successfully mounted\n");
 
23
 *      mnt_free_context(cxt);
 
24
 *
 
25
 *   </programlisting>
 
26
 * </informalexample>
 
27
 *
 
28
 * This code is similar to:
 
29
 *
 
30
 *   mount -o aaa,bbb,ccc=CCC,noatime,noexec /mnt/foo
 
31
 *
 
32
 */
 
33
 
 
34
#include <stdio.h>
 
35
#include <stdlib.h>
 
36
#include <sys/types.h>
 
37
#include <sys/stat.h>
 
38
#include <unistd.h>
 
39
#include <string.h>
 
40
#include <errno.h>
 
41
 
 
42
#include "c.h"
 
43
#include "mountP.h"
 
44
 
 
45
/**
 
46
 * mnt_new_context:
 
47
 *
 
48
 * Returns: newly allocated mount context
 
49
 */
 
50
struct libmnt_context *mnt_new_context(void)
 
51
{
 
52
        struct libmnt_context *cxt;
 
53
        uid_t ruid, euid;
 
54
 
 
55
        cxt = calloc(1, sizeof(*cxt));
 
56
        if (!cxt)
 
57
                return NULL;
 
58
 
 
59
        ruid = getuid();
 
60
        euid = geteuid();
 
61
 
 
62
        cxt->syscall_status = 1;        /* not called yet */
 
63
        cxt->helper_exec_status = 1;
 
64
 
 
65
        /* if we're really root and aren't running setuid */
 
66
        cxt->restricted = (uid_t) 0 == ruid && ruid == euid ? 0 : 1;
 
67
 
 
68
        DBG(CXT, mnt_debug_h(cxt, "allocate %s",
 
69
                                cxt->restricted ? "[RESTRICTED]" : ""));
 
70
 
 
71
        mnt_has_regular_mtab(&cxt->mtab_path, &cxt->mtab_writable);
 
72
 
 
73
        if (!cxt->mtab_writable)
 
74
                /* use /run/mount/utab if /etc/mtab is useless */
 
75
                mnt_has_regular_utab(&cxt->utab_path, &cxt->utab_writable);
 
76
 
 
77
        return cxt;
 
78
}
 
79
 
 
80
/**
 
81
 * mnt_free_context:
 
82
 * @cxt: mount context
 
83
 *
 
84
 * Deallocates context struct.
 
85
 */
 
86
void mnt_free_context(struct libmnt_context *cxt)
 
87
{
 
88
        if (!cxt)
 
89
                return;
 
90
 
 
91
        mnt_reset_context(cxt);
 
92
 
 
93
        DBG(CXT, mnt_debug_h(cxt, "free"));
 
94
 
 
95
        free(cxt->fstype_pattern);
 
96
        free(cxt->optstr_pattern);
 
97
 
 
98
        if (!(cxt->flags & MNT_FL_EXTERN_FSTAB))
 
99
                mnt_free_table(cxt->fstab);
 
100
        if (!(cxt->flags & MNT_FL_EXTERN_CACHE))
 
101
                mnt_free_cache(cxt->cache);
 
102
 
 
103
        mnt_free_lock(cxt->lock);
 
104
        mnt_free_update(cxt->update);
 
105
 
 
106
        free(cxt);
 
107
}
 
108
 
 
109
/**
 
110
 * mnt_reset_context:
 
111
 * @cxt: mount context
 
112
 *
 
113
 * Resets all information in the context that are directly related to
 
114
 * the latest mount (spec, source, target, mount options, ....)
 
115
 *
 
116
 * The match patters, cached fstab, cached canonicalized paths and tags and
 
117
 * [e]uid are not reseted. You have to use
 
118
 *
 
119
 *      mnt_context_set_fstab(cxt, NULL);
 
120
 *      mnt_context_set_cache(cxt, NULL);
 
121
 *      mnt_context_set_fstype_pattern(cxt, NULL);
 
122
 *      mnt_context_set_options_pattern(cxt, NULL);
 
123
 *
 
124
 *
 
125
 * to reset these stuff.
 
126
 *
 
127
 * Returns: 0 on success, negative number in case of error.
 
128
 */
 
129
int mnt_reset_context(struct libmnt_context *cxt)
 
130
{
 
131
        int fl;
 
132
 
 
133
        if (!cxt)
 
134
                return -EINVAL;
 
135
 
 
136
        fl = cxt->flags;
 
137
 
 
138
        if (!(cxt->flags & MNT_FL_EXTERN_FS))
 
139
                mnt_free_fs(cxt->fs);
 
140
 
 
141
        mnt_free_table(cxt->mtab);
 
142
 
 
143
        free(cxt->helper);
 
144
        free(cxt->orig_user);
 
145
 
 
146
        cxt->fs = NULL;
 
147
        cxt->mtab = NULL;
 
148
        cxt->ambi = 0;
 
149
        cxt->helper = NULL;
 
150
        cxt->orig_user = NULL;
 
151
        cxt->mountflags = 0;
 
152
        cxt->user_mountflags = 0;
 
153
        cxt->mountdata = NULL;
 
154
        cxt->flags = MNT_FL_DEFAULT;
 
155
        cxt->syscall_status = 1;
 
156
        cxt->helper_exec_status = 1;
 
157
        cxt->helper_status = 0;
 
158
 
 
159
        /* restore non-resetable flags */
 
160
        cxt->flags |= (fl & MNT_FL_EXTERN_FSTAB);
 
161
        cxt->flags |= (fl & MNT_FL_EXTERN_CACHE);
 
162
 
 
163
        return 0;
 
164
}
 
165
 
 
166
static int set_flag(struct libmnt_context *cxt, int flag, int enable)
 
167
{
 
168
        if (!cxt)
 
169
                return -EINVAL;
 
170
        if (enable)
 
171
                cxt->flags |= flag;
 
172
        else
 
173
                cxt->flags &= ~flag;
 
174
        return 0;
 
175
}
 
176
 
 
177
/**
 
178
 * mnt_context_is_restricted:
 
179
 * @cxt: mount context
 
180
 *
 
181
 * Returns: 0 for unrestricted mount (user is root), or 1 for non-root mounts
 
182
 */
 
183
int mnt_context_is_restricted(struct libmnt_context *cxt)
 
184
{
 
185
        assert(cxt);
 
186
        return cxt->restricted;
 
187
}
 
188
 
 
189
/**
 
190
 * mnt_context_set_optsmode
 
191
 * @cxt: mount context
 
192
 * @mode: mask, see MNT_OMASK_* flags in libmount mount.h
 
193
 *
 
194
 * Controls how to use mount options from fstab/mtab.
 
195
 *
 
196
 * Returns: 0 on success, negative number in case of error.
 
197
 */
 
198
int mnt_context_set_optsmode(struct libmnt_context *cxt, int mode)
 
199
{
 
200
        if (!cxt)
 
201
                return -EINVAL;
 
202
        cxt->optsmode = mode;
 
203
        return 0;
 
204
}
 
205
 
 
206
/**
 
207
 * mnt_context_get_optsmode
 
208
 * @cxt: mount context
 
209
 *
 
210
 * Returns: MNT_OMASK_* mask or zero.
 
211
 */
 
212
 
 
213
int mnt_context_get_optsmode(struct libmnt_context *cxt)
 
214
{
 
215
        return cxt ? cxt->optsmode : 0;
 
216
}
 
217
 
 
218
/**
 
219
 * mnt_context_disable_canonicalize:
 
220
 * @cxt: mount context
 
221
 * @disable: TRUE or FALSE
 
222
 *
 
223
 * Enable/disable paths canonicalization and tags evaluation. The libmount context
 
224
 * canonicalies paths when search in fstab and when prepare source and target paths
 
225
 * for mount(2) syscall.
 
226
 *
 
227
 * This fuction has effect to the private fstab instance only (see
 
228
 * mnt_context_set_fstab()). If you want to use an external fstab then you need
 
229
 * manage your private struct libmnt_cache (see mnt_table_set_cache(fstab, NULL).
 
230
 *
 
231
 * Returns: 0 on success, negative number in case of error.
 
232
 */
 
233
int mnt_context_disable_canonicalize(struct libmnt_context *cxt, int disable)
 
234
{
 
235
        return set_flag(cxt, MNT_FL_NOCANONICALIZE, disable);
 
236
}
 
237
 
 
238
/**
 
239
 * mnt_context_enable_lazy:
 
240
 * @cxt: mount context
 
241
 * @enable: TRUE or FALSE
 
242
 *
 
243
 * Enable/disable lazy umount (see umount(8) man page, option -l).
 
244
 *
 
245
 * Returns: 0 on success, negative number in case of error.
 
246
 */
 
247
int mnt_context_enable_lazy(struct libmnt_context *cxt, int enable)
 
248
{
 
249
        return set_flag(cxt, MNT_FL_LAZY, enable);
 
250
}
 
251
 
 
252
/**
 
253
 * mnt_context_is_lazy:
 
254
 * @cxt: mount context
 
255
 *
 
256
 * Returns: 1 if lazy umount is enabled or 0
 
257
 */
 
258
int mnt_context_is_lazy(struct libmnt_context *cxt)
 
259
{
 
260
        return cxt && (cxt->flags & MNT_FL_LAZY) ? 1 : 0;
 
261
}
 
262
 
 
263
 
 
264
/**
 
265
 * mnt_context_enable_rdonly_umount:
 
266
 * @cxt: mount context
 
267
 * @enable: TRUE or FALSE
 
268
 *
 
269
 * Enable/disable read-only remount on failed umount(2)
 
270
 * (see umount(8) man page, option -r).
 
271
 *
 
272
 * Returns: 0 on success, negative number in case of error.
 
273
 */
 
274
int mnt_context_enable_rdonly_umount(struct libmnt_context *cxt, int enable)
 
275
{
 
276
        return set_flag(cxt, MNT_FL_RDONLY_UMOUNT, enable);
 
277
}
 
278
 
 
279
/**
 
280
 * mnt_context_is_rdonly_umount
 
281
 * @cxt: mount context
 
282
 *
 
283
 * See also mnt_context_enable_rdonly_umount() and see umount(8) man page,
 
284
 * option -r.
 
285
 *
 
286
 * Returns: 1 if read-only remount failed umount(2) is enables or 0
 
287
 */
 
288
int mnt_context_is_rdonly_umount(struct libmnt_context *cxt)
 
289
{
 
290
        return cxt && (cxt->flags & MNT_FL_RDONLY_UMOUNT) ? 1 : 0;
 
291
}
 
292
 
 
293
/**
 
294
 * mnt_context_disable_helpers:
 
295
 * @cxt: mount context
 
296
 * @disable: TRUE or FALSE
 
297
 *
 
298
 * Enable/disable /sbin/[u]mount.* helpers (see mount(8) man page, option -i).
 
299
 *
 
300
 * Returns: 0 on success, negative number in case of error.
 
301
 */
 
302
int mnt_context_disable_helpers(struct libmnt_context *cxt, int disable)
 
303
{
 
304
        return set_flag(cxt, MNT_FL_NOHELPERS, disable);
 
305
}
 
306
 
 
307
/**
 
308
 * mnt_context_enable_sloppy:
 
309
 * @cxt: mount context
 
310
 * @enable: TRUE or FALSE
 
311
 *
 
312
 * Set/unset sloppy mounting (see mount(8) man page, option -s).
 
313
 *
 
314
 * Returns: 0 on success, negative number in case of error.
 
315
 */
 
316
int mnt_context_enable_sloppy(struct libmnt_context *cxt, int enable)
 
317
{
 
318
        return set_flag(cxt, MNT_FL_SLOPPY, enable);
 
319
}
 
320
 
 
321
/**
 
322
 * mnt_context_is_sloppy:
 
323
 * @cxt: mount context
 
324
 *
 
325
 * Returns: 1 if sloppy flag is enabled or 0
 
326
 */
 
327
int mnt_context_is_sloppy(struct libmnt_context *cxt)
 
328
{
 
329
        return cxt && (cxt->flags & MNT_FL_SLOPPY) ? 1 : 0;
 
330
}
 
331
 
 
332
/**
 
333
 * mnt_context_enable_fake:
 
334
 * @cxt: mount context
 
335
 * @enable: TRUE or FALSE
 
336
 *
 
337
 * Enable/disable fake mounting (see mount(8) man page, option -f).
 
338
 *
 
339
 * Returns: 0 on success, negative number in case of error.
 
340
 */
 
341
int mnt_context_enable_fake(struct libmnt_context *cxt, int enable)
 
342
{
 
343
        return set_flag(cxt, MNT_FL_FAKE, enable);
 
344
}
 
345
 
 
346
/**
 
347
 * mnt_context_is_fake:
 
348
 * @cxt: mount context
 
349
 *
 
350
 * Returns: 1 if fake flag is enabled or 0
 
351
 */
 
352
int mnt_context_is_fake(struct libmnt_context *cxt)
 
353
{
 
354
        return cxt && (cxt->flags & MNT_FL_FAKE) ? 1 : 0;
 
355
}
 
356
 
 
357
/**
 
358
 * mnt_context_disable_mtab:
 
359
 * @cxt: mount context
 
360
 * @disable: TRUE or FALSE
 
361
 *
 
362
 * Disable/enable mtab update (see mount(8) man page, option -n).
 
363
 *
 
364
 * Returns: 0 on success, negative number in case of error.
 
365
 */
 
366
int mnt_context_disable_mtab(struct libmnt_context *cxt, int disable)
 
367
{
 
368
        return set_flag(cxt, MNT_FL_NOMTAB, disable);
 
369
}
 
370
 
 
371
/**
 
372
 * mnt_context_is_nomtab
 
373
 * @cxt: mount context
 
374
 *
 
375
 * Returns: 1 if no-mtab is enabled or 0
 
376
 */
 
377
int mnt_context_is_nomtab(struct libmnt_context *cxt)
 
378
{
 
379
        return cxt && (cxt->flags & MNT_FL_NOMTAB) ? 1 : 0;
 
380
}
 
381
 
 
382
/**
 
383
 * mnt_context_enable_force:
 
384
 * @cxt: mount context
 
385
 * @enable: TRUE or FALSE
 
386
 *
 
387
 * Enable/disable force umounting (see umount(8) man page, option -f).
 
388
 *
 
389
 * Returns: 0 on success, negative number in case of error.
 
390
 */
 
391
int mnt_context_enable_force(struct libmnt_context *cxt, int enable)
 
392
{
 
393
        return set_flag(cxt, MNT_FL_FORCE, enable);
 
394
}
 
395
 
 
396
/**
 
397
 * mnt_context_is_force
 
398
 * @cxt: mount context
 
399
 *
 
400
 * Returns: 1 if force umounting flag is enabled or 0
 
401
 */
 
402
int mnt_context_is_force(struct libmnt_context *cxt)
 
403
{
 
404
        return cxt && (cxt->flags & MNT_FL_FORCE) ? 1 : 0;
 
405
}
 
406
 
 
407
/**
 
408
 * mnt_context_enable_verbose:
 
409
 * @cxt: mount context
 
410
 * @enable: TRUE or FALSE
 
411
 *
 
412
 * Enable/disable verbose output (TODO: not implemented yet)
 
413
 *
 
414
 * Returns: 0 on success, negative number in case of error.
 
415
 */
 
416
int mnt_context_enable_verbose(struct libmnt_context *cxt, int enable)
 
417
{
 
418
        return set_flag(cxt, MNT_FL_VERBOSE, enable);
 
419
}
 
420
 
 
421
/**
 
422
 * mnt_context_is_verbose
 
423
 * @cxt: mount context
 
424
 *
 
425
 * Returns: 1 if verbose flag is enabled or 0
 
426
 */
 
427
int mnt_context_is_verbose(struct libmnt_context *cxt)
 
428
{
 
429
        return cxt && (cxt->flags & MNT_FL_VERBOSE) ? 1 : 0;
 
430
}
 
431
 
 
432
/**
 
433
 * mnt_context_enable_loopdel:
 
434
 * @cxt: mount context
 
435
 * @enable: TRUE or FALSE
 
436
 *
 
437
 * Enable/disable loop delete (destroy) after umount (see umount(8), option -d)
 
438
 *
 
439
 * Returns: 0 on success, negative number in case of error.
 
440
 */
 
441
int mnt_context_enable_loopdel(struct libmnt_context *cxt, int enable)
 
442
{
 
443
        return set_flag(cxt, MNT_FL_LOOPDEL, enable);
 
444
}
 
445
 
 
446
/**
 
447
 * mnt_context_set_fs:
 
448
 * @cxt: mount context
 
449
 * @fs: filesystem description
 
450
 *
 
451
 * The mount context uses private @fs by default. This function allows to
 
452
 * overwrite the private @fs with an external instance. Note that the external
 
453
 * @fs instance is not deallocated by mnt_free_context() or mnt_reset_context().
 
454
 *
 
455
 * The @fs will be modified by mnt_context_set_{source,target,options,fstype}
 
456
 * functions, If the @fs is NULL then all current FS specific setting (source,
 
457
 * target, etc., exclude spec) is reseted.
 
458
 *
 
459
 * Returns: 0 on success, negative number in case of error.
 
460
 */
 
461
int mnt_context_set_fs(struct libmnt_context *cxt, struct libmnt_fs *fs)
 
462
{
 
463
        if (!cxt)
 
464
                return -EINVAL;
 
465
        if (!(cxt->flags & MNT_FL_EXTERN_FS))
 
466
                mnt_free_fs(cxt->fs);
 
467
 
 
468
        set_flag(cxt, MNT_FL_EXTERN_FS, fs != NULL);
 
469
        cxt->fs = fs;
 
470
        return 0;
 
471
}
 
472
 
 
473
/**
 
474
 * mnt_context_get_fs:
 
475
 * @cxt: mount context
 
476
 *
 
477
 * The FS contains the basic description of mountpoint, fs type and so on.
 
478
 * Note that the FS is modified by mnt_context_set_{source,target,options,fstype}
 
479
 * functions.
 
480
 *
 
481
 * Returns: pointer to FS description or NULL in case of calloc() errrr.
 
482
 */
 
483
struct libmnt_fs *mnt_context_get_fs(struct libmnt_context *cxt)
 
484
{
 
485
        if (!cxt)
 
486
                return NULL;
 
487
        if (!cxt->fs) {
 
488
                cxt->fs = mnt_new_fs();
 
489
                cxt->flags &= ~MNT_FL_EXTERN_FS;
 
490
        }
 
491
        return cxt->fs;
 
492
}
 
493
 
 
494
/**
 
495
 * mnt_context_set_source:
 
496
 * @cxt: mount context
 
497
 * @source: mount source (device, directory, UUID, LABEL, ...)
 
498
 *
 
499
 * Returns: 0 on success, negative number in case of error.
 
500
 */
 
501
int mnt_context_set_source(struct libmnt_context *cxt, const char *source)
 
502
{
 
503
        return mnt_fs_set_source(mnt_context_get_fs(cxt), source);
 
504
}
 
505
 
 
506
/**
 
507
 * mnt_context_get_source:
 
508
 * @cxt: mount context
 
509
 *
 
510
 * Returns: returns pointer or NULL in case of error pr if not set.
 
511
 */
 
512
const char *mnt_context_get_source(struct libmnt_context *cxt)
 
513
{
 
514
        return mnt_fs_get_source(mnt_context_get_fs(cxt));
 
515
}
 
516
 
 
517
/**
 
518
 * mnt_context_set_target:
 
519
 * @cxt: mount context
 
520
 * @target: mountpoint
 
521
 *
 
522
 * Returns: 0 on success, negative number in case of error.
 
523
 */
 
524
int mnt_context_set_target(struct libmnt_context *cxt, const char *target)
 
525
{
 
526
        return mnt_fs_set_target(mnt_context_get_fs(cxt), target);
 
527
}
 
528
 
 
529
/**
 
530
 * mnt_context_get_target:
 
531
 * @cxt: mount context
 
532
 *
 
533
 * Returns: returns pointer or NULL in case of error pr if not set.
 
534
 */
 
535
const char *mnt_context_get_target(struct libmnt_context *cxt)
 
536
{
 
537
        return mnt_fs_get_target(mnt_context_get_fs(cxt));
 
538
}
 
539
 
 
540
/**
 
541
 * mnt_context_set_fstype:
 
542
 * @cxt: mount context
 
543
 * @fstype: filesystem type
 
544
 *
 
545
 * Note that the @fstype has to be the real FS type. For comma-separated list of
 
546
 * filesystems or for "nofs" notation use mnt_context_set_fstype_pattern().
 
547
 *
 
548
 * Returns: 0 on success, negative number in case of error.
 
549
 */
 
550
int mnt_context_set_fstype(struct libmnt_context *cxt, const char *fstype)
 
551
{
 
552
        if (fstype && strchr(fstype, ','))
 
553
                return -EINVAL;
 
554
        return mnt_fs_set_fstype(mnt_context_get_fs(cxt), fstype);
 
555
}
 
556
 
 
557
/**
 
558
 * mnt_context_get_fstype:
 
559
 * @cxt: mount context
 
560
 *
 
561
 * Returns: returns pointer or NULL in case of error pr if not set.
 
562
 */
 
563
const char *mnt_context_get_fstype(struct libmnt_context *cxt)
 
564
{
 
565
        return mnt_fs_get_fstype(mnt_context_get_fs(cxt));
 
566
}
 
567
 
 
568
/**
 
569
 * mnt_context_set_options:
 
570
 * @cxt: mount context
 
571
 * @optstr: comma delimited mount options
 
572
 *
 
573
 * Returns: 0 on success, negative number in case of error.
 
574
 */
 
575
int mnt_context_set_options(struct libmnt_context *cxt, const char *optstr)
 
576
{
 
577
        return mnt_fs_set_options(mnt_context_get_fs(cxt), optstr);
 
578
}
 
579
 
 
580
/**
 
581
 * mnt_context_append_options:
 
582
 * @cxt: mount context
 
583
 * @optstr: comma delimited mount options
 
584
 *
 
585
 * Returns: 0 on success, negative number in case of error.
 
586
 */
 
587
int mnt_context_append_options(struct libmnt_context *cxt, const char *optstr)
 
588
{
 
589
        return mnt_fs_append_options(mnt_context_get_fs(cxt), optstr);
 
590
}
 
591
 
 
592
/**
 
593
 * mnt_context_set_fstype_pattern:
 
594
 * @cxt: mount context
 
595
 * @pattern: FS name pattern (or NULL to reset the current setting)
 
596
 *
 
597
 * See mount(8), option -t.
 
598
 *
 
599
 * Returns: 0 on success, negative number in case of error.
 
600
 */
 
601
int mnt_context_set_fstype_pattern(struct libmnt_context *cxt, const char *pattern)
 
602
{
 
603
        char *p = NULL;
 
604
 
 
605
        if (!cxt)
 
606
                return -EINVAL;
 
607
        if (pattern) {
 
608
                p = strdup(pattern);
 
609
                if (!p)
 
610
                        return -ENOMEM;
 
611
        }
 
612
        free(cxt->fstype_pattern);
 
613
        cxt->fstype_pattern = p;
 
614
        return 0;
 
615
}
 
616
 
 
617
/**
 
618
 * mnt_context_set_options_pattern:
 
619
 * @cxt: mount context
 
620
 * @pattern: options pattern (or NULL to reset the current setting)
 
621
 *
 
622
 * See mount(8), option -O.
 
623
 *
 
624
 * Returns: 0 on success, negative number in case of error.
 
625
 */
 
626
int mnt_context_set_options_pattern(struct libmnt_context *cxt, const char *pattern)
 
627
{
 
628
        char *p = NULL;
 
629
 
 
630
        if (!cxt)
 
631
                return -EINVAL;
 
632
        if (pattern) {
 
633
                p = strdup(pattern);
 
634
                if (!p)
 
635
                        return -ENOMEM;
 
636
        }
 
637
        free(cxt->optstr_pattern);
 
638
        cxt->optstr_pattern = p;
 
639
        return 0;
 
640
}
 
641
 
 
642
/**
 
643
 * mnt_context_set_fstab:
 
644
 * @cxt: mount context
 
645
 * @tb: fstab
 
646
 *
 
647
 * The mount context reads /etc/fstab to the the private struct libmnt_table by default.
 
648
 * This function allows to overwrite the private fstab with an external
 
649
 * instance. Note that the external instance is not deallocated by mnt_free_context().
 
650
 *
 
651
 * The fstab is used read-only and is not modified, it should be possible to
 
652
 * share the fstab between more mount contexts (TODO: tests it.)
 
653
 *
 
654
 * If the @tb argument is NULL then the current private fstab instance is
 
655
 * reseted.
 
656
 *
 
657
 * Returns: 0 on success, negative number in case of error.
 
658
 */
 
659
int mnt_context_set_fstab(struct libmnt_context *cxt, struct libmnt_table *tb)
 
660
{
 
661
        if (!cxt)
 
662
                return -EINVAL;
 
663
        if (!(cxt->flags & MNT_FL_EXTERN_FSTAB))
 
664
                mnt_free_table(cxt->fstab);
 
665
 
 
666
        set_flag(cxt, MNT_FL_EXTERN_FSTAB, tb != NULL);
 
667
        cxt->fstab = tb;
 
668
        return 0;
 
669
}
 
670
 
 
671
/**
 
672
 * mnt_context_get_fstab:
 
673
 * @cxt: mount context
 
674
 * @tb: returns fstab
 
675
 *
 
676
 * See also mnt_table_parse_fstab() for more details about fstab.
 
677
 *
 
678
 * Returns: 0 on success, negative number in case of error.
 
679
 */
 
680
int mnt_context_get_fstab(struct libmnt_context *cxt, struct libmnt_table **tb)
 
681
{
 
682
        struct libmnt_cache *cache;
 
683
 
 
684
        if (!cxt)
 
685
                return -EINVAL;
 
686
 
 
687
        if (!cxt->fstab) {
 
688
                int rc;
 
689
 
 
690
                cxt->fstab = mnt_new_table();
 
691
                if (!cxt->fstab)
 
692
                        return -ENOMEM;
 
693
                cxt->flags &= ~MNT_FL_EXTERN_FSTAB;
 
694
                rc = mnt_table_parse_fstab(cxt->fstab, NULL);
 
695
                if (rc)
 
696
                        return rc;
 
697
        }
 
698
 
 
699
        cache = mnt_context_get_cache(cxt);
 
700
 
 
701
        /*  never touch an external fstab */
 
702
        if (!(cxt->flags & MNT_FL_EXTERN_FSTAB))
 
703
                mnt_table_set_cache(cxt->fstab, cache);
 
704
 
 
705
        if (tb)
 
706
                *tb = cxt->fstab;
 
707
        return 0;
 
708
}
 
709
 
 
710
/**
 
711
 * mnt_context_get_mtab:
 
712
 * @cxt: mount context
 
713
 * @tb: returns mtab
 
714
 *
 
715
 * See also mnt_table_parse_mtab() for more details about mtab/mountinfo.
 
716
 *
 
717
 * Returns: 0 on success, negative number in case of error.
 
718
 */
 
719
int mnt_context_get_mtab(struct libmnt_context *cxt, struct libmnt_table **tb)
 
720
{
 
721
        struct libmnt_cache *cache;
 
722
 
 
723
        if (!cxt)
 
724
                return -EINVAL;
 
725
 
 
726
        if (!cxt->mtab) {
 
727
                int rc;
 
728
 
 
729
                cxt->mtab = mnt_new_table();
 
730
                if (!cxt->mtab)
 
731
                        return -ENOMEM;
 
732
                rc = mnt_table_parse_mtab(cxt->mtab, cxt->mtab_path);
 
733
                if (rc)
 
734
                        return rc;
 
735
        }
 
736
 
 
737
        cache = mnt_context_get_cache(cxt);
 
738
        mnt_table_set_cache(cxt->mtab, cache);
 
739
 
 
740
        if (tb)
 
741
                *tb = cxt->mtab;
 
742
        return 0;
 
743
}
 
744
 
 
745
/**
 
746
 * mnt_context_set_cache:
 
747
 * @cxt: mount context
 
748
 * @cache: cache instance or nULL
 
749
 *
 
750
 * The mount context maintains a private struct libmnt_cache by default.  This function
 
751
 * allows to overwrite the private cache with an external instance. Note that
 
752
 * the external instance is not deallocated by mnt_free_context().
 
753
 *
 
754
 * If the @cache argument is NULL then the current private cache instance is
 
755
 * reseted.
 
756
 *
 
757
 * Returns: 0 on success, negative number in case of error.
 
758
 */
 
759
int mnt_context_set_cache(struct libmnt_context *cxt, struct libmnt_cache *cache)
 
760
{
 
761
        if (!cxt)
 
762
                return -EINVAL;
 
763
        if (!(cxt->flags & MNT_FL_EXTERN_CACHE))
 
764
                mnt_free_cache(cxt->cache);
 
765
 
 
766
        set_flag(cxt, MNT_FL_EXTERN_CACHE, cache != NULL);
 
767
        cxt->cache = cache;
 
768
        return 0;
 
769
}
 
770
 
 
771
/**
 
772
 * mnt_context_get_cache
 
773
 * @cxt: mount context
 
774
 *
 
775
 * See also mnt_context_set_cache().
 
776
 *
 
777
 * Returns: pointer to cache or NULL if canonicalization is disabled.
 
778
 */
 
779
struct libmnt_cache *mnt_context_get_cache(struct libmnt_context *cxt)
 
780
{
 
781
        if (!cxt || (cxt->flags & MNT_FL_NOCANONICALIZE))
 
782
                return NULL;
 
783
 
 
784
        if (!cxt->cache) {
 
785
                cxt->cache = mnt_new_cache();
 
786
                if (!cxt->cache)
 
787
                        return NULL;
 
788
                cxt->flags &= ~MNT_FL_EXTERN_CACHE;
 
789
        }
 
790
        return cxt->cache;
 
791
}
 
792
 
 
793
/**
 
794
 * mnt_context_get_lock:
 
795
 * @cxt: mount context
 
796
 *
 
797
 * The libmount applications don't have to care about mtab locking, but with a
 
798
 * small exception: the application has to be able to remove the lock file when
 
799
 * interrupted by signal or signals have to be ignored when the lock is locked.
 
800
 *
 
801
 * The default behavior is to ignore all signals (except SIGALRM and SIGTRAP)
 
802
 * when the lock is locked. If this behavior is unacceptable then use:
 
803
 *
 
804
 *      lc = mnt_context_get_lock(cxt);
 
805
 *      if (lc)
 
806
 *              mnt_lock_block_signals(lc, FALSE);
 
807
 *
 
808
 * and don't forget to call mnt_unlock_file(lc) before exit.
 
809
 *
 
810
 * This function returns NULL if the lock is unnecessary (mtab file is not writable
 
811
 * or /etc/mtab is symlink to /proc/mounts).
 
812
 *
 
813
 * Returns: pointer to lock struct or NULL.
 
814
 */
 
815
struct libmnt_lock *mnt_context_get_lock(struct libmnt_context *cxt)
 
816
{
 
817
        if (!cxt || (cxt->flags & MNT_FL_NOMTAB) || !cxt->mtab_writable)
 
818
                return NULL;
 
819
 
 
820
        if (!cxt->lock && cxt->mtab_path) {
 
821
                cxt->lock = mnt_new_lock(cxt->mtab_path, 0);
 
822
                if (cxt->lock)
 
823
                        mnt_lock_block_signals(cxt->lock, TRUE);
 
824
        }
 
825
        return cxt->lock;
 
826
}
 
827
 
 
828
/**
 
829
 * mnt_context_set_mflags:
 
830
 * @cxt: mount context
 
831
 * @flags: mount(2) flags (MS_* flags)
 
832
 *
 
833
 * Sets mount flags (see mount(2) man page).
 
834
 *
 
835
 * Note that mount context allows to define mount options by mount flags. It
 
836
 * means you can for example use
 
837
 *
 
838
 *      mnt_context_set_mflags(cxt, MS_NOEXEC | MS_NOSUID);
 
839
 *
 
840
 * rather than
 
841
 *
 
842
 *      mnt_context_set_options(cxt, "noexec,nosuid");
 
843
 *
 
844
 * these both calls have the same effect.
 
845
 *
 
846
 * Returns: 0 on success, negative number in case of error.
 
847
 */
 
848
int mnt_context_set_mflags(struct libmnt_context *cxt, unsigned long flags)
 
849
{
 
850
        if (!cxt)
 
851
                return -EINVAL;
 
852
        cxt->mountflags = flags;
 
853
        return 0;
 
854
}
 
855
 
 
856
/**
 
857
 * mnt_context_get_mflags:
 
858
 * @cxt: mount context
 
859
 * @flags: returns MS_* mount flags
 
860
 *
 
861
 * Converts mount options string to MS_* flags and bitewise-OR the result with
 
862
 * already defined flags (see mnt_context_set_mflags()).
 
863
 *
 
864
 * Returns: 0 on success, negative number in case of error.
 
865
 */
 
866
int mnt_context_get_mflags(struct libmnt_context *cxt, unsigned long *flags)
 
867
{
 
868
        int rc = 0;
 
869
        if (!cxt || !flags)
 
870
                return -EINVAL;
 
871
 
 
872
        *flags = 0;
 
873
        if (!(cxt->flags & MNT_FL_MOUNTFLAGS_MERGED) && cxt->fs) {
 
874
                const char *o = mnt_fs_get_vfs_options(cxt->fs);
 
875
                if (o)
 
876
                        rc = mnt_optstr_get_flags(o, flags,
 
877
                                    mnt_get_builtin_optmap(MNT_LINUX_MAP));
 
878
        }
 
879
        if (!rc)
 
880
                *flags |= cxt->mountflags;
 
881
        return rc;
 
882
}
 
883
 
 
884
/**
 
885
 * mnt_context_set_user_mflags:
 
886
 * @cxt: mount context
 
887
 * @flags: mount(2) flags (MNT_MS_* flags, e.g. MNT_MS_LOOP)
 
888
 *
 
889
 * Sets userspace mount flags.
 
890
 *
 
891
 * See also notest for mnt_context_set_mflags().
 
892
 *
 
893
 * Returns: 0 on success, negative number in case of error.
 
894
 */
 
895
int mnt_context_set_user_mflags(struct libmnt_context *cxt, unsigned long flags)
 
896
{
 
897
        if (!cxt)
 
898
                return -EINVAL;
 
899
        cxt->user_mountflags = flags;
 
900
        return 0;
 
901
}
 
902
 
 
903
/**
 
904
 * mnt_context_get_user_mflags:
 
905
 * @cxt: mount context
 
906
 * @flags: returns mount flags
 
907
 *
 
908
 * Converts mount options string to MNT_MS_* flags and bitewise-OR the result
 
909
 * with already defined flags (see mnt_context_set_user_mflags()).
 
910
 *
 
911
 * Returns: 0 on success, negative number in case of error.
 
912
 */
 
913
int mnt_context_get_user_mflags(struct libmnt_context *cxt, unsigned long *flags)
 
914
{
 
915
        int rc = 0;
 
916
        if (!cxt || !flags)
 
917
                return -EINVAL;
 
918
 
 
919
        *flags = 0;
 
920
        if (!(cxt->flags & MNT_FL_MOUNTFLAGS_MERGED) && cxt->fs) {
 
921
                const char *o = mnt_fs_get_user_options(cxt->fs);
 
922
                if (o)
 
923
                        rc = mnt_optstr_get_flags(o, flags,
 
924
                                mnt_get_builtin_optmap(MNT_USERSPACE_MAP));
 
925
        }
 
926
        if (!rc)
 
927
                *flags |= cxt->user_mountflags;
 
928
        return rc;
 
929
}
 
930
 
 
931
static int is_loop(struct libmnt_context *cxt)
 
932
{
 
933
        unsigned long fl = 0;
 
934
 
 
935
        if (cxt->user_mountflags & MNT_MS_LOOP)
 
936
                return 1;
 
937
        if (!mnt_context_get_mflags(cxt, &fl) && (fl & MNT_MS_LOOP))
 
938
                return 1;
 
939
 
 
940
        /* TODO:
 
941
         *      - support MNT_MS_{OFFSET,SIZELIMIT,ENCRYPTION}
 
942
         */
 
943
        return 0;
 
944
}
 
945
 
 
946
/**
 
947
 * mnt_context_set_mountdata:
 
948
 * @cxt: mount context
 
949
 * @data: mount(2) data
 
950
 *
 
951
 * The mount context generates mountdata from mount options by default. This
 
952
 * function allows to overwrite this behavior, and @data will be used instead
 
953
 * of mount options.
 
954
 *
 
955
 * The libmount does not deallocated the data by mnt_free_context(). Note that
 
956
 * NULL is also valid mount data.
 
957
 *
 
958
 * Returns: 0 on success, negative number in case of error.
 
959
 */
 
960
int mnt_context_set_mountdata(struct libmnt_context *cxt, void *data)
 
961
{
 
962
        if (!cxt)
 
963
                return -EINVAL;
 
964
        cxt->mountdata = data;
 
965
        cxt->flags |= MNT_FL_MOUNTDATA;
 
966
        return 0;
 
967
}
 
968
 
 
969
/*
 
970
 * Translates LABEL/UUID/path to mountable path
 
971
 */
 
972
int mnt_context_prepare_srcpath(struct libmnt_context *cxt)
 
973
{
 
974
        const char *path = NULL;
 
975
        struct libmnt_cache *cache;
 
976
        const char *t, *v, *src;
 
977
        int rc = 0;
 
978
 
 
979
        assert(cxt);
 
980
        assert(cxt->fs);
 
981
        assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
 
982
 
 
983
        if (!cxt || !cxt->fs)
 
984
                return -EINVAL;
 
985
 
 
986
        DBG(CXT, mnt_debug_h(cxt, "preparing source path"));
 
987
 
 
988
        src = mnt_fs_get_source(cxt->fs);
 
989
 
 
990
        /* ignore filesystems without source or filesystems
 
991
         * where the source is quasi-path (//foo/bar)
 
992
         */
 
993
        if (!src || (cxt->fs->flags & MNT_FS_NET))
 
994
                return 0;
 
995
 
 
996
        DBG(CXT, mnt_debug_h(cxt, "srcpath '%s'", src));
 
997
 
 
998
        cache = mnt_context_get_cache(cxt);
 
999
 
 
1000
        if (!mnt_fs_get_tag(cxt->fs, &t, &v)) {
 
1001
                /*
 
1002
                 * Source is TAG (evaluate)
 
1003
                 */
 
1004
                if (cache)
 
1005
                        path = mnt_resolve_tag(t, v, cache);
 
1006
 
 
1007
                rc = path ? mnt_fs_set_source(cxt->fs, path) : -EINVAL;
 
1008
 
 
1009
        } else if (cache) {
 
1010
                /*
 
1011
                 * Source is PATH (canonicalize)
 
1012
                 */
 
1013
                path = mnt_resolve_path(src, cache);
 
1014
                if (path && strcmp(path, src))
 
1015
                        rc = mnt_fs_set_source(cxt->fs, path);
 
1016
         }
 
1017
 
 
1018
        if (rc) {
 
1019
                DBG(CXT, mnt_debug_h(cxt, "failed to prepare srcpath [rc=%d]", rc));
 
1020
                return rc;
 
1021
        }
 
1022
 
 
1023
        if (!path)
 
1024
                path = src;
 
1025
 
 
1026
        if ((cxt->mountflags & (MS_BIND | MS_MOVE | MS_PROPAGATION)) ||
 
1027
            (cxt->fs->flags & MNT_FS_PSEUDO)) {
 
1028
                DBG(CXT, mnt_debug_h(cxt, "PROPAGATION/pseudo FS source: %s", path));
 
1029
                return rc;
 
1030
        }
 
1031
 
 
1032
        /*
 
1033
         * Initialize loop device
 
1034
         */
 
1035
        if (is_loop(cxt)) {
 
1036
                ; /* TODO */
 
1037
        }
 
1038
 
 
1039
        DBG(CXT, mnt_debug_h(cxt, "final srcpath '%s'", path));
 
1040
        return 0;
 
1041
}
 
1042
 
 
1043
int mnt_context_prepare_target(struct libmnt_context *cxt)
 
1044
{
 
1045
        const char *tgt;
 
1046
        struct libmnt_cache *cache;
 
1047
        int rc = 0;
 
1048
 
 
1049
        assert(cxt);
 
1050
        assert(cxt->fs);
 
1051
        assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
 
1052
 
 
1053
        if (!cxt || !cxt->fs)
 
1054
                return -EINVAL;
 
1055
 
 
1056
        DBG(CXT, mnt_debug_h(cxt, "preparing target path"));
 
1057
 
 
1058
        tgt = mnt_fs_get_target(cxt->fs);
 
1059
        if (!tgt)
 
1060
                return 0;
 
1061
 
 
1062
        cache = mnt_context_get_cache(cxt);
 
1063
        if (cache) {
 
1064
                char *path = mnt_resolve_path(tgt, cache);
 
1065
                if (strcmp(path, tgt))
 
1066
                        rc = mnt_fs_set_target(cxt->fs, path);
 
1067
        }
 
1068
 
 
1069
        if (rc)
 
1070
                DBG(CXT, mnt_debug_h(cxt, "failed to prepare target"));
 
1071
        else
 
1072
                DBG(CXT, mnt_debug_h(cxt, "final target '%s'",
 
1073
                                        mnt_fs_get_target(cxt->fs)));
 
1074
        return 0;
 
1075
}
 
1076
 
 
1077
int mnt_context_guess_fstype(struct libmnt_context *cxt)
 
1078
{
 
1079
        char *type;
 
1080
        const char *dev;
 
1081
        int rc = -EINVAL;
 
1082
 
 
1083
        assert(cxt);
 
1084
        assert(cxt->fs);
 
1085
        assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
 
1086
 
 
1087
        if (!cxt || !cxt->fs)
 
1088
                return -EINVAL;
 
1089
 
 
1090
        if (cxt->mountflags & (MS_BIND | MS_MOVE | MS_PROPAGATION))
 
1091
                goto none;
 
1092
 
 
1093
        type = (char *) mnt_fs_get_fstype(cxt->fs);
 
1094
        if (type && !strcmp(type, "auto")) {
 
1095
                mnt_fs_set_fstype(cxt->fs, NULL);
 
1096
                type = NULL;
 
1097
        }
 
1098
 
 
1099
        if (type)
 
1100
                goto done;
 
1101
        if (cxt->flags & MS_REMOUNT)
 
1102
                goto none;
 
1103
        if (cxt->fstype_pattern)
 
1104
                goto done;
 
1105
 
 
1106
        dev = mnt_fs_get_srcpath(cxt->fs);
 
1107
        if (!dev)
 
1108
                goto err;
 
1109
 
 
1110
        if (access(dev, F_OK) == 0) {
 
1111
                struct libmnt_cache *cache = mnt_context_get_cache(cxt);
 
1112
 
 
1113
                type = mnt_get_fstype(dev, &cxt->ambi, cache);
 
1114
                if (type) {
 
1115
                        rc = mnt_fs_set_fstype(cxt->fs, type);
 
1116
                        if (!cache)
 
1117
                                free(type);     /* type is not cached */
 
1118
                }
 
1119
        } else {
 
1120
                if (strchr(dev, ':') != NULL)
 
1121
                        rc = mnt_fs_set_fstype(cxt->fs, "nfs");
 
1122
                else if (!strncmp(dev, "//", 2))
 
1123
                        rc = mnt_fs_set_fstype(cxt->fs, "cifs");
 
1124
        }
 
1125
        if (rc)
 
1126
                goto err;
 
1127
done:
 
1128
        DBG(CXT, mnt_debug_h(cxt, "FS type: %s",
 
1129
                                mnt_fs_get_fstype(cxt->fs)));
 
1130
        return 0;
 
1131
none:
 
1132
        return mnt_fs_set_fstype(cxt->fs, "none");
 
1133
err:
 
1134
        DBG(CXT, mnt_debug_h(cxt, "failed to detect FS type"));
 
1135
        return rc;
 
1136
}
 
1137
 
 
1138
/*
 
1139
 * The default is to use fstype from cxt->fs, this could be overwritten by
 
1140
 * @type. The @act is MNT_ACT_{MOUNT,UMOUNT}.
 
1141
 *
 
1142
 * Returns: 0 on success or negative number in case of error. Note that success
 
1143
 * does not mean that there is any usable helper, you have to check cxt->helper.
 
1144
 */
 
1145
int mnt_context_prepare_helper(struct libmnt_context *cxt, const char *name,
 
1146
                                const char *type)
 
1147
{
 
1148
        char search_path[] = FS_SEARCH_PATH;            /* from config.h */
 
1149
        char *p = NULL, *path;
 
1150
 
 
1151
        assert(cxt);
 
1152
        assert(cxt->fs);
 
1153
        assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
 
1154
 
 
1155
        if (!type)
 
1156
                type = mnt_fs_get_fstype(cxt->fs);
 
1157
 
 
1158
        if ((cxt->flags & MNT_FL_NOHELPERS) || !type ||
 
1159
            !strcmp(type, "none") || (cxt->fs->flags & MNT_FS_SWAP))
 
1160
                return 0;
 
1161
 
 
1162
        path = strtok_r(search_path, ":", &p);
 
1163
        while (path) {
 
1164
                char helper[PATH_MAX];
 
1165
                struct stat st;
 
1166
                int rc;
 
1167
 
 
1168
                rc = snprintf(helper, sizeof(helper), "%s/%s.%s",
 
1169
                                                path, name, type);
 
1170
                path = strtok_r(NULL, ":", &p);
 
1171
 
 
1172
                if (rc >= sizeof(helper) || rc < 0)
 
1173
                        continue;
 
1174
 
 
1175
                rc = stat(helper, &st);
 
1176
                if (rc == -1 && errno == ENOENT && strchr(type, '.')) {
 
1177
                        /* If type ends with ".subtype" try without it */
 
1178
                        *strrchr(helper, '.') = '\0';
 
1179
                        rc = stat(helper, &st);
 
1180
                }
 
1181
 
 
1182
                DBG(CXT, mnt_debug_h(cxt, "%-25s ... %s", helper,
 
1183
                                        rc ? "not found" : "found"));
 
1184
                if (rc)
 
1185
                        continue;
 
1186
 
 
1187
                if (cxt->helper)
 
1188
                        free(cxt->helper);
 
1189
                cxt->helper = strdup(helper);
 
1190
                if (!cxt->helper)
 
1191
                        return -ENOMEM;
 
1192
                return 0;
 
1193
        }
 
1194
 
 
1195
        return 0;
 
1196
}
 
1197
 
 
1198
int mnt_context_merge_mflags(struct libmnt_context *cxt)
 
1199
{
 
1200
        unsigned long fl = 0;
 
1201
        int rc;
 
1202
 
 
1203
        assert(cxt);
 
1204
 
 
1205
        DBG(CXT, mnt_debug_h(cxt, "merging mount flags"));
 
1206
 
 
1207
        rc = mnt_context_get_mflags(cxt, &fl);
 
1208
        if (rc)
 
1209
                return rc;
 
1210
        cxt->mountflags = fl;
 
1211
 
 
1212
        /* TODO: if cxt->fs->fs_optstr contains 'ro' then set the MS_RDONLY to
 
1213
         * mount flags, it's possible that superblock is read-only, but VFS is
 
1214
         * read-write.
 
1215
         */
 
1216
 
 
1217
        fl = 0;
 
1218
        rc = mnt_context_get_user_mflags(cxt, &fl);
 
1219
        if (rc)
 
1220
                return rc;
 
1221
        cxt->user_mountflags = fl;
 
1222
 
 
1223
        DBG(CXT, mnt_debug_h(cxt, "final flags: VFS=%08lx user=%08lx",
 
1224
                        cxt->mountflags, cxt->user_mountflags));
 
1225
 
 
1226
        cxt->flags |= MNT_FL_MOUNTFLAGS_MERGED;
 
1227
        return 0;
 
1228
}
 
1229
 
 
1230
/*
 
1231
 * Prepare /etc/mtab or /run/mount/utab
 
1232
 */
 
1233
int mnt_context_prepare_update(struct libmnt_context *cxt)
 
1234
{
 
1235
        int rc;
 
1236
        const char *target;
 
1237
 
 
1238
        assert(cxt);
 
1239
        assert(cxt->fs);
 
1240
        assert(cxt->action);
 
1241
        assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
 
1242
 
 
1243
        DBG(CXT, mnt_debug_h(cxt, "prepare update"));
 
1244
 
 
1245
        if (cxt->mountflags & MS_PROPAGATION) {
 
1246
                DBG(CXT, mnt_debug_h(cxt, "skip update: MS_PROPAGATION"));
 
1247
                return 0;
 
1248
        }
 
1249
 
 
1250
        target = mnt_fs_get_target(cxt->fs);
 
1251
 
 
1252
        if (cxt->action == MNT_ACT_UMOUNT && target && !strcmp(target, "/"))
 
1253
                /* Don't try to touch mtab if umounting root FS */
 
1254
                cxt->flags |= MNT_FL_NOMTAB;
 
1255
 
 
1256
        if (cxt->flags & MNT_FL_NOMTAB) {
 
1257
                DBG(CXT, mnt_debug_h(cxt, "skip update: NOMTAB flag"));
 
1258
                return 0;
 
1259
        }
 
1260
        if (cxt->helper) {
 
1261
                DBG(CXT, mnt_debug_h(cxt, "skip update: external helper"));
 
1262
                return 0;
 
1263
        }
 
1264
        if (!cxt->mtab_writable && !cxt->utab_writable) {
 
1265
                DBG(CXT, mnt_debug_h(cxt, "skip update: no writable destination"));
 
1266
                return 0;
 
1267
        }
 
1268
        /* 0 = success, 1 = not called yet */
 
1269
        if (cxt->syscall_status != 1 && cxt->syscall_status != 0) {
 
1270
                DBG(CXT, mnt_debug_h(cxt,
 
1271
                                "skip update: syscall failed [status=%d]",
 
1272
                                cxt->syscall_status));
 
1273
                return 0;
 
1274
        }
 
1275
        if (!cxt->update) {
 
1276
                cxt->update = mnt_new_update();
 
1277
                if (!cxt->update)
 
1278
                        return -ENOMEM;
 
1279
 
 
1280
                mnt_update_set_filename(cxt->update,
 
1281
                                cxt->mtab_writable ? cxt->mtab_path : cxt->utab_path,
 
1282
                                !cxt->mtab_writable);
 
1283
        }
 
1284
 
 
1285
        if (cxt->action == MNT_ACT_UMOUNT)
 
1286
                rc = mnt_update_set_fs(cxt->update, cxt->mountflags,
 
1287
                                        mnt_fs_get_target(cxt->fs), NULL);
 
1288
        else
 
1289
                rc = mnt_update_set_fs(cxt->update, cxt->mountflags,
 
1290
                                        NULL, cxt->fs);
 
1291
 
 
1292
        return rc < 0 ? rc : 0;
 
1293
}
 
1294
 
 
1295
int mnt_context_update_tabs(struct libmnt_context *cxt)
 
1296
{
 
1297
        unsigned long fl;
 
1298
 
 
1299
        assert(cxt);
 
1300
 
 
1301
        if (cxt->flags & MNT_FL_NOMTAB) {
 
1302
                DBG(CXT, mnt_debug_h(cxt, "don't update: NOMTAB flag"));
 
1303
                return 0;
 
1304
        }
 
1305
        if (cxt->helper) {
 
1306
                DBG(CXT, mnt_debug_h(cxt, "don't update: external helper"));
 
1307
                return 0;
 
1308
        }
 
1309
        if (!cxt->update || !mnt_update_is_ready(cxt->update)) {
 
1310
                DBG(CXT, mnt_debug_h(cxt, "don't update: no update prepared"));
 
1311
                return 0;
 
1312
        }
 
1313
        if (cxt->syscall_status) {
 
1314
                DBG(CXT, mnt_debug_h(cxt, "don't update: syscall failed/not called"));
 
1315
                return 0;
 
1316
        }
 
1317
 
 
1318
        fl = mnt_update_get_mflags(cxt->update);
 
1319
        if ((cxt->mountflags & MS_RDONLY) != (fl & MS_RDONLY))
 
1320
                /*
 
1321
                 * fix MS_RDONLY in options
 
1322
                 */
 
1323
                mnt_update_force_rdonly(cxt->update,
 
1324
                                cxt->mountflags & MS_RDONLY);
 
1325
 
 
1326
        return mnt_update_table(cxt->update, mnt_context_get_lock(cxt));
 
1327
}
 
1328
 
 
1329
static int apply_table(struct libmnt_context *cxt, struct libmnt_table *tb,
 
1330
                     int direction)
 
1331
{
 
1332
        struct libmnt_fs *fs = NULL;
 
1333
        const char *src = NULL, *tgt = NULL;
 
1334
        int rc;
 
1335
 
 
1336
        assert(cxt);
 
1337
        assert(cxt->fs);
 
1338
 
 
1339
        if (!cxt->fs)
 
1340
                return -EINVAL;
 
1341
 
 
1342
        src = mnt_fs_get_source(cxt->fs);
 
1343
        tgt = mnt_fs_get_target(cxt->fs);
 
1344
 
 
1345
        if (tgt && src)
 
1346
                fs = mnt_table_find_pair(tb, src, tgt, direction);
 
1347
        else {
 
1348
                if (src)
 
1349
                        fs = mnt_table_find_source(tb, src, direction);
 
1350
                else if (tgt)
 
1351
                        fs = mnt_table_find_target(tb, tgt, direction);
 
1352
 
 
1353
                if (!fs) {
 
1354
                        /* swap source and target (if @src is not LABEL/UUID),
 
1355
                         * for example in
 
1356
                         *
 
1357
                         *      mount /foo/bar
 
1358
                         *
 
1359
                         * the path could be a mountpoint as well as source (for
 
1360
                         * example bind mount, symlink to device, ...).
 
1361
                         */
 
1362
                        if (src && !mnt_fs_get_tag(cxt->fs, NULL, NULL))
 
1363
                                fs = mnt_table_find_target(tb, src, direction);
 
1364
                        if (!fs && tgt)
 
1365
                                fs = mnt_table_find_source(tb, tgt, direction);
 
1366
                }
 
1367
        }
 
1368
 
 
1369
        if (!fs)
 
1370
                return -EINVAL;
 
1371
 
 
1372
        DBG(CXT, mnt_debug_h(cxt, "apply entry:"));
 
1373
        DBG(CXT, mnt_fs_print_debug(fs, stderr));
 
1374
 
 
1375
        /* copy from tab to our FS description
 
1376
         */
 
1377
        rc = mnt_fs_set_source(cxt->fs, mnt_fs_get_source(fs));
 
1378
        if (!rc)
 
1379
                rc = mnt_fs_set_target(cxt->fs, mnt_fs_get_target(fs));
 
1380
 
 
1381
        if (!rc && !mnt_fs_get_fstype(cxt->fs))
 
1382
                rc = mnt_fs_set_fstype(cxt->fs, mnt_fs_get_fstype(fs));
 
1383
 
 
1384
        if (rc)
 
1385
                return rc;
 
1386
 
 
1387
        if (cxt->optsmode & MNT_OMODE_IGNORE)
 
1388
                ;
 
1389
        else if (cxt->optsmode & MNT_OMODE_REPLACE) {
 
1390
                rc = mnt_fs_set_vfs_options(cxt->fs,
 
1391
                                        mnt_fs_get_vfs_options(fs));
 
1392
                if (!rc)
 
1393
                        rc = mnt_fs_set_fs_options(cxt->fs,
 
1394
                                        mnt_fs_get_fs_options(fs));
 
1395
                if (!rc)
 
1396
                        rc = mnt_fs_set_user_options(cxt->fs,
 
1397
                                        mnt_fs_get_user_options(fs));
 
1398
 
 
1399
        } else if (cxt->optsmode & MNT_OMODE_APPEND) {
 
1400
                rc = mnt_fs_append_vfs_options(cxt->fs,
 
1401
                                        mnt_fs_get_vfs_options(fs));
 
1402
                if (!rc)
 
1403
                        rc = mnt_fs_append_fs_options(cxt->fs,
 
1404
                                        mnt_fs_get_fs_options(fs));
 
1405
                if (!rc)
 
1406
                        rc = mnt_fs_append_user_options(cxt->fs,
 
1407
                                        mnt_fs_get_user_options(fs));
 
1408
 
 
1409
        } else if (cxt->optsmode & MNT_OMODE_PREPEND) {
 
1410
                rc = mnt_fs_prepend_vfs_options(cxt->fs,
 
1411
                                        mnt_fs_get_vfs_options(fs));
 
1412
                if (!rc)
 
1413
                        rc = mnt_fs_prepend_fs_options(cxt->fs,
 
1414
                                        mnt_fs_get_fs_options(fs));
 
1415
                if (!rc)
 
1416
                        rc = mnt_fs_prepend_user_options(cxt->fs,
 
1417
                                        mnt_fs_get_user_options(fs));
 
1418
        }
 
1419
 
 
1420
        if (!rc)
 
1421
                cxt->flags |= MNT_FL_TAB_APPLIED;
 
1422
        return rc;
 
1423
}
 
1424
 
 
1425
/**
 
1426
 * mnt_context_apply_fstab:
 
1427
 * @cxt: mount context
 
1428
 *
 
1429
 * This function is optional.
 
1430
 *
 
1431
 * Returns: 0 on success, negative number in case of error.
 
1432
 */
 
1433
int mnt_context_apply_fstab(struct libmnt_context *cxt)
 
1434
{
 
1435
        int rc = -1;
 
1436
        struct libmnt_table *tab = NULL;
 
1437
        const char *src = NULL, *tgt = NULL;
 
1438
 
 
1439
        assert(cxt);
 
1440
        assert(cxt->fs);
 
1441
 
 
1442
        if (!cxt)
 
1443
                return -EINVAL;
 
1444
 
 
1445
        if (cxt->flags & MNT_FL_TAB_APPLIED)
 
1446
                return 0;
 
1447
 
 
1448
        if (mnt_context_is_restricted(cxt)) {
 
1449
                DBG(CXT, mnt_debug_h(cxt, "force fstab usage for non-root users"));
 
1450
                cxt->optsmode = MNT_OMODE_USER;
 
1451
 
 
1452
        } else if (cxt->optsmode == 0)
 
1453
                cxt->optsmode = MNT_OMODE_AUTO;
 
1454
 
 
1455
        if (cxt->fs) {
 
1456
                src = mnt_fs_get_source(cxt->fs);
 
1457
                tgt = mnt_fs_get_target(cxt->fs);
 
1458
        }
 
1459
 
 
1460
        /* fstab is not required if source and target are specified */
 
1461
        if (src && tgt && !(cxt->optsmode & MNT_OMODE_FORCE)) {
 
1462
                DBG(CXT, mnt_debug_h(cxt, "fstab not required -- skip"));
 
1463
                return 0;
 
1464
        }
 
1465
 
 
1466
        DBG(CXT, mnt_debug_h(cxt,
 
1467
                "trying to apply fstab (src=%s, target=%s)", src, tgt));
 
1468
 
 
1469
        /* let's initialize cxt->fs */
 
1470
        mnt_context_get_fs(cxt);
 
1471
 
 
1472
        /* try fstab */
 
1473
        if (cxt->optsmode & MNT_OMODE_FSTAB) {
 
1474
                rc = mnt_context_get_fstab(cxt, &tab);
 
1475
                if (!rc)
 
1476
                        rc = apply_table(cxt, tab, MNT_ITER_FORWARD);
 
1477
        }
 
1478
 
 
1479
        /* try mtab */
 
1480
        if (rc == -1 && (cxt->optsmode & MNT_OMODE_MTAB)) {
 
1481
                rc = mnt_context_get_mtab(cxt, &tab);
 
1482
                if (!rc)
 
1483
                        rc = apply_table(cxt, tab, MNT_ITER_BACKWARD);
 
1484
        }
 
1485
        if (rc)
 
1486
                DBG(CXT, mnt_debug_h(cxt, "failed to found entry in fstab/mtab"));
 
1487
        return rc;
 
1488
}
 
1489
 
 
1490
/**
 
1491
 * mnt_context_get_status:
 
1492
 * @cxt: mount context
 
1493
 *
 
1494
 * Returns: 0 if /sbin/mount.type or mount(2) syscall was successfull.
 
1495
 */
 
1496
int mnt_context_get_status(struct libmnt_context *cxt)
 
1497
{
 
1498
        return cxt && (!cxt->syscall_status || !cxt->helper_exec_status);
 
1499
}
 
1500
 
 
1501
/**
 
1502
 * mnt_context_set_syscall_status:
 
1503
 * @cxt: mount context
 
1504
 * @status: mount(2) return code
 
1505
 *
 
1506
 * The @status should be 0 on succcess, or negative number on error (-1 or
 
1507
 * -errno).
 
1508
 *
 
1509
 * This function should be used if [u]mount(2) syscall was NOT called by
 
1510
 * libmount (by mnt_context_mount() or mnt_context_do_mount()) only.
 
1511
 *
 
1512
 * Returns: 0 or negative number in case of error.
 
1513
 */
 
1514
int mnt_context_set_syscall_status(struct libmnt_context *cxt, int status)
 
1515
{
 
1516
        if (!cxt)
 
1517
                return -EINVAL;
 
1518
 
 
1519
        DBG(CXT, mnt_debug_h(cxt, "syscall status set to: %d", status));
 
1520
        cxt->syscall_status = status;
 
1521
        return 0;
 
1522
}
 
1523
 
 
1524
/**
 
1525
 * mnt_context_strerror
 
1526
 * @cxt: context
 
1527
 * @buf: buffer
 
1528
 * @bufsiz: size of the buffer
 
1529
 *
 
1530
 * Returns: 0 or negative number in case of error.
 
1531
 */
 
1532
int mnt_context_strerror(struct libmnt_context *cxt, char *buf, size_t bufsiz)
 
1533
{
 
1534
        /* TODO: based on cxt->syscall_errno or cxt->helper_status */
 
1535
        return 0;
 
1536
}
 
1537
 
 
1538
/**
 
1539
 * mnt_context_init_helper
 
1540
 * @cxt: mount context
 
1541
 * @action: MNT_ACT_{UMOUNT,MOUNT}
 
1542
 * @flags: not used
 
1543
 *
 
1544
 * This function infors libmount that used from [u]mount.<type> helper.
 
1545
 *
 
1546
 * The function also calls mnt_context_disable_helpers() to avoid recursive
 
1547
 * mount.<type> helpers calling. It you really want to call another
 
1548
 * mount.<type> helper from your helper than you have to explicitly enable this
 
1549
 * feature by:
 
1550
 *
 
1551
 *       mnt_context_disable_helpers(cxt, FALSE);
 
1552
 *
 
1553
 * Returns: 0 on success, negative number in case of error.
 
1554
 */
 
1555
int mnt_context_init_helper(struct libmnt_context *cxt, int action, int flags)
 
1556
{
 
1557
        int rc = mnt_context_disable_helpers(cxt, TRUE);
 
1558
 
 
1559
        if (!rc)
 
1560
                rc = set_flag(cxt, MNT_FL_HELPER, 1);
 
1561
        if (!rc)
 
1562
                cxt->action = action;
 
1563
 
 
1564
        DBG(CXT, mnt_debug_h(cxt, "initialized for [u]mount.<type> helper [rc=%d]", rc));
 
1565
        return rc;
 
1566
}
 
1567
 
 
1568
/**
 
1569
 * mnt_context_helper_setopt:
 
1570
 * @cxr: context
 
1571
 * @c: getopt() result
 
1572
 * @arg: getopt() optarg
 
1573
 *
 
1574
 * This function applies [u]mount.<type> command line option (for example parsed
 
1575
 * by getopt() or getopt_long()) to @cxt. All unknown options are ignored and
 
1576
 * then 1 is returned.
 
1577
 *
 
1578
 * Returns: negative number on error, 1 if @c is unknown option, 0 on success.
 
1579
 */
 
1580
int mnt_context_helper_setopt(struct libmnt_context *cxt, int c, char *arg)
 
1581
{
 
1582
        if (cxt) {
 
1583
                switch(cxt->action) {
 
1584
                case MNT_ACT_MOUNT:
 
1585
                        return mnt_context_mount_setopt(cxt, c, arg);
 
1586
                case MNT_ACT_UMOUNT:
 
1587
                        return mnt_context_umount_setopt(cxt, c, arg);
 
1588
                }
 
1589
        }
 
1590
        return -EINVAL;
 
1591
}
 
1592
 
 
1593
#ifdef TEST_PROGRAM
 
1594
 
 
1595
struct libmnt_lock *lock;
 
1596
 
 
1597
static void lock_fallback(void)
 
1598
{
 
1599
        if (lock)
 
1600
                mnt_unlock_file(lock);
 
1601
}
 
1602
 
 
1603
int test_mount(struct libmnt_test *ts, int argc, char *argv[])
 
1604
{
 
1605
        int idx = 1, rc = 0;
 
1606
        struct libmnt_context *cxt;
 
1607
 
 
1608
        if (argc < 2)
 
1609
                return -EINVAL;
 
1610
 
 
1611
        cxt = mnt_new_context();
 
1612
        if (!cxt)
 
1613
                return -ENOMEM;
 
1614
 
 
1615
        if (!strcmp(argv[idx], "-o")) {
 
1616
                mnt_context_set_options(cxt, argv[idx + 1]);
 
1617
                idx += 2;
 
1618
        }
 
1619
        if (!strcmp(argv[idx], "-t")) {
 
1620
                /* TODO: use mnt_context_set_fstype_pattern() */
 
1621
                mnt_context_set_fstype(cxt, argv[idx + 1]);
 
1622
                idx += 2;
 
1623
        }
 
1624
 
 
1625
        if (argc == idx + 1)
 
1626
                /* mount <mountpont>|<device> */
 
1627
                mnt_context_set_target(cxt, argv[idx++]);
 
1628
 
 
1629
        else if (argc == idx + 2) {
 
1630
                /* mount <device> <mountpoint> */
 
1631
                mnt_context_set_source(cxt, argv[idx++]);
 
1632
                mnt_context_set_target(cxt, argv[idx++]);
 
1633
        }
 
1634
 
 
1635
        lock = mnt_context_get_lock(cxt);
 
1636
        if (lock)
 
1637
                atexit(lock_fallback);
 
1638
 
 
1639
        rc = mnt_context_mount(cxt);
 
1640
        if (rc)
 
1641
                printf("failed to mount %s\n", strerror(errno));
 
1642
        else
 
1643
                printf("successfully mounted\n");
 
1644
 
 
1645
        mnt_free_context(cxt);
 
1646
        return rc;
 
1647
}
 
1648
 
 
1649
int test_umount(struct libmnt_test *ts, int argc, char *argv[])
 
1650
{
 
1651
        int idx = 1, rc = 0;
 
1652
        struct libmnt_context *cxt;
 
1653
 
 
1654
        if (argc < 2)
 
1655
                return -EINVAL;
 
1656
 
 
1657
        cxt = mnt_new_context();
 
1658
        if (!cxt)
 
1659
                return -ENOMEM;
 
1660
 
 
1661
        if (!strcmp(argv[idx], "-t")) {
 
1662
                mnt_context_set_fstype(cxt, argv[idx + 1]);
 
1663
                idx += 2;
 
1664
        }
 
1665
 
 
1666
        if (!strcmp(argv[idx], "-f")) {
 
1667
                mnt_context_enable_force(cxt, TRUE);
 
1668
                idx++;
 
1669
        }
 
1670
 
 
1671
        if (!strcmp(argv[idx], "-l")) {
 
1672
                mnt_context_enable_lazy(cxt, TRUE);
 
1673
                idx++;
 
1674
        }
 
1675
 
 
1676
        if (!strcmp(argv[idx], "-r")) {
 
1677
                mnt_context_enable_rdonly_umount(cxt, TRUE);
 
1678
                idx++;
 
1679
        }
 
1680
 
 
1681
        if (argc == idx + 1) {
 
1682
                /* mount <mountpont>|<device> */
 
1683
                mnt_context_set_target(cxt, argv[idx++]);
 
1684
        } else {
 
1685
                rc = -EINVAL;
 
1686
                goto err;
 
1687
        }
 
1688
 
 
1689
        lock = mnt_context_get_lock(cxt);
 
1690
        if (lock)
 
1691
                atexit(lock_fallback);
 
1692
 
 
1693
        rc = mnt_context_umount(cxt);
 
1694
        if (rc)
 
1695
                printf("failed to umount\n");
 
1696
        else
 
1697
                printf("successfully umounted\n");
 
1698
err:
 
1699
        mnt_free_context(cxt);
 
1700
        return rc;
 
1701
}
 
1702
 
 
1703
int main(int argc, char *argv[])
 
1704
{
 
1705
        struct libmnt_test tss[] = {
 
1706
        { "--mount",  test_mount,  "[-o <opts>] [-t <type>] <spec>|<src> <target>" },
 
1707
        { "--umount", test_umount, "[-t <type>] [-f][-l][-r] <src>|<target>" },
 
1708
        { NULL }};
 
1709
 
 
1710
 
 
1711
        umask(S_IWGRP|S_IWOTH); /* to be compatible with mount(8) */
 
1712
 
 
1713
        return mnt_run_test(tss, argc, argv);
 
1714
}
 
1715
 
 
1716
#endif /* TEST_PROGRAM */