2
* mount_libmount.c - NILFS mount helper program (libmount version)
4
* Copyright (C) 2007-2011 Nippon Telegraph and Telephone Corporation.
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.
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.
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.
21
* Written by Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
26
#endif /* HAVE_CONFIG_H */
29
#include <sys/types.h>
30
#endif /* HAVE_SYS_TYPES_H */
36
#endif /* HAVE_STDLIB_H */
40
#endif /* HAVE_UNISTD_H */
44
#endif /* HAVE_FCNTL_H */
48
#endif /* HAVE_STRINGS_H */
52
#endif /* HAVE_STRING_H */
55
#include <sys/ioctl.h> /* ioctl() */
56
#endif /* HAVE_SYS_IOCTL_H */
59
#include <sys/mount.h> /* BLKROGET */
60
#endif /* HAVE_SYS_MOUNT_H */
64
#endif /* HAVE_SYS_STAT_H */
68
#endif /* HAVE_SYSLOG_H */
70
#if HAVE_LIBMOUNT_LIBMOUNT_H
71
#include <libmount/libmount.h>
72
#endif /* HAVE_LIBMOUNT_H */
80
#include "mount.nilfs2.h"
81
#include "mount_attrs.h"
82
#include "cleaner_exec.h"
87
#endif /* _GNU_SOURCE */
90
int mount_quiet = 0; /* for sundries.c */
91
static int verbose = 0;
94
static char *mount_fstype = NULL;
96
/* global variables */
97
const char fstype[] = NILFS2_FS_NAME;
98
char *progname = "mount." NILFS2_FS_NAME;
101
struct nilfs_mount_info {
102
struct libmnt_context *cxt;
103
unsigned long mflags;
106
struct nilfs_mount_attrs old_attrs;
107
struct nilfs_mount_attrs new_attrs;
117
static void nilfs_mount_logger(int priority, const char *fmt, ...)
121
if ((verbose && priority > LOG_INFO) || priority >= LOG_INFO)
124
fprintf(stderr, "%s: ", progname);
125
vfprintf(stderr, fmt, args);
126
fputs(_("\n"), stderr);
131
static int nilfs_libmount_table_errcb(struct libmnt_table *tb,
132
const char *filename, int line)
135
error(_("%s: parse error: ignore entry at line %d."),
144
static int device_is_readonly(const char *device, int *ro)
148
fd = open(device, O_RDONLY);
152
if (ioctl(fd, BLKROGET, ro) < 0)
158
static void show_version(void)
160
printf("%s (%s %s)\n", progname, PACKAGE, PACKAGE_VERSION);
163
static void nilfs_mount_parse_options(int argc, char *argv[],
164
struct nilfs_mount_info *mi)
166
struct libmnt_context *cxt = mi->cxt;
167
struct libmnt_fs *fs;
168
int c, show_version_only = 0;
170
fs = mnt_context_get_fs(cxt);
172
die(EX_SYSERR, _("failed to get fs"));
174
while ((c = getopt(argc, argv, "fvnt:o:rwV")) != EOF) {
177
mnt_context_enable_fake(cxt, 1);
180
mnt_context_enable_verbose(cxt, 1);
184
mnt_context_disable_mtab(cxt, 1);
187
mount_fstype = optarg;
193
if (nilfs_mount_attrs_parse(&mi->new_attrs, optarg,
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"));
202
if (mnt_context_append_options(cxt, "ro"))
203
die(EX_SYSERR, _("failed to append options"));
206
if (mnt_context_append_options(cxt, "rw"))
207
die(EX_SYSERR, _("failed to append options"));
210
show_version_only = 1;
217
if (show_version_only) {
223
static struct libmnt_fs *nilfs_find_rw_mount(struct libmnt_context *cxt,
224
struct libmnt_table *mtab)
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;
232
die(EX_SYSERR, _("libmount iterator allocation failed"));
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"))
245
static int nilfs_prepare_mount(struct nilfs_mount_info *mi)
247
struct libmnt_context *cxt = mi->cxt;
248
struct libmnt_fs *fs;
249
struct libmnt_table *mtab;
253
res = mnt_context_prepare_mount(cxt);
255
error(_("%s: preparing failed: %s"), progname,
260
* mnt_context_prepare_mount() parses mtab (/etc/mtab or
261
* /proc/self/mountinfo + /run/mount/utabs or /proc/mounts)
264
res = mnt_context_get_mflags(cxt, &mi->mflags);
266
error(_("%s: get mount flags failed: %s"), progname,
271
if (!(mi->mflags & MS_RDONLY) && !(mi->mflags & MS_BIND)) {
272
res = device_is_readonly(mnt_context_get_source(cxt),
275
error(_("%s: device %s not accessible: %s"),
276
progname, mnt_context_get_source(cxt),
282
res = mnt_context_get_mtab(cxt, &mtab);
284
error(_("%s: libmount mount check failed: %s"),
285
progname, strerror(-res));
289
mi->mounted = mnt_table_is_fs_mounted(mtab, mnt_context_get_fs(cxt));
291
if (mi->mflags & MS_BIND)
294
fs = nilfs_find_rw_mount(cxt, mtab);
296
return 0; /* no previous rw-mount */
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));
304
case MS_RDONLY: /* ro-mount (a rw-mount exists) */
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;
311
attrs = mnt_fs_get_attributes(fs);
313
if (nilfs_mount_attrs_parse(&mi->old_attrs, attrs,
315
error(_("%s: libmount mount check failed: %s"),
316
progname, strerror(-res));
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). "
325
progname, mnt_context_get_target(cxt));
329
if (mi->old_attrs.gcpid) {
330
res = nilfs_shutdown_cleanerd(
331
mnt_fs_get_source(fs), mi->old_attrs.gcpid);
333
error(_("%s: remount failed due to %s "
334
"shutdown failure"), progname,
335
NILFS_CLEANERD_NAME);
347
static int nilfs_do_mount_one(struct nilfs_mount_info *mi)
349
struct libmnt_context *cxt = mi->cxt;
352
res = mnt_context_do_mount(cxt);
359
error(_("%s: cannot find or load %s filesystem"), progname,
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));
368
if (mi->type != RW2RO_REMOUNT && mi->type != RW2RW_REMOUNT)
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 };
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);
384
nilfs_mount_attrs_update(&mi->old_attrs, &mattrs, cxt);
385
mnt_context_finalize_mount(cxt);
387
error(_("%s: failed to restart %s"),
388
progname, NILFS_CLEANERD_NAME);
391
printf(_("%s not restarted\n"), NILFS_CLEANERD_NAME);
397
static int nilfs_update_mount_state(struct nilfs_mount_info *mi)
399
struct libmnt_context *cxt = mi->cxt;
400
struct nilfs_mount_attrs *old_attrs;
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;
407
if (mnt_context_is_nomtab(cxt)) {
409
printf(_("%s not started\n"), NILFS_CLEANERD_NAME);
414
if (mi->new_attrs.pp == ULONG_MAX)
415
mi->new_attrs.pp = mi->old_attrs.pp;
417
if (nilfs_launch_cleanerd(mnt_context_get_source(cxt),
418
mnt_context_get_target(cxt),
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);
427
nilfs_mount_attrs_update(old_attrs, &mi->new_attrs, cxt);
429
return mnt_context_finalize_mount(cxt);
432
static int nilfs_mount_one(struct nilfs_mount_info *mi)
434
int res, err = EX_FAIL;
436
res = nilfs_prepare_mount(mi);
440
if (!mnt_context_is_fake(mi->cxt)) {
441
res = nilfs_do_mount_one(mi);
445
res = nilfs_update_mount_state(mi);
452
int main(int argc, char *argv[])
454
struct nilfs_mount_info mi = {0};
455
char *device, *mntdir;
459
char *cp = strrchr(argv[0], '/');
461
progname = (cp ? cp + 1 : argv[0]);
464
nilfs_cleaner_logger = nilfs_mount_logger;
466
mi.type = NORMAL_MOUNT;
469
mi.cxt = mnt_new_context();
471
die(EX_SYSERR, _("libmount context allocation failed"));
474
mnt_context_set_tables_errcb(mi.cxt, nilfs_libmount_table_errcb);
476
mnt_context_set_fstype(mi.cxt, fstype);
477
mnt_context_disable_helpers(mi.cxt, 1);
479
nilfs_mount_attrs_init(&mi.old_attrs);
480
nilfs_mount_attrs_init(&mi.new_attrs);
481
nilfs_mount_parse_options(argc, argv, &mi);
485
if (optind >= argc || !argv[optind])
486
die(EX_USAGE, _("No device specified"));
488
device = argv[optind++];
489
mnt_context_set_source(mi.cxt, device);
491
if (optind >= argc || !argv[optind])
492
die(EX_USAGE, _("No mountpoint specified"));
494
mntdir = argv[optind++];
495
mnt_context_set_target(mi.cxt, mntdir);
497
if (mount_fstype && strncmp(mount_fstype, fstype, strlen(fstype)))
498
die(EX_USAGE, _("Unknown filesystem (%s)"), mount_fstype);
500
if (getuid() != geteuid())
502
_("%s: mount by non-root user is not supported yet"),
505
res = nilfs_mount_one(&mi);
507
mnt_free_context(mi.cxt);