~ubuntu-branches/ubuntu/trusty/nilfs-tools/trusty

« back to all changes in this revision

Viewing changes to sbin/mount/mount_libmount.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Baumann
  • Date: 2011-08-12 20:42:38 UTC
  • mto: This revision was merged to the branch mainline in revision 11.
  • Revision ID: james.westby@ubuntu.com-20110812204238-3i5mnvvmg7amtyjm
Tags: upstream-2.1.0~rc2
ImportĀ upstreamĀ versionĀ 2.1.0~rc2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * mount_libmount.c - NILFS mount helper program (libmount version)
 
3
 *
 
4
 * Copyright (C) 2007-2011 Nippon Telegraph and Telephone Corporation.
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU General Public
 
8
 * License as published by the Free Software Foundation; either
 
9
 * version 2 of the License, or (at your option) any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
 * General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public
 
17
 * License along with this program; if not, write to the
 
18
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
19
 * Boston, MA 021110-1307, USA.
 
20
 *
 
21
 * Written by Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
 
22
 */
 
23
 
 
24
#ifdef HAVE_CONFIG_H
 
25
#include "config.h"
 
26
#endif  /* HAVE_CONFIG_H */
 
27
 
 
28
#if HAVE_SYS_TYPES_H
 
29
#include <sys/types.h>
 
30
#endif  /* HAVE_SYS_TYPES_H */
 
31
 
 
32
#include <stdio.h>
 
33
 
 
34
#if HAVE_STDLIB_H
 
35
#include <stdlib.h>
 
36
#endif  /* HAVE_STDLIB_H */
 
37
 
 
38
#if HAVE_UNISTD_H
 
39
#include <unistd.h>
 
40
#endif  /* HAVE_UNISTD_H */
 
41
 
 
42
#if HAVE_FCNTL_H
 
43
#include <fcntl.h>
 
44
#endif  /* HAVE_FCNTL_H */
 
45
 
 
46
#if HAVE_STRINGS_H
 
47
#include <strings.h>
 
48
#endif  /* HAVE_STRINGS_H */
 
49
 
 
50
#if HAVE_STRING_H
 
51
#include <string.h>
 
52
#endif  /* HAVE_STRING_H */
 
53
 
 
54
#if HAVE_SYS_IOCTL_H
 
55
#include <sys/ioctl.h>          /* ioctl() */
 
56
#endif  /* HAVE_SYS_IOCTL_H */
 
57
 
 
58
#if HAVE_SYS_MOUNT_H
 
59
#include <sys/mount.h>          /* BLKROGET */
 
60
#endif  /* HAVE_SYS_MOUNT_H */
 
61
 
 
62
#if HAVE_SYS_STAT_H
 
63
#include <sys/stat.h>
 
64
#endif  /* HAVE_SYS_STAT_H */
 
65
 
 
66
#if HAVE_SYSLOG_H
 
67
#include <syslog.h>
 
68
#endif  /* HAVE_SYSLOG_H */
 
69
 
 
70
#if HAVE_LIBMOUNT_LIBMOUNT_H
 
71
#include <libmount/libmount.h>
 
72
#endif  /* HAVE_LIBMOUNT_H */
 
73
 
 
74
#include <stdarg.h>
 
75
#include <errno.h>
 
76
#include <assert.h>
 
77
 
 
78
#include "sundries.h"
 
79
#include "xmalloc.h"
 
80
#include "mount.nilfs2.h"
 
81
#include "mount_attrs.h"
 
82
#include "cleaner_exec.h"
 
83
#include "nls.h"
 
84
 
 
85
#ifdef _GNU_SOURCE
 
86
#include <getopt.h>
 
87
#endif  /* _GNU_SOURCE */
 
88
 
 
89
/* mount options */
 
90
int mount_quiet = 0;    /* for sundries.c */
 
91
static int verbose = 0;
 
92
static int devro = 0;
 
93
 
 
94
static char *mount_fstype = NULL;
 
95
 
 
96
/* global variables */
 
97
const char fstype[] = NILFS2_FS_NAME;
 
98
char *progname = "mount." NILFS2_FS_NAME;
 
99
 
 
100
/* mount info */
 
101
struct nilfs_mount_info {
 
102
        struct libmnt_context *cxt;
 
103
        unsigned long mflags;
 
104
        int type;
 
105
        int mounted;
 
106
        struct nilfs_mount_attrs old_attrs;
 
107
        struct nilfs_mount_attrs new_attrs;
 
108
};
 
109
 
 
110
enum {
 
111
        NORMAL_MOUNT,
 
112
        RW2RO_REMOUNT,
 
113
        RW2RW_REMOUNT,
 
114
};
 
115
 
 
116
 
 
117
static void nilfs_mount_logger(int priority, const char *fmt, ...)
 
118
{
 
119
        va_list args;
 
120
 
 
121
        if ((verbose && priority > LOG_INFO) || priority >= LOG_INFO)
 
122
                return;
 
123
        va_start(args, fmt);
 
124
        fprintf(stderr, "%s: ", progname);
 
125
        vfprintf(stderr, fmt, args);
 
126
        fputs(_("\n"), stderr);
 
127
        va_end(args);
 
128
}
 
129
 
 
130
#if 0
 
131
static int nilfs_libmount_table_errcb(struct libmnt_table *tb,
 
132
                                      const char *filename, int line)
 
133
{
 
134
        if (filename)
 
135
                error(_("%s: parse error: ignore entry at line %d."),
 
136
                      filename, line);
 
137
        return 0;
 
138
}
 
139
#endif
 
140
 
 
141
/*
 
142
 * Other routines
 
143
 */
 
144
static int device_is_readonly(const char *device, int *ro)
 
145
{
 
146
        int fd, res = 0;
 
147
 
 
148
        fd = open(device, O_RDONLY);
 
149
        if (fd < 0)
 
150
                return -errno;
 
151
 
 
152
        if (ioctl(fd, BLKROGET, ro) < 0)
 
153
                res = -errno;
 
154
        close(fd);
 
155
        return res;
 
156
}
 
157
 
 
158
static void show_version(void)
 
159
{
 
160
        printf("%s (%s %s)\n", progname, PACKAGE, PACKAGE_VERSION);
 
161
}
 
162
 
 
163
static void nilfs_mount_parse_options(int argc, char *argv[],
 
164
                                      struct nilfs_mount_info *mi)
 
165
{
 
166
        struct libmnt_context *cxt = mi->cxt;
 
167
        struct libmnt_fs *fs;
 
168
        int c, show_version_only = 0;
 
169
 
 
170
        fs = mnt_context_get_fs(cxt);
 
171
        if (!fs)
 
172
                die(EX_SYSERR, _("failed to get fs"));
 
173
 
 
174
        while ((c = getopt(argc, argv, "fvnt:o:rwV")) != EOF) {
 
175
                switch (c) {
 
176
                case 'f':
 
177
                        mnt_context_enable_fake(cxt, 1);
 
178
                        break;
 
179
                case 'v':
 
180
                        mnt_context_enable_verbose(cxt, 1);
 
181
                        verbose = 1;
 
182
                        break;
 
183
                case 'n':
 
184
                        mnt_context_disable_mtab(cxt, 1);
 
185
                        break;
 
186
                case 't':
 
187
                        mount_fstype = optarg;
 
188
                        break;
 
189
                case 'o':
 
190
                {
 
191
                        char *rest;
 
192
 
 
193
                        if (nilfs_mount_attrs_parse(&mi->new_attrs, optarg,
 
194
                                                    NULL, &rest, 0))
 
195
                                die(EX_SYSERR, _("failed to parse options"));
 
196
                        if (rest && mnt_context_append_options(cxt, rest))
 
197
                                die(EX_SYSERR, _("failed to append options"));
 
198
                        free(rest);
 
199
                        break;
 
200
                }
 
201
                case 'r':
 
202
                        if (mnt_context_append_options(cxt, "ro"))
 
203
                                die(EX_SYSERR, _("failed to append options"));
 
204
                        break;
 
205
                case 'w':
 
206
                        if (mnt_context_append_options(cxt, "rw"))
 
207
                                die(EX_SYSERR, _("failed to append options"));
 
208
                        break;
 
209
                case 'V':
 
210
                        show_version_only = 1;
 
211
                        break;
 
212
                default:
 
213
                        break;
 
214
                }
 
215
        }
 
216
 
 
217
        if (show_version_only) {
 
218
                show_version();
 
219
                exit(0);
 
220
        }
 
221
}
 
222
 
 
223
static struct libmnt_fs *nilfs_find_rw_mount(struct libmnt_context *cxt,
 
224
                                             struct libmnt_table *mtab)
 
225
{
 
226
        struct libmnt_iter *iter = mnt_new_iter(MNT_ITER_BACKWARD);
 
227
        const char *src = mnt_context_get_source(cxt);
 
228
        const char *type = mnt_context_get_fstype(cxt);
 
229
        struct libmnt_fs *fs = NULL;
 
230
 
 
231
        if (!iter)
 
232
                die(EX_SYSERR, _("libmount iterator allocation failed"));
 
233
 
 
234
        while (mnt_table_next_fs(mtab, iter, &fs) == 0) {
 
235
                if (mnt_fs_match_fstype(fs, type) &&
 
236
                    mnt_fs_match_source(fs, src, mnt_table_get_cache(mtab)) &&
 
237
                    mnt_fs_match_options(fs, "rw"))
 
238
                        break;
 
239
        }
 
240
 
 
241
        mnt_free_iter(iter);
 
242
        return fs;
 
243
}
 
244
 
 
245
static int nilfs_prepare_mount(struct nilfs_mount_info *mi)
 
246
{
 
247
        struct libmnt_context *cxt = mi->cxt;
 
248
        struct libmnt_fs *fs;
 
249
        struct libmnt_table *mtab;
 
250
        const char *attrs;
 
251
        int res;
 
252
 
 
253
        res = mnt_context_prepare_mount(cxt);
 
254
        if (res < 0) {
 
255
                error(_("%s: preparing failed: %s"), progname,
 
256
                      strerror(-res));
 
257
                goto failed;
 
258
        }
 
259
        /*
 
260
         * mnt_context_prepare_mount() parses mtab (/etc/mtab or
 
261
         * /proc/self/mountinfo + /run/mount/utabs or /proc/mounts)
 
262
         */
 
263
 
 
264
        res = mnt_context_get_mflags(cxt, &mi->mflags);
 
265
        if (res < 0) {
 
266
                error(_("%s: get mount flags failed: %s"), progname,
 
267
                      strerror(-res));
 
268
                goto failed;
 
269
        }
 
270
 
 
271
        if (!(mi->mflags & MS_RDONLY) && !(mi->mflags & MS_BIND)) {
 
272
                res = device_is_readonly(mnt_context_get_source(cxt),
 
273
                                         &devro);
 
274
                if (res < 0) {
 
275
                        error(_("%s: device %s not accessible: %s"),
 
276
                              progname, mnt_context_get_source(cxt),
 
277
                              strerror(-res));
 
278
                        goto failed;
 
279
                }
 
280
        }
 
281
 
 
282
        res = mnt_context_get_mtab(cxt, &mtab);
 
283
        if (res < 0) {
 
284
                error(_("%s: libmount mount check failed: %s"),
 
285
                      progname, strerror(-res));
 
286
                goto failed;
 
287
        }
 
288
 
 
289
        mi->mounted = mnt_table_is_fs_mounted(mtab, mnt_context_get_fs(cxt));
 
290
 
 
291
        if (mi->mflags & MS_BIND)
 
292
                return 0;
 
293
 
 
294
        fs = nilfs_find_rw_mount(cxt, mtab);
 
295
        if (fs == NULL)
 
296
                return 0; /* no previous rw-mount */
 
297
 
 
298
        switch (mi->mflags & (MS_RDONLY | MS_REMOUNT)) {
 
299
        case 0: /* overlapping rw-mount */
 
300
                error(_("%s: the device already has a rw-mount on %s."
 
301
                        "\n\t\tmultiple rw-mount is not allowed."),
 
302
                      progname, mnt_fs_get_target(fs));
 
303
                goto failed;
 
304
        case MS_RDONLY: /* ro-mount (a rw-mount exists) */
 
305
                break;
 
306
        case MS_REMOUNT | MS_RDONLY: /* rw->ro remount */
 
307
        case MS_REMOUNT: /* rw->rw remount */
 
308
                mi->type = (mi->mflags & MS_RDONLY) ?
 
309
                        RW2RO_REMOUNT : RW2RW_REMOUNT;
 
310
 
 
311
                attrs = mnt_fs_get_attributes(fs);
 
312
                if (attrs) {
 
313
                        if (nilfs_mount_attrs_parse(&mi->old_attrs, attrs,
 
314
                                                    NULL, NULL, 1)) {
 
315
                                error(_("%s: libmount mount check failed: %s"),
 
316
                                      progname, strerror(-res));
 
317
                                goto failed;
 
318
                        }
 
319
                }
 
320
 
 
321
                if (!mnt_fs_match_target(fs, mnt_context_get_target(cxt),
 
322
                                         mnt_table_get_cache(mtab))) {
 
323
                        error(_("%s: different mount point (%s). "
 
324
                                "remount failed."),
 
325
                              progname, mnt_context_get_target(cxt));
 
326
                        goto failed;
 
327
                }
 
328
 
 
329
                if (mi->old_attrs.gcpid) {
 
330
                        res = nilfs_shutdown_cleanerd(
 
331
                                mnt_fs_get_source(fs), mi->old_attrs.gcpid);
 
332
                        if (res < 0) {
 
333
                                error(_("%s: remount failed due to %s "
 
334
                                        "shutdown failure"), progname,
 
335
                                      NILFS_CLEANERD_NAME);
 
336
                                goto failed;
 
337
                        }
 
338
                }
 
339
                break;
 
340
        }
 
341
 
 
342
        res = 0;
 
343
 failed:
 
344
        return res;
 
345
}
 
346
 
 
347
static int nilfs_do_mount_one(struct nilfs_mount_info *mi)
 
348
{
 
349
        struct libmnt_context *cxt = mi->cxt;
 
350
        int res, errsv;
 
351
 
 
352
        res = mnt_context_do_mount(cxt);
 
353
        if (!res)
 
354
                goto out;
 
355
 
 
356
        errsv = errno;
 
357
        switch (errsv) {
 
358
        case ENODEV:
 
359
                error(_("%s: cannot find or load %s filesystem"), progname,
 
360
                      fstype);
 
361
                break;
 
362
        default:
 
363
                error(_("%s: Error while mounting %s on %s: %s"), progname,
 
364
                      mnt_context_get_source(cxt),
 
365
                      mnt_context_get_target(cxt), strerror(errsv));
 
366
                break;
 
367
        }
 
368
        if (mi->type != RW2RO_REMOUNT && mi->type != RW2RW_REMOUNT)
 
369
                goto out;
 
370
 
 
371
        /* Cleaner daemon was stopped and it needs to run */
 
372
        /* because filesystem is still mounted */
 
373
        if (!mi->old_attrs.nogc) {
 
374
                struct nilfs_mount_attrs mattrs = { .pp = mi->old_attrs.pp };
 
375
 
 
376
                /* Restarting cleaner daemon */
 
377
                if (nilfs_launch_cleanerd(mnt_context_get_source(cxt),
 
378
                                          mnt_context_get_target(cxt),
 
379
                                          mattrs.pp, &mattrs.gcpid)) {
 
380
                        if (mnt_context_is_verbose(cxt))
 
381
                                printf(_("%s: restarted %s\n"),
 
382
                                       progname, NILFS_CLEANERD_NAME);
 
383
 
 
384
                        nilfs_mount_attrs_update(&mi->old_attrs, &mattrs, cxt);
 
385
                        mnt_context_finalize_mount(cxt);
 
386
                } else {
 
387
                        error(_("%s: failed to restart %s"),
 
388
                              progname, NILFS_CLEANERD_NAME);
 
389
                }
 
390
        } else {
 
391
                printf(_("%s not restarted\n"), NILFS_CLEANERD_NAME);
 
392
        }
 
393
out:
 
394
        return res;
 
395
}
 
396
 
 
397
static int nilfs_update_mount_state(struct nilfs_mount_info *mi)
 
398
{
 
399
        struct libmnt_context *cxt = mi->cxt;
 
400
        struct nilfs_mount_attrs *old_attrs;
 
401
        int rungc, gc_ok;
 
402
 
 
403
        gc_ok = !(mi->mflags & MS_RDONLY) && !(mi->mflags & MS_BIND);
 
404
        rungc = gc_ok && !mi->new_attrs.nogc;
 
405
        old_attrs = (mi->mflags & MS_REMOUNT) ? &mi->old_attrs : NULL;
 
406
 
 
407
        if (mnt_context_is_nomtab(cxt)) {
 
408
                if (rungc)
 
409
                        printf(_("%s not started\n"), NILFS_CLEANERD_NAME);
 
410
                return 0;
 
411
        }
 
412
 
 
413
        if (rungc) {
 
414
                if (mi->new_attrs.pp == ULONG_MAX)
 
415
                        mi->new_attrs.pp = mi->old_attrs.pp;
 
416
 
 
417
                if (nilfs_launch_cleanerd(mnt_context_get_source(cxt),
 
418
                                          mnt_context_get_target(cxt),
 
419
                                          mi->new_attrs.pp,
 
420
                                          &mi->new_attrs.gcpid) < 0)
 
421
                        error(_("%s aborted"), NILFS_CLEANERD_NAME);
 
422
                else if (mnt_context_is_verbose(cxt))
 
423
                        printf(_("%s: started %s\n"), progname,
 
424
                               NILFS_CLEANERD_NAME);
 
425
        }
 
426
 
 
427
        nilfs_mount_attrs_update(old_attrs, &mi->new_attrs, cxt);
 
428
 
 
429
        return mnt_context_finalize_mount(cxt);
 
430
}
 
431
 
 
432
static int nilfs_mount_one(struct nilfs_mount_info *mi)
 
433
{
 
434
        int res, err = EX_FAIL;
 
435
 
 
436
        res = nilfs_prepare_mount(mi);
 
437
        if (res)
 
438
                goto failed;
 
439
 
 
440
        if (!mnt_context_is_fake(mi->cxt)) {
 
441
                res = nilfs_do_mount_one(mi);
 
442
                if (res)
 
443
                        goto failed;
 
444
        }
 
445
        res = nilfs_update_mount_state(mi);
 
446
        if (!res)
 
447
                err = 0;
 
448
failed:
 
449
        return err;
 
450
}
 
451
 
 
452
int main(int argc, char *argv[])
 
453
{
 
454
        struct nilfs_mount_info mi = {0};
 
455
        char *device, *mntdir;
 
456
        int res = 0;
 
457
 
 
458
        if (argc > 0) {
 
459
                char *cp = strrchr(argv[0], '/');
 
460
 
 
461
                progname = (cp ? cp + 1 : argv[0]);
 
462
        }
 
463
 
 
464
        nilfs_cleaner_logger = nilfs_mount_logger;
 
465
 
 
466
        mi.type = NORMAL_MOUNT;
 
467
 
 
468
        mnt_init_debug(0);
 
469
        mi.cxt = mnt_new_context();
 
470
        if (!mi.cxt)
 
471
                die(EX_SYSERR, _("libmount context allocation failed"));
 
472
 
 
473
#if 0
 
474
        mnt_context_set_tables_errcb(mi.cxt, nilfs_libmount_table_errcb);
 
475
#endif
 
476
        mnt_context_set_fstype(mi.cxt, fstype);
 
477
        mnt_context_disable_helpers(mi.cxt, 1);
 
478
 
 
479
        nilfs_mount_attrs_init(&mi.old_attrs);
 
480
        nilfs_mount_attrs_init(&mi.new_attrs);
 
481
        nilfs_mount_parse_options(argc, argv, &mi);
 
482
 
 
483
        umask(022);
 
484
 
 
485
        if (optind >= argc || !argv[optind])
 
486
                die(EX_USAGE, _("No device specified"));
 
487
 
 
488
        device = argv[optind++];
 
489
        mnt_context_set_source(mi.cxt, device);
 
490
 
 
491
        if (optind >= argc || !argv[optind])
 
492
                die(EX_USAGE, _("No mountpoint specified"));
 
493
 
 
494
        mntdir = argv[optind++];
 
495
        mnt_context_set_target(mi.cxt, mntdir);
 
496
 
 
497
        if (mount_fstype && strncmp(mount_fstype, fstype, strlen(fstype)))
 
498
                die(EX_USAGE, _("Unknown filesystem (%s)"), mount_fstype);
 
499
 
 
500
        if (getuid() != geteuid())
 
501
                die(EX_USAGE,
 
502
                    _("%s: mount by non-root user is not supported yet"),
 
503
                    progname);
 
504
 
 
505
        res = nilfs_mount_one(&mi);
 
506
 
 
507
        mnt_free_context(mi.cxt);
 
508
        return res;
 
509
}