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

« back to all changes in this revision

Viewing changes to shlibs/mount/src/tab_update.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: update
10
 
 * @title: mtab managment
11
 
 * @short_description: userspace mount information management.
12
 
 *
13
 
 * The struct libmnt_update provides abstraction to manage mount options in userspace independently on
14
 
 * system configuration. This low-level API works on system with and without /etc/mtab. On 
15
 
 * systems without the regular /etc/mtab file are userspace mount options (e.g. user=)
16
 
 * stored to the /run/mount/utab file.
17
 
 *
18
 
 * It's recommended to use high-level struct libmnt_context API.
19
 
 */
20
 
 
21
 
#include <stdio.h>
22
 
#include <stdlib.h>
23
 
#include <sys/types.h>
24
 
#include <sys/stat.h>
25
 
#include <sys/file.h>
26
 
#include <fcntl.h>
27
 
#include <unistd.h>
28
 
#include <string.h>
29
 
#include <errno.h>
30
 
#include <signal.h>
31
 
 
32
 
#include "c.h"
33
 
#include "mountP.h"
34
 
#include "mangle.h"
35
 
#include "pathnames.h"
36
 
 
37
 
struct libmnt_update {
38
 
        char            *target;
39
 
        struct libmnt_fs *fs;
40
 
        char            *filename;
41
 
        unsigned long   mountflags;
42
 
        int             userspace_only;
43
 
        int             ready;
44
 
 
45
 
        sigset_t        oldsigmask;
46
 
        int             utab_lock;
47
 
};
48
 
 
49
 
static int utab_new_entry(struct libmnt_fs *fs, unsigned long mountflags, struct libmnt_fs **ent);
50
 
static int set_fs_root(struct libmnt_fs *result, struct libmnt_fs *fs, unsigned long mountflags);
51
 
 
52
 
/**
53
 
 * mnt_new_update:
54
 
 *
55
 
 * Returns: newly allocated update handler
56
 
 */
57
 
struct libmnt_update *mnt_new_update(void)
58
 
{
59
 
        struct libmnt_update *upd;
60
 
 
61
 
        upd = calloc(1, sizeof(*upd));
62
 
        if (!upd)
63
 
                return NULL;
64
 
 
65
 
        upd->utab_lock = -1;
66
 
        DBG(UPDATE, mnt_debug_h(upd, "allocate"));
67
 
        return upd;
68
 
}
69
 
 
70
 
/**
71
 
 * mnt_free_update:
72
 
 * @upd: update
73
 
 *
74
 
 * Deallocates struct libmnt_update handler.
75
 
 */
76
 
void mnt_free_update(struct libmnt_update *upd)
77
 
{
78
 
        if (!upd)
79
 
                return;
80
 
 
81
 
        DBG(UPDATE, mnt_debug_h(upd, "free"));
82
 
 
83
 
        mnt_free_fs(upd->fs);
84
 
        free(upd->target);
85
 
        free(upd->filename);
86
 
        free(upd);
87
 
}
88
 
 
89
 
/*
90
 
 * Returns 0 on success, <0 in case of error.
91
 
 */
92
 
int mnt_update_set_filename(struct libmnt_update *upd, const char *filename,
93
 
                            int userspace_only)
94
 
{
95
 
        const char *path = NULL;
96
 
        int rw = 0;
97
 
 
98
 
        assert(upd);
99
 
 
100
 
        /* filename explicitly defined */
101
 
        if (filename) {
102
 
                char *p = strdup(filename);
103
 
                if (!p)
104
 
                        return -ENOMEM;
105
 
 
106
 
                upd->userspace_only = userspace_only;
107
 
                free(upd->filename);
108
 
                upd->filename = p;
109
 
        }
110
 
 
111
 
        if (upd->filename)
112
 
                return 0;
113
 
 
114
 
        /* detect tab filename -- /etc/mtab or /run/mount/utab
115
 
         */
116
 
        mnt_has_regular_mtab(&path, &rw);
117
 
        if (!rw) {
118
 
                path = NULL;
119
 
                mnt_has_regular_utab(&path, &rw);
120
 
                if (!rw)
121
 
                        return -EACCES;
122
 
                upd->userspace_only = TRUE;
123
 
        }
124
 
        upd->filename = strdup(path);
125
 
        if (!upd->filename)
126
 
                return -ENOMEM;
127
 
 
128
 
        return 0;
129
 
}
130
 
 
131
 
/**
132
 
 * mnt_update_get_filename:
133
 
 * @upd: update
134
 
 *
135
 
 * This function returns file name (e.g. /etc/mtab) if the update
136
 
 * should be covered by mnt_lock, otherwise returne NULL.
137
 
 *
138
 
 * Returns: pointer to filename that will be updated or NULL in case of error.
139
 
 */
140
 
const char *mnt_update_get_filename(struct libmnt_update *upd)
141
 
{
142
 
        return upd && !upd->userspace_only ? upd->filename : NULL;
143
 
}
144
 
 
145
 
/**
146
 
 * mnt_update_is_ready:
147
 
 * @upd: update handler
148
 
 *
149
 
 * Returns: 1 if entry described by @upd is successfully prepared and will be
150
 
 * written to mtab/utab file.
151
 
 */
152
 
int mnt_update_is_ready(struct libmnt_update *upd)
153
 
{
154
 
        return upd ? upd->ready : FALSE;
155
 
}
156
 
 
157
 
/**
158
 
 * mnt_update_set_fs:
159
 
 * @upd: update handler
160
 
 * @mountflags: MS_* flags
161
 
 * @target: umount target, must be num for mount
162
 
 * @fs: mount filesystem description, must be NULL for umount
163
 
 *
164
 
 * Returns: <0 in case on error, 0 on success, 1 if update is unnecessary.
165
 
 */
166
 
int mnt_update_set_fs(struct libmnt_update *upd, unsigned long mountflags,
167
 
                      const char *target, struct libmnt_fs *fs)
168
 
{
169
 
        int rc;
170
 
 
171
 
        assert(upd);
172
 
        assert(target || fs);
173
 
 
174
 
        if (!upd)
175
 
                return -EINVAL;
176
 
        if ((mountflags & MS_MOVE) && (!fs || !mnt_fs_get_srcpath(fs)))
177
 
                return -EINVAL;
178
 
        if (target && fs)
179
 
                return -EINVAL;
180
 
 
181
 
        DBG(UPDATE, mnt_debug_h(upd,
182
 
                        "reseting FS [fs=0x%p, target=%s, flags=0x%08lx]",
183
 
                        fs, target, mountflags));
184
 
        if (fs) {
185
 
                DBG(UPDATE, mnt_debug_h(upd, "FS template:"));
186
 
                DBG(UPDATE, mnt_fs_print_debug(fs, stderr));
187
 
        }
188
 
 
189
 
        mnt_free_fs(upd->fs);
190
 
        free(upd->target);
191
 
        upd->ready = FALSE;
192
 
        upd->fs = NULL;
193
 
        upd->target = NULL;
194
 
        upd->mountflags = 0;
195
 
 
196
 
        if (mountflags & MS_PROPAGATION)
197
 
                return 1;
198
 
 
199
 
        upd->mountflags = mountflags;
200
 
 
201
 
        rc = mnt_update_set_filename(upd, NULL, 0);
202
 
        if (rc) {
203
 
                DBG(UPDATE, mnt_debug_h(upd, "no writable file available [rc=%d]", rc));
204
 
                return rc;      /* error or no file available (rc = 1) */
205
 
        }
206
 
        if (target) {
207
 
                upd->target = strdup(target);
208
 
                if (!upd->target)
209
 
                        return -ENOMEM;
210
 
 
211
 
        } else if (fs) {
212
 
                if (upd->userspace_only && !(mountflags & MS_MOVE)) {
213
 
                        int rc = utab_new_entry(fs, mountflags, &upd->fs);
214
 
                        if (rc)
215
 
                                return rc;
216
 
                } else {
217
 
                        upd->fs = mnt_copy_mtab_fs(fs);
218
 
                        if (!upd->fs)
219
 
                                return -ENOMEM;
220
 
 
221
 
                }
222
 
        }
223
 
 
224
 
 
225
 
        DBG(UPDATE, mnt_debug_h(upd, "ready"));
226
 
        upd->ready = TRUE;
227
 
        return 0;
228
 
}
229
 
 
230
 
/**
231
 
 * mnt_update_get_fs:
232
 
 * @upd: update
233
 
 *
234
 
 * Returns: update filesystem entry or NULL
235
 
 */
236
 
struct libmnt_fs *mnt_update_get_fs(struct libmnt_update *upd)
237
 
{
238
 
        return upd ? upd->fs : NULL;
239
 
}
240
 
 
241
 
/**
242
 
 * mnt_update_get_mflags:
243
 
 * @upd: update
244
 
 *
245
 
 * Returns: mount flags as was set by mnt_update_set_fs()
246
 
 */
247
 
unsigned long mnt_update_get_mflags(struct libmnt_update *upd)
248
 
{
249
 
        return upd ? upd->mountflags : 0;
250
 
}
251
 
 
252
 
/**
253
 
 * mnt_update_force_rdonly:
254
 
 * @upd: update
255
 
 * @rdonly: is read-only?
256
 
 *
257
 
 * Returns: 0 on success and negative number in case of error.
258
 
 */
259
 
int mnt_update_force_rdonly(struct libmnt_update *upd, int rdonly)
260
 
{
261
 
        int rc = 0;
262
 
 
263
 
        if (!upd || !upd->fs)
264
 
                return -EINVAL;
265
 
 
266
 
        if (rdonly && (upd->mountflags & MS_RDONLY))
267
 
                return 0;
268
 
        if (!rdonly && !(upd->mountflags & MS_RDONLY))
269
 
                return 0;
270
 
 
271
 
        if (!upd->userspace_only) {
272
 
                /* /etc/mtab -- we care about VFS options there */
273
 
                const char *o = mnt_fs_get_vfs_options(upd->fs);
274
 
                char *n = o ? strdup(o) : NULL;
275
 
 
276
 
                if (n)
277
 
                        mnt_optstr_remove_option(&n, rdonly ? "rw" : "ro");
278
 
                if (!mnt_optstr_prepend_option(&n, rdonly ? "ro" : "rw", NULL))
279
 
                        rc = mnt_fs_set_vfs_options(upd->fs, n);
280
 
 
281
 
                free(n);
282
 
        }
283
 
 
284
 
        if (rdonly)
285
 
                upd->mountflags &= ~MS_RDONLY;
286
 
        else
287
 
                upd->mountflags |= MS_RDONLY;
288
 
 
289
 
        return rc;
290
 
}
291
 
 
292
 
/*
293
 
 * Allocates (but does not write) utab entry for mount/remount. This function
294
 
 * should be called *before* mount(2) syscall.
295
 
 *
296
 
 * Returns: 0 on success, negative number on error, 1 if utabs update is
297
 
 *          unnecessary.
298
 
 */
299
 
static int utab_new_entry(struct libmnt_fs *fs, unsigned long mountflags, struct libmnt_fs **ent)
300
 
{
301
 
        int rc = 0;
302
 
        const char *o = NULL, *a = NULL;
303
 
        char *u = NULL;
304
 
 
305
 
        assert(fs);
306
 
        assert(ent);
307
 
        assert(!(mountflags & MS_MOVE));
308
 
 
309
 
        if (!fs || !ent)
310
 
                return -EINVAL;
311
 
        *ent = NULL;
312
 
 
313
 
        DBG(UPDATE, mnt_debug("prepare utab entry"));
314
 
 
315
 
        o = mnt_fs_get_user_options(fs);
316
 
        a = mnt_fs_get_attributes(fs);
317
 
 
318
 
        if (o) {
319
 
                /* remove non-mtab options */
320
 
                rc = mnt_optstr_get_options(o, &u,
321
 
                                mnt_get_builtin_optmap(MNT_USERSPACE_MAP),
322
 
                                MNT_NOMTAB);
323
 
                if (rc)
324
 
                        goto err;
325
 
        }
326
 
 
327
 
        if (!u && !a) {
328
 
                DBG(UPDATE, mnt_debug("utab entry unnecessary (no options)"));
329
 
                return 1;
330
 
        }
331
 
 
332
 
        /* allocate the entry */
333
 
        *ent = mnt_copy_fs(NULL, fs);
334
 
        if (!*ent) {
335
 
                rc = -ENOMEM;
336
 
                goto err;
337
 
        }
338
 
 
339
 
        rc = mnt_fs_set_user_options(*ent, u);
340
 
        if (rc)
341
 
                goto err;
342
 
        rc = mnt_fs_set_attributes(*ent, a);
343
 
        if (rc)
344
 
                goto err;
345
 
 
346
 
        if (!(mountflags & MS_REMOUNT)) {
347
 
                rc = set_fs_root(*ent, fs, mountflags);
348
 
                if (rc)
349
 
                        goto err;
350
 
        }
351
 
 
352
 
        free(u);
353
 
        DBG(UPDATE, mnt_debug("utab entry OK"));
354
 
        return 0;
355
 
err:
356
 
        mnt_free_fs(*ent);
357
 
        free(u);
358
 
        *ent = NULL;
359
 
        return rc;
360
 
}
361
 
 
362
 
static int set_fs_root(struct libmnt_fs *result, struct libmnt_fs *fs, unsigned long mountflags)
363
 
{
364
 
        char *root = NULL, *mnt = NULL;
365
 
        const char *fstype;
366
 
        struct libmnt_table *tb = NULL;
367
 
        int rc = -ENOMEM;
368
 
 
369
 
        assert(fs);
370
 
        assert(result);
371
 
 
372
 
        DBG(UPDATE, mnt_debug("setting FS root"));
373
 
 
374
 
        fstype = mnt_fs_get_fstype(fs);
375
 
 
376
 
        /*
377
 
         * bind-mount -- get fs-root and source device for the source filesystem
378
 
         */
379
 
        if (mountflags & MS_BIND) {
380
 
                const char *src, *src_root;
381
 
                struct libmnt_fs *src_fs;
382
 
 
383
 
                DBG(UPDATE, mnt_debug("setting FS root: bind"));
384
 
 
385
 
                src = mnt_fs_get_srcpath(fs);
386
 
                if (src) {
387
 
                        rc = mnt_fs_set_bindsrc(result, src);
388
 
                        if (rc)
389
 
                                goto err;
390
 
                        mnt = mnt_get_mountpoint(src);
391
 
                }
392
 
                if (!mnt) {
393
 
                        rc = -EINVAL;
394
 
                        goto err;
395
 
                }
396
 
                root = mnt_get_fs_root(src, mnt);
397
 
 
398
 
                tb = __mnt_new_table_from_file(_PATH_PROC_MOUNTINFO, MNT_FMT_MOUNTINFO);
399
 
                if (!tb) {
400
 
                        DBG(UPDATE, mnt_debug("failed to parse mountinfo -- using default"));
401
 
                        goto dflt;
402
 
                }
403
 
                src_fs = mnt_table_find_target(tb, mnt, MNT_ITER_BACKWARD);
404
 
                if (!src_fs)  {
405
 
                        DBG(UPDATE, mnt_debug("not found '%s' in mountinfo -- using default", mnt));
406
 
                        goto dflt;
407
 
                }
408
 
 
409
 
                /* set device name and fs */
410
 
                src = mnt_fs_get_srcpath(src_fs);
411
 
                rc = mnt_fs_set_source(result, src);
412
 
                if (rc)
413
 
                        goto err;
414
 
 
415
 
                mnt_fs_set_fstype(result, mnt_fs_get_fstype(src_fs));
416
 
 
417
 
                /* on btrfs the subvolume is used as fs-root in
418
 
                 * /proc/self/mountinfo, so we have get the original subvolume
419
 
                 * name from src_fs and prepend the subvolume name to the
420
 
                 * fs-root path
421
 
                 */
422
 
                src_root = mnt_fs_get_root(src_fs);
423
 
                if (src_root && !startswith(root, src_root)) {
424
 
                        size_t sz = strlen(root) + strlen(src_root) + 1;
425
 
                        char *tmp = malloc(sz);
426
 
 
427
 
                        if (!tmp)
428
 
                                goto err;
429
 
                        snprintf(tmp, sz, "%s%s", src_root, root);
430
 
                        free(root);
431
 
                        root = tmp;
432
 
                }
433
 
        }
434
 
 
435
 
        /*
436
 
         * btrfs-subvolume mount -- get subvolume name and use it as a root-fs path
437
 
         */
438
 
        else if (fstype && !strcmp(fstype, "btrfs")) {
439
 
                char *vol = NULL, *p;
440
 
                size_t sz, volsz = 0;
441
 
 
442
 
                if (mnt_fs_get_option(fs, "subvol", &vol, &volsz))
443
 
                        goto dflt;
444
 
 
445
 
                DBG(UPDATE, mnt_debug("setting FS root: btrfs subvol"));
446
 
 
447
 
                sz = volsz;
448
 
                if (*vol != '/')
449
 
                        sz++;
450
 
                root = malloc(sz + 1);
451
 
                if (!root)
452
 
                        goto err;
453
 
                p = root;
454
 
                if (*vol != '/')
455
 
                        *p++ = '/';
456
 
                memcpy(p, vol, volsz);
457
 
                *(root + sz) = '\0';
458
 
        }
459
 
dflt:
460
 
        mnt_free_table(tb);
461
 
        if (!root) {
462
 
                root = strdup("/");
463
 
                if (!root)
464
 
                        goto err;
465
 
        }
466
 
        result->root = root;
467
 
 
468
 
        DBG(UPDATE, mnt_debug("FS root result: %s", root));
469
 
 
470
 
        free(mnt);
471
 
        return 0;
472
 
err:
473
 
        free(root);
474
 
        free(mnt);
475
 
        return rc;
476
 
}
477
 
 
478
 
/* mtab and fstab update -- returns zero on success
479
 
 */
480
 
static int fprintf_mtab_fs(FILE *f, struct libmnt_fs *fs)
481
 
{
482
 
        char *o;
483
 
        char *m1, *m2, *m3, *m4;
484
 
        int rc;
485
 
 
486
 
        assert(fs);
487
 
        assert(f);
488
 
 
489
 
        o = mnt_fs_strdup_options(fs);
490
 
        if (!o)
491
 
                return -ENOMEM;
492
 
 
493
 
        m1 = mangle(mnt_fs_get_source(fs));
494
 
        m2 = mangle(mnt_fs_get_target(fs));
495
 
        m3 = mangle(mnt_fs_get_fstype(fs));
496
 
        m4 = mangle(o);
497
 
 
498
 
        if (m1 && m2 && m3 && m4) {
499
 
                rc = fprintf(f, "%s %s %s %s %d %d\n",
500
 
                                m1, m2, m3, m4,
501
 
                                mnt_fs_get_freq(fs),
502
 
                                mnt_fs_get_passno(fs));
503
 
                if (rc > 0)
504
 
                        rc = 0;
505
 
        } else
506
 
                rc = -ENOMEM;
507
 
 
508
 
        free(o);
509
 
        free(m1);
510
 
        free(m2);
511
 
        free(m3);
512
 
        free(m4);
513
 
 
514
 
        return rc;
515
 
}
516
 
 
517
 
static int fprintf_utab_fs(FILE *f, struct libmnt_fs *fs)
518
 
{
519
 
        char *p;
520
 
        int rc = 0;
521
 
 
522
 
        assert(fs);
523
 
        assert(f);
524
 
 
525
 
        if (!fs || !f)
526
 
                return -EINVAL;
527
 
 
528
 
        p = mangle(mnt_fs_get_source(fs));
529
 
        if (p) {
530
 
                rc = fprintf(f, "SRC=%s ", p);
531
 
                free(p);
532
 
        }
533
 
        if (rc >= 0) {
534
 
                p = mangle(mnt_fs_get_target(fs));
535
 
                if (p) {
536
 
                        rc = fprintf(f, "TARGET=%s ", p);
537
 
                        free(p);
538
 
                }
539
 
        }
540
 
        if (rc >= 0) {
541
 
                p = mangle(mnt_fs_get_root(fs));
542
 
                if (p) {
543
 
                        rc = fprintf(f, "ROOT=%s ", p);
544
 
                        free(p);
545
 
                }
546
 
        }
547
 
        if (rc >= 0) {
548
 
                p = mangle(mnt_fs_get_bindsrc(fs));
549
 
                if (p) {
550
 
                        rc = fprintf(f, "BINDSRC=%s ", p);
551
 
                        free(p);
552
 
                }
553
 
        }
554
 
        if (rc >= 0) {
555
 
                p = mangle(mnt_fs_get_attributes(fs));
556
 
                if (p) {
557
 
                        rc = fprintf(f, "ATTRS=%s ", p);
558
 
                        free(p);
559
 
                }
560
 
        }
561
 
        if (rc >= 0) {
562
 
                p = mangle(mnt_fs_get_user_options(fs));
563
 
                if (p) {
564
 
                        rc = fprintf(f, "OPTS=%s", p);
565
 
                        free(p);
566
 
                }
567
 
        }
568
 
        if (rc >= 0)
569
 
                rc = fprintf(f, "\n");
570
 
 
571
 
        if (rc > 0)
572
 
                rc = 0; /* success */
573
 
        return rc;
574
 
}
575
 
 
576
 
static int update_table(struct libmnt_update *upd, struct libmnt_table *tb)
577
 
{
578
 
        FILE *f;
579
 
        int rc, fd;
580
 
        char *uq = NULL;
581
 
 
582
 
        if (!tb || !upd->filename)
583
 
                return -EINVAL;
584
 
 
585
 
        DBG(UPDATE, mnt_debug_h(upd, "%s: updating", upd->filename));
586
 
 
587
 
        fd = mnt_open_uniq_filename(upd->filename, &uq);
588
 
        if (fd < 0)
589
 
                return fd;      /* error */
590
 
 
591
 
        f = fdopen(fd, "w");
592
 
        if (f) {
593
 
                struct stat st;
594
 
                struct libmnt_iter itr;
595
 
                struct libmnt_fs *fs;
596
 
                int fd;
597
 
 
598
 
                mnt_reset_iter(&itr, MNT_ITER_FORWARD);
599
 
                while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
600
 
                        if (upd->userspace_only)
601
 
                                rc = fprintf_utab_fs(f, fs);
602
 
                        else
603
 
                                rc = fprintf_mtab_fs(f, fs);
604
 
                        if (rc) {
605
 
                                DBG(UPDATE, mnt_debug_h(upd,
606
 
                                        "%s: write entry failed: %m", uq));
607
 
                                goto leave;
608
 
                        }
609
 
                }
610
 
 
611
 
                if (fflush(f) != 0) {
612
 
                        rc = -errno;
613
 
                        DBG(UPDATE, mnt_debug_h(upd, "%s: fflush failed: %m", uq));
614
 
                        goto leave;
615
 
                }
616
 
 
617
 
                fd = fileno(f);
618
 
                rc = fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) ? -errno : 0;
619
 
 
620
 
                if (!rc && stat(upd->filename, &st) == 0)
621
 
                        /* Copy uid/gid from the present file before renaming. */
622
 
                        rc = fchown(fd, st.st_uid, st.st_gid) ? -errno : 0;
623
 
 
624
 
                fclose(f);
625
 
                rc = rename(uq, upd->filename) ? -errno : 0;
626
 
        } else {
627
 
                rc = -errno;
628
 
                close(fd);
629
 
        }
630
 
 
631
 
leave:
632
 
        unlink(uq);     /* be paranoid */
633
 
        free(uq);
634
 
        return rc;
635
 
}
636
 
 
637
 
static int utab_lock(struct libmnt_update *upd)
638
 
{
639
 
        char *lfile;
640
 
        int rc;
641
 
        sigset_t sigs;
642
 
 
643
 
        assert(upd);
644
 
        assert(upd->filename);
645
 
        assert(upd->userspace_only);
646
 
 
647
 
        if (asprintf(&lfile, "%s.lock", upd->filename) == -1)
648
 
                return -1;
649
 
 
650
 
        DBG(UPDATE, mnt_debug("%s: locking", lfile));
651
 
 
652
 
        sigemptyset(&upd->oldsigmask);
653
 
        sigfillset(&sigs);
654
 
        sigprocmask(SIG_BLOCK, &sigs, &upd->oldsigmask);
655
 
 
656
 
        upd->utab_lock = open(lfile, O_RDONLY|O_CREAT|O_CLOEXEC, S_IWUSR|
657
 
                                     S_IRUSR|S_IRGRP|S_IROTH);
658
 
        free(lfile);
659
 
 
660
 
        if (upd->utab_lock < 0) {
661
 
                rc = -errno;
662
 
                goto err;
663
 
        }
664
 
 
665
 
        while (flock(upd->utab_lock, LOCK_EX) < 0) {
666
 
                int errsv;
667
 
                if (errno == EINTR)
668
 
                        continue;
669
 
                errsv = errno;
670
 
                close(upd->utab_lock);
671
 
                upd->utab_lock = -1;
672
 
                rc = -errsv;
673
 
                goto err;
674
 
        }
675
 
        return 0;
676
 
err:
677
 
        sigprocmask(SIG_SETMASK, &upd->oldsigmask, NULL);
678
 
        return rc;
679
 
}
680
 
 
681
 
static void utab_unlock(struct libmnt_update *upd)
682
 
{
683
 
        assert(upd);
684
 
        assert(upd->userspace_only);
685
 
 
686
 
        if (upd->utab_lock >= 0) {
687
 
                DBG(UPDATE, mnt_debug("unlocking utab"));
688
 
                close(upd->utab_lock);
689
 
                upd->utab_lock = -1;
690
 
                sigprocmask(SIG_SETMASK, &upd->oldsigmask, NULL);
691
 
        }
692
 
}
693
 
 
694
 
static int update_add_entry(struct libmnt_update *upd, struct libmnt_lock *lc)
695
 
{
696
 
        struct libmnt_table *tb;
697
 
        int rc = 0;
698
 
 
699
 
        assert(upd);
700
 
        assert(upd->fs);
701
 
 
702
 
        DBG(UPDATE, mnt_debug_h(upd, "%s: add entry", upd->filename));
703
 
 
704
 
        if (upd->userspace_only)
705
 
                rc = utab_lock(upd);
706
 
        else if (lc)
707
 
                rc = mnt_lock_file(lc);
708
 
        if (rc)
709
 
                return rc;
710
 
 
711
 
        tb = __mnt_new_table_from_file(upd->filename,
712
 
                        upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB);
713
 
        if (tb) {
714
 
                struct libmnt_fs *fs = mnt_copy_fs(NULL, upd->fs);
715
 
                if (!fs)
716
 
                        rc = -ENOMEM;
717
 
                else {
718
 
                        mnt_table_add_fs(tb, fs);
719
 
                        rc = update_table(upd, tb);
720
 
                }
721
 
        }
722
 
 
723
 
        if (upd->userspace_only)
724
 
                utab_unlock(upd);
725
 
        else if (lc)
726
 
                mnt_unlock_file(lc);
727
 
 
728
 
        mnt_free_table(tb);
729
 
        return rc;
730
 
}
731
 
 
732
 
static int update_remove_entry(struct libmnt_update *upd, struct libmnt_lock *lc)
733
 
{
734
 
        struct libmnt_table *tb;
735
 
        int rc = 0;
736
 
 
737
 
        assert(upd);
738
 
        assert(upd->target);
739
 
 
740
 
        DBG(UPDATE, mnt_debug_h(upd, "%s: remove entry", upd->filename));
741
 
 
742
 
        if (upd->userspace_only)
743
 
                rc = utab_lock(upd);
744
 
        else if (lc)
745
 
                rc = mnt_lock_file(lc);
746
 
        if (rc)
747
 
                return rc;
748
 
 
749
 
        tb = __mnt_new_table_from_file(upd->filename,
750
 
                        upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB);
751
 
        if (tb) {
752
 
                struct libmnt_fs *rem = mnt_table_find_target(tb, upd->target, MNT_ITER_BACKWARD);
753
 
                if (rem) {
754
 
                        mnt_table_remove_fs(tb, rem);
755
 
                        rc = update_table(upd, tb);
756
 
                        mnt_free_fs(rem);
757
 
                }
758
 
        }
759
 
 
760
 
        if (upd->userspace_only)
761
 
                utab_unlock(upd);
762
 
        else if (lc)
763
 
                mnt_unlock_file(lc);
764
 
 
765
 
        mnt_free_table(tb);
766
 
        return rc;
767
 
}
768
 
 
769
 
static int update_modify_target(struct libmnt_update *upd, struct libmnt_lock *lc)
770
 
{
771
 
        struct libmnt_table *tb = NULL;
772
 
        int rc = 0;
773
 
 
774
 
        DBG(UPDATE, mnt_debug_h(upd, "%s: modify target", upd->filename));
775
 
 
776
 
        if (upd->userspace_only)
777
 
                rc = utab_lock(upd);
778
 
        else if (lc)
779
 
                rc = mnt_lock_file(lc);
780
 
        if (rc)
781
 
                return rc;
782
 
 
783
 
        tb = __mnt_new_table_from_file(upd->filename,
784
 
                        upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB);
785
 
        if (tb) {
786
 
                struct libmnt_fs *cur = mnt_table_find_target(tb,
787
 
                                mnt_fs_get_srcpath(upd->fs), MNT_ITER_BACKWARD);
788
 
                if (cur) {
789
 
                        rc = mnt_fs_set_target(cur, mnt_fs_get_target(upd->fs));
790
 
                        if (!rc)
791
 
                                rc = update_table(upd, tb);
792
 
                }
793
 
        }
794
 
 
795
 
        if (upd->userspace_only)
796
 
                utab_unlock(upd);
797
 
        else if (lc)
798
 
                mnt_unlock_file(lc);
799
 
 
800
 
        mnt_free_table(tb);
801
 
        return rc;
802
 
}
803
 
 
804
 
static int update_modify_options(struct libmnt_update *upd, struct libmnt_lock *lc)
805
 
{
806
 
        struct libmnt_table *tb = NULL;
807
 
        int rc = 0;
808
 
        struct libmnt_fs *fs;
809
 
 
810
 
        assert(upd);
811
 
        assert(upd->fs);
812
 
 
813
 
        DBG(UPDATE, mnt_debug_h(upd, "%s: modify options", upd->filename));
814
 
 
815
 
        fs = upd->fs;
816
 
 
817
 
        if (upd->userspace_only)
818
 
                rc = utab_lock(upd);
819
 
        else if (lc)
820
 
                rc = mnt_lock_file(lc);
821
 
        if (rc)
822
 
                return rc;
823
 
 
824
 
        tb = __mnt_new_table_from_file(upd->filename,
825
 
                        upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB);
826
 
        if (tb) {
827
 
                struct libmnt_fs *cur = mnt_table_find_target(tb,
828
 
                                        mnt_fs_get_target(fs),
829
 
                                        MNT_ITER_BACKWARD);
830
 
                if (cur) {
831
 
                        if (upd->userspace_only)
832
 
                                rc = mnt_fs_set_attributes(cur, mnt_fs_get_attributes(fs));
833
 
                        if (!rc && !upd->userspace_only)
834
 
                                rc = mnt_fs_set_vfs_options(cur, mnt_fs_get_vfs_options(fs));
835
 
                        if (!rc && !upd->userspace_only)
836
 
                                rc = mnt_fs_set_fs_options(cur, mnt_fs_get_fs_options(fs));
837
 
                        if (!rc)
838
 
                                rc = mnt_fs_set_user_options(cur,
839
 
                                                mnt_fs_get_user_options(fs));
840
 
                        if (!rc)
841
 
                                rc = update_table(upd, tb);
842
 
                }
843
 
        }
844
 
 
845
 
        if (upd->userspace_only)
846
 
                utab_unlock(upd);
847
 
        else if (lc)
848
 
                mnt_unlock_file(lc);
849
 
 
850
 
        mnt_free_table(tb);
851
 
        return rc;
852
 
}
853
 
 
854
 
/**
855
 
 * mnt_update_table:
856
 
 * @upd: update
857
 
 * @lc: lock or NULL
858
 
 *
859
 
 * High-level API to update /etc/mtab (or private /run/mount/utab file).
860
 
 *
861
 
 * The @lc lock is optional and will be created if necessary. Note that
862
 
 * the automatically created lock blocks all signals.
863
 
 *
864
 
 * See also mnt_lock_block_signals() and mnt_context_get_lock().
865
 
 *
866
 
 * Returns: 0 on success, negative number on error.
867
 
 */
868
 
int mnt_update_table(struct libmnt_update *upd, struct libmnt_lock *lc)
869
 
{
870
 
        struct libmnt_lock *lc0 = lc;
871
 
        int rc = -EINVAL;
872
 
 
873
 
        assert(upd);
874
 
 
875
 
        if (!upd->filename || !upd)
876
 
                return -EINVAL;
877
 
        if (!upd->ready)
878
 
                return 0;
879
 
 
880
 
        DBG(UPDATE, mnt_debug_h(upd, "%s: update tab", upd->filename));
881
 
        if (upd->fs) {
882
 
                DBG(UPDATE, mnt_fs_print_debug(upd->fs, stderr));
883
 
        }
884
 
        if (!lc && !upd->userspace_only) {
885
 
                lc = mnt_new_lock(upd->filename, 0);
886
 
                if (lc)
887
 
                        mnt_lock_block_signals(lc, TRUE);
888
 
        }
889
 
 
890
 
        if (!upd->fs && upd->target)
891
 
                rc = update_remove_entry(upd, lc);      /* umount */
892
 
        else if (upd->mountflags & MS_MOVE)
893
 
                rc = update_modify_target(upd, lc);     /* move */
894
 
        else if (upd->mountflags & MS_REMOUNT)
895
 
                rc = update_modify_options(upd, lc);    /* remount */
896
 
        else if (upd->fs)
897
 
                rc = update_add_entry(upd, lc); /* mount */
898
 
 
899
 
        upd->ready = FALSE;
900
 
        DBG(UPDATE, mnt_debug_h(upd, "%s: update tab: done [rc=%d]",
901
 
                                upd->filename, rc));
902
 
 
903
 
        if (lc != lc0)
904
 
                 mnt_free_lock(lc);
905
 
 
906
 
        return rc;
907
 
}
908
 
 
909
 
#ifdef TEST_PROGRAM
910
 
 
911
 
static int update(const char *target, struct libmnt_fs *fs, unsigned long mountflags)
912
 
{
913
 
        int rc;
914
 
        struct libmnt_update *upd;
915
 
 
916
 
        DBG(UPDATE, mnt_debug("update test"));
917
 
 
918
 
        upd = mnt_new_update();
919
 
        if (!upd)
920
 
                return -ENOMEM;
921
 
 
922
 
        rc = mnt_update_set_fs(upd, mountflags, target, fs);
923
 
        if (rc == 1) {
924
 
                /* update is unnecessary */
925
 
                rc = 0;
926
 
                goto done;
927
 
        }
928
 
        if (rc) {
929
 
                fprintf(stderr, "failed to set FS\n");
930
 
                goto done;
931
 
        }
932
 
 
933
 
        /* [... here should be mount(2) call ...]  */
934
 
 
935
 
        rc = mnt_update_table(upd, NULL);
936
 
done:
937
 
        return rc;
938
 
}
939
 
 
940
 
static int test_add(struct libmnt_test *ts, int argc, char *argv[])
941
 
{
942
 
        struct libmnt_fs *fs = mnt_new_fs();
943
 
        int rc;
944
 
 
945
 
        if (argc < 5 || !fs)
946
 
                return -1;
947
 
        mnt_fs_set_source(fs, argv[1]);
948
 
        mnt_fs_set_target(fs, argv[2]);
949
 
        mnt_fs_set_fstype(fs, argv[3]);
950
 
        mnt_fs_set_options(fs, argv[4]);
951
 
 
952
 
        rc = update(NULL, fs, 0);
953
 
        mnt_free_fs(fs);
954
 
        return rc;
955
 
}
956
 
 
957
 
static int test_remove(struct libmnt_test *ts, int argc, char *argv[])
958
 
{
959
 
        if (argc < 2)
960
 
                return -1;
961
 
        return update(argv[1], NULL, 0);
962
 
}
963
 
 
964
 
static int test_move(struct libmnt_test *ts, int argc, char *argv[])
965
 
{
966
 
        struct libmnt_fs *fs = mnt_new_fs();
967
 
        int rc;
968
 
 
969
 
        if (argc < 3)
970
 
                return -1;
971
 
        mnt_fs_set_source(fs, argv[1]);
972
 
        mnt_fs_set_target(fs, argv[2]);
973
 
 
974
 
        rc = update(NULL, fs, MS_MOVE);
975
 
 
976
 
        mnt_free_fs(fs);
977
 
        return rc;
978
 
}
979
 
 
980
 
static int test_remount(struct libmnt_test *ts, int argc, char *argv[])
981
 
{
982
 
        struct libmnt_fs *fs = mnt_new_fs();
983
 
        int rc;
984
 
 
985
 
        if (argc < 3)
986
 
                return -1;
987
 
        mnt_fs_set_target(fs, argv[1]);
988
 
        mnt_fs_set_options(fs, argv[2]);
989
 
 
990
 
        rc = update(NULL, fs, MS_REMOUNT);
991
 
        mnt_free_fs(fs);
992
 
        return rc;
993
 
}
994
 
 
995
 
int main(int argc, char *argv[])
996
 
{
997
 
        struct libmnt_test tss[] = {
998
 
        { "--add",    test_add,     "<src> <target> <type> <options>  add line to mtab" },
999
 
        { "--remove", test_remove,  "<target>                      MS_REMOUNT mtab change" },
1000
 
        { "--move",   test_move,    "<old_target>  <target>        MS_MOVE mtab change" },
1001
 
        { "--remount",test_remount, "<target>  <options>           MS_REMOUNT mtab change" },
1002
 
        { NULL }
1003
 
        };
1004
 
 
1005
 
        return mnt_run_test(tss, argc, argv);
1006
 
}
1007
 
 
1008
 
#endif /* TEST_PROGRAM */