This patch add new commands named "nilfs-tune".
nilfs-tune modifys tunable NILFS parameters.
Currently supported parameters are:
- volume label
- UUID
- commit interval
- segment contsruction block max

It also displays NILFS super block information if specified.

Signed-off-by: Jiro SEKIBA <[email protected]>
---
 configure.ac                 |    7 +-
 man/Makefile.am              |    2 +-
 man/chcp.8                   |    3 +-
 man/lscp.1                   |    3 +-
 man/mkcp.8                   |    3 +-
 man/nilfs-tune.8             |   54 +++++
 man/nilfs.8                  |    1 +
 man/rmcp.8                   |    3 +-
 sbin/Makefile.am             |    2 +-
 sbin/nilfs-tune/Makefile.am  |    9 +
 sbin/nilfs-tune/nilfs-tune.c |  500 ++++++++++++++++++++++++++++++++++++++++++
 11 files changed, 578 insertions(+), 9 deletions(-)
 create mode 100644 man/nilfs-tune.8
 create mode 100644 sbin/nilfs-tune/Makefile.am
 create mode 100644 sbin/nilfs-tune/nilfs-tune.c

diff --git a/configure.ac b/configure.ac
index 74dbae3..af75142 100644
--- a/configure.ac
+++ b/configure.ac
@@ -37,7 +37,7 @@ AC_HEADER_STDC
 AC_HEADER_SYS_WAIT
 AC_CHECK_HEADERS([fcntl.h libintl.h limits.h locale.h mntent.h paths.h \
                  stdlib.h string.h strings.h sys/ioctl.h sys/mount.h \
-                 sys/time.h syslog.h unistd.h linux/types.h])
+                 sys/time.h syslog.h unistd.h linux/types.h grp.h pwd.h])
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
@@ -68,7 +68,7 @@ AC_FUNC_STRFTIME
 AC_FUNC_VPRINTF
 AC_CHECK_FUNCS([alarm atexit ftruncate getcwd gettimeofday localtime_r \
                memmove memset munmap strchr strdup strerror strrchr strstr \
-               strtoul])
+               strtoul getgrgid getpwuid])
 
 # Checks for system services
 AC_SYS_LARGEFILE
@@ -87,5 +87,6 @@ AC_CONFIG_FILES([Makefile
                 sbin/Makefile
                 sbin/cleanerd/Makefile
                 sbin/mkfs/Makefile
-                sbin/mount/Makefile])
+                sbin/mount/Makefile
+                sbin/nilfs-tune/Makefile])
 AC_OUTPUT
diff --git a/man/Makefile.am b/man/Makefile.am
index 7085c86..3953f90 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -2,4 +2,4 @@
 
 dist_man_MANS = nilfs.8 mkfs.nilfs2.8 mount.nilfs2.8 umount.nilfs2.8 \
        lscp.1 mkcp.8 chcp.8 rmcp.8 lssu.1 dumpseg.8 nilfs_cleanerd.8 \
-       nilfs_cleanerd.conf.5
+       nilfs_cleanerd.conf.5 nilfs-tune.8
diff --git a/man/chcp.8 b/man/chcp.8
index 65445f3..031e2eb 100644
--- a/man/chcp.8
+++ b/man/chcp.8
@@ -33,4 +33,5 @@ http://www.nilfs.org.
 .BR nilfs (8),
 .BR lscp (1),
 .BR mkcp (8),
-.BR rmcp (8).
+.BR rmcp (8),
+.BR nilfs-tune (8).
diff --git a/man/lscp.1 b/man/lscp.1
index 73ffc9a..0513f57 100644
--- a/man/lscp.1
+++ b/man/lscp.1
@@ -70,4 +70,5 @@ http://www.nilfs.org.
 .BR nilfs (8),
 .BR mkcp (8),
 .BR chcp (8),
-.BR rmcp (8).
+.BR rmcp (8),
+.BR nilfs-tune (8).
diff --git a/man/mkcp.8 b/man/mkcp.8
index 20e1848..490a75b 100644
--- a/man/mkcp.8
+++ b/man/mkcp.8
@@ -32,4 +32,5 @@ http://www.nilfs.org.
 .BR nilfs (8),
 .BR lscp (1),
 .BR chcp (8),
-.BR rmcp (8).
+.BR rmcp (8),
+.BR nilfs-tune (8).
diff --git a/man/nilfs-tune.8 b/man/nilfs-tune.8
new file mode 100644
index 0000000..2337c8f
--- /dev/null
+++ b/man/nilfs-tune.8
@@ -0,0 +1,54 @@
+.\"  Copyright (C) 2010 Jiro SEKIBA <[email protected]>
+.\"
+.TH NILFS-TUNE 8 "May 2010" "nilfs-utils version 2.0"
+.SH NAME
+nilfs-tune \- adjust tunable file system parameters on NILFS filesystem
+.SH SYNOPSIS
+.B nilfs-tune
+[\fIoptions\fP] \fIdevice\fP
+.SH DESCRIPTION
+.B nilfs-tune
+is a utility to modify tunable file system parameters on NILFS2 file
+system in \fIdevice\fP.  When \fIdevice\fP is omitted, it tries
+to find a NILFS2 file system from \fI/proc/mounts\fP.
+.PP
+This command is valid only for mounted NILFS2 file systems, and
+will fail if the \fIdevice\fP has no active mounts.
+.SH OPTIONS
+.TP
+.B \-i \fIinterval\fP
+Set the commit interval of segment.
+.TP
+.B \-m \fIblock-max\fP
+Set the threshold of the data amount of the segment construction.
+.TP
+.B \-l
+List the contents of the file system superblock, including the current
+values of the prameters that can be set via this program.
+.TP
+.B \-L \fIvolume-label\fP
+Set the volume label of the file system.  NILFS2 file system labels
+can be at most 80 bytes long.  If volume-label is longer than 80 bytes,
+nilfs-tune will truncate it.  The volume label can be used mount(8) and
+/etc/fstab(5) (and possibly others) by specifying \fBLABEL\fP=volume-label
+instead of a block special device name like /dev/sda5.
+.TP
+.B \-U \fIUUID\fP
+Set the universally unique identifier (UUID) of the filesystem to UUID.
+The format of the UUID is a series of hex digits sepa rated by hyphens,
+like this: "c1b9d5a2-f162-11cf-9ece-0020afc76f16".
+.TP
+.B \-h
+Display help message and exit.
+.SH AUTHOR
+Jiro SEKIBA <[email protected]>
+.SH AVAILABILITY
+.B nilfs-tune
+is part of the nilfs-utils package and is available from
+http://www.nilfs.org.
+.SH SEE ALSO
+.BR nilfs (8),
+.BR lscp (1),
+.BR chcp (8),
+.BR mkcp (8),
+.BR rmcp (8).
diff --git a/man/nilfs.8 b/man/nilfs.8
index 8ec8f13..e8089e6 100644
--- a/man/nilfs.8
+++ b/man/nilfs.8
@@ -111,6 +111,7 @@ was developed by NILFS development team <[email protected]>.
 .BR umount.nilfs2 (8),
 .BR nilfs_cleanerd (8),
 .BR nilfs_cleanerd.conf (5),
+.BR nilfs-tune (8),
 .BR lscp (1),
 .BR mkcp (8),
 .BR chcp (8),
diff --git a/man/rmcp.8 b/man/rmcp.8
index e7d65f9..6d99a21 100644
--- a/man/rmcp.8
+++ b/man/rmcp.8
@@ -52,4 +52,5 @@ http://www.nilfs.org.
 .BR nilfs (8),
 .BR lscp (1),
 .BR mkcp (8),
-.BR chcp (8).
+.BR chcp (8),
+.BR nilfs-tune (8).
diff --git a/sbin/Makefile.am b/sbin/Makefile.am
index 6038b8f..0783ce0 100644
--- a/sbin/Makefile.am
+++ b/sbin/Makefile.am
@@ -1,3 +1,3 @@
 ## Makefile.am
 
-SUBDIRS = cleanerd mkfs mount
+SUBDIRS = cleanerd mkfs mount nilfs-tune
diff --git a/sbin/nilfs-tune/Makefile.am b/sbin/nilfs-tune/Makefile.am
new file mode 100644
index 0000000..e29ba2e
--- /dev/null
+++ b/sbin/nilfs-tune/Makefile.am
@@ -0,0 +1,9 @@
+## Makefile.am
+
+AM_CFLAGS = -Wall
+AM_CPPFLAGS = -I$(top_srcdir)/include
+
+sbin_PROGRAMS = nilfs-tune
+
+nilfs_tune_SOURCES = nilfs-tune.c
+nilfs_tune_LDADD = $(top_builddir)/lib/libnilfs.la
diff --git a/sbin/nilfs-tune/nilfs-tune.c b/sbin/nilfs-tune/nilfs-tune.c
new file mode 100644
index 0000000..99abb56
--- /dev/null
+++ b/sbin/nilfs-tune/nilfs-tune.c
@@ -0,0 +1,500 @@
+/*
+ * nilfs-tune.c - adjust tunable filesystem parameters on NILFS filesystem
+ *
+ * Copyright (C) 2010 Jiro SEKIBA <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NILFS; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#define _FILE_OFFSET_BITS 64
+//#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+#define __USE_FILE_OFFSET64
+#define _XOPEN_SOURCE 600
+
+#include <stdio.h>
+
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+
+#if HAVE_STRINGS_H
+#include <strings.h>
+#endif /* HAVE_STRINGS_H */
+
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif /* HAVE_SYS_IOCTL_H */
+
+#if HAVE_STRING_H
+#include <string.h>
+#endif /* HAVE_STRING_H */
+
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif /* HAVE_LIMITS_H */
+
+#if HAVE_GRP_H
+#include <grp.h>
+#endif /* HAVE_GRP_H */
+
+#if HAVE_PWD_H
+#include <pwd.h>
+#endif /* HAVE_PWD_H */
+
+#include <ctype.h>
+
+#include <errno.h>
+#include "nilfs.h"
+
+#define MOUNTS                 "/etc/mtab"
+#define LINE_BUFFER_SIZE       256  /* Line buffer size for reading mtab */
+
+struct nilfs_tune_options {
+       int flags;
+       int display;
+       int mask;
+       int force;
+       __u32 c_interval;
+       __u32 c_block_max;
+       char label[80];
+       __u8 uuid[16];
+};
+
+static void nilfs_tune_usage(void)
+{
+       printf("Usage: nilfs-tune [-h] [-l] [-i interval] [-L volume_name]\n"
+              "                  [-m block_max] [-U UUID] device\n");
+}
+
+int parse_uuid(const char *uuid_string, __u8 *uuid)
+{
+       int i;
+       char p[3];
+
+       if (strlen(uuid_string) != 36)
+               return -1;
+
+       for (i=0, p[2]='\0'; i < 36; i++) {
+               if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) {
+                       if (uuid_string[i] == '-')
+                               continue;
+                       else
+                               return -1;
+               }
+               if (!isxdigit(uuid_string[i]) || !isxdigit(uuid_string[i+1]))
+                       return -1;
+
+               p[0] = uuid_string[i++];
+               p[1] = uuid_string[i];
+               *uuid = strtoul(p, NULL, 16);
+               uuid++;
+       }
+       return 0;
+}
+
+void parse_options(int argc, char *argv[], struct nilfs_tune_options *opts)
+{
+       int c;
+       opts->flags = O_RDONLY;
+       opts->display = 0;
+       opts->mask = 0;
+       opts->force = 0;
+
+       while ((c = getopt(argc, argv, "flhi:L:m:U:")) != EOF) {
+               switch (c) {
+               case 'f':
+                       opts->force = 1;
+                       break;
+               case 'h':
+                       nilfs_tune_usage();
+                       exit(EXIT_SUCCESS);
+                       break;
+               case 'i':
+                       opts->c_interval = atol(optarg);
+                       opts->mask |= NILFS_SB_COMMIT_INTERVAL;
+                       opts->flags = O_RDWR;
+                       break;
+               case 'L':
+                       strncpy(opts->label, optarg, sizeof(opts->label));
+                       opts->mask |= NILFS_SB_LABEL;
+                       opts->flags = O_RDWR;
+                       break;
+               case 'm':
+                       opts->c_block_max = atol(optarg);
+                       opts->mask |= NILFS_SB_BLOCK_MAX;
+                       opts->flags = O_RDWR;
+                       break;
+               case 'l':
+                       opts->display = 1;
+                       break;
+               case 'U':
+                       if (parse_uuid(optarg, opts->uuid)) {
+                               fprintf(stderr, "Invalid UUID format\n");
+                               exit(EXIT_FAILURE);
+                       }
+                       opts->mask |= NILFS_SB_UUID;
+                       opts->flags = O_RDWR;
+                       break;
+               default:
+                       nilfs_tune_usage();
+               }
+       }
+}
+
+#define MINUTE (60)
+#define HOUR   (MINUTE * 60)
+#define DAY    (HOUR * 24)
+#define WEEK   (DAY * 7)
+#define MONTH  (DAY * 30)
+
+#define DIV_SECS(v, C)         \
+do {                           \
+       if (secs > (C)) {       \
+               v = secs / C;   \
+               secs -= v * C;  \
+       } else {                \
+               v = 0;          \
+       }                       \
+} while(0)
+
+#define FORMAT_VARIABLE(v) \
+do {                           \
+       if (v##s) {             \
+               sprintf(tmp, "%s%d " #v "%s", buf[0] ? ", " : "", \
+                       v##s, (v##s>1) ? "s" : ""); \
+               strcat(buf, tmp);       \
+       }                       \
+} while(0)
+
+static const char *interval_string(unsigned int secs)
+{
+       static char buf[512], tmp[128];
+       int months, weeks, days, hours, minutes;
+
+       if (secs == 0)
+               return "none";
+
+       buf[0] = 0;
+       DIV_SECS(months, MONTH);
+       DIV_SECS(weeks, WEEK);
+       DIV_SECS(days, DAY);
+       DIV_SECS(hours, HOUR);
+       DIV_SECS(minutes, MINUTE);
+
+       FORMAT_VARIABLE(month);
+       FORMAT_VARIABLE(week);
+       FORMAT_VARIABLE(day);
+       FORMAT_VARIABLE(hour);
+       FORMAT_VARIABLE(minute);
+       FORMAT_VARIABLE(sec);
+
+       return buf;
+}
+
+static const char *user_string(uid_t uid)
+{
+       static char tmp[LOGIN_NAME_MAX];
+       static char buf[LOGIN_NAME_MAX + 8];
+       struct passwd *pwd;
+
+       strcpy(buf, "user ");
+
+       pwd = getpwuid(uid);
+       if (pwd)
+               strncpy(tmp, pwd->pw_name, sizeof(tmp));
+       else
+               strcpy(tmp, "unknown");
+       strcat(buf, tmp);
+       return buf;
+}
+
+static const char *group_string(gid_t gid)
+{
+       static char tmp[LOGIN_NAME_MAX];
+       static char buf[LOGIN_NAME_MAX + 8];
+       struct group *grp;
+
+       strcpy(buf, "group ");
+
+       grp = getgrgid(gid);
+       if (grp)
+               strncpy(tmp, grp->gr_name, sizeof(tmp));
+       else
+               strcpy(tmp, "unknown");
+       strcat(buf, tmp);
+       return buf;
+}
+
+static const char *uuid_string(unsigned char *uuid)
+{
+       static char buf[256];
+
+       sprintf(buf, "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
+               "%02x%02x-%02x%02x%02x%02x%02x%02x", uuid[0], uuid[1],
+               uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
+               uuid[8], uuid[9], uuid[10], uuid[11], uuid[12],
+               uuid[13], uuid[14], uuid[15]);
+       return buf;
+}
+
+static const char *state_string(unsigned int state)
+{
+       static char buf[256];
+
+       if (state & NILFS_VALID_FS)
+               strcpy(buf, "valid");
+       else
+               strcpy(buf, "invalid or mounted");
+       if (state & NILFS_ERROR_FS)
+               strcat(buf, ",error");
+       if (state & NILFS_RESIZE_FS)
+               strcat(buf, ",resize");
+       return buf;
+}
+
+static const char *creator_os_string(unsigned int creator)
+{
+       static char buf[64];
+
+       switch(creator) {
+       case NILFS_OS_LINUX:
+               strcpy(buf, "Linux");
+               break;
+       default:
+               strcpy(buf, "Unknown");
+               break;
+       }
+
+       return buf;
+}
+
+static char *time_string(time_t t)
+{
+       return ctime(&t);
+}
+
+void show_nilfs_sb(struct nilfs_super_block *sbp)
+{
+       char label[sizeof(sbp->s_volume_name) + 1];
+       gid_t gid;
+       uid_t uid;
+
+       memset(label, 0, sizeof(label));
+       memcpy(label, sbp->s_volume_name, sizeof(sbp->s_volume_name));
+       if (!label[0])
+               strcpy(label, "<none>");
+
+       printf("Filesystem volume name:\t  %s\n", label);
+       printf("Filesystem UUID:\t  %s\n", uuid_string(sbp->s_uuid));
+       printf("Filesystem magic number:  0x%04x\n",
+              le16_to_cpu(sbp->s_magic));
+       printf("Filesystem revision #:\t  %d.%d\n",
+              le32_to_cpu(sbp->s_rev_level),
+              le32_to_cpu(sbp->s_minor_rev_level));
+
+       /* sbp->s_flags is not used */
+
+       printf("Filesystem state:\t  %s\n",
+              state_string(le16_to_cpu(sbp->s_state)));
+
+       /* sbp->s_errors is not used */
+
+       printf("Filesystem OS type:\t  %s\n",
+              creator_os_string(le32_to_cpu(sbp->s_creator_os)));
+
+       printf("Block size:\t\t  %u\n",
+              1 << (le32_to_cpu(sbp->s_log_block_size) + 10));
+
+       printf("Filesystem created:\t  %s",
+              time_string(le64_to_cpu(sbp->s_ctime)));
+       printf("Last mount time:\t  %s",
+              time_string(le64_to_cpu(sbp->s_mtime)));
+       printf("Last write time:\t  %s",
+              time_string(le64_to_cpu(sbp->s_wtime)));
+       printf("Mount count:\t\t  %u\n", le16_to_cpu(sbp->s_mnt_count));
+       printf("Maximum mount count:\t  %u\n",
+              le16_to_cpu(sbp->s_max_mnt_count));
+
+#if 0 /* filesystem check is not implemented yet */
+       {
+               time_t t;
+               unsigned int interval;
+
+               t = (time_t)le64_to_cpu(sbp->s_lastcheck);
+               printf("Last checked:\t\t  %s", ctime(&t));
+
+               interval = le32_to_cpu(sbp->s_checkinterval);
+               printf("Check interval:\t\t  %u (%s)\n", interval,
+                      interval_string(interval));
+
+               if(interval)
+                       printf("Next check after:\t  %s",
+                              time_string(t+interval));
+       }
+#endif
+
+       uid = (uid_t)le16_to_cpu(sbp->s_def_resuid);
+       printf("Reserve blocks uid:\t  %u (%s)\n", uid, user_string(uid));
+       gid = (gid_t)le16_to_cpu(sbp->s_def_resgid);
+       printf("Reserve blocks gid:\t  %u (%s)\n", gid, group_string(gid));
+
+       printf("First inode:\t\t  %u\n", le32_to_cpu(sbp->s_first_ino));
+
+       printf("Inode size:\t\t  %u\n", le16_to_cpu(sbp->s_inode_size));
+       printf("DAT entry size:\t\t  %u\n", le16_to_cpu(sbp->s_dat_entry_size));
+       printf("Checkpoint size:\t  %u\n",
+              le16_to_cpu(sbp->s_checkpoint_size));
+       printf("Segment usage size:\t  %u\n",
+              le16_to_cpu(sbp->s_segment_usage_size));
+
+       printf("Number of segments:\t  %llu\n", le64_to_cpu(sbp->s_nsegments));
+       printf("Device size:\t\t  %llu\n", le64_to_cpu(sbp->s_dev_size));
+       printf("First data block:\t  %llu\n",
+              le64_to_cpu(sbp->s_first_data_block));
+       printf("# of blocks per segment:  %u\n",
+              le32_to_cpu(sbp->s_blocks_per_segment));
+       printf("Reserved segments %%:\t  %u\n",
+              le32_to_cpu(sbp->s_r_segments_percentage));
+       printf("Last checkpoint #:\t  %llu\n", le64_to_cpu(sbp->s_last_cno));
+       printf("Last block address:\t  %llu\n", le64_to_cpu(sbp->s_last_pseg));
+       printf("Last sequence #:\t  %llu\n", le64_to_cpu(sbp->s_last_seq));
+       printf("Free blocks count:\t  %llu\n",
+              le64_to_cpu(sbp->s_free_blocks_count));
+
+       printf("Commit interval:\t  %u\n", le32_to_cpu(sbp->s_c_interval));
+       printf("# of blks to create seg:  %u\n", 
le32_to_cpu(sbp->s_c_block_max));
+
+       printf("CRC seed:\t\t  0x%08x\n", le32_to_cpu(sbp->s_crc_seed));
+       printf("CRC check sum:\t\t  0x%08x\n", le32_to_cpu(sbp->s_sum));
+       printf("CRC check data size:\t  0x%08x\n", le32_to_cpu(sbp->s_bytes));
+}
+
+int modify_nilfs(char *device, struct nilfs_tune_options *opts)
+{
+       int devfd;
+       int ret = EXIT_SUCCESS;
+       struct nilfs_super_block *sbp;
+       __u64 features;
+
+       devfd = open(device, opts->flags);
+
+       if (devfd == -1) {
+               fprintf(stderr, "%s: cannot open NILFS\n", device);
+               ret = EXIT_FAILURE;
+               goto out;
+       }
+
+       sbp = nilfs_sb_read(devfd);
+       if (!sbp) {
+               fprintf(stderr, "%s: cannot open NILFS\n", device);
+               ret = EXIT_FAILURE;
+               goto close_fd;
+       }
+
+       features = le64_to_cpu(sbp->s_feature_incompat);
+       if (features & ~NILFS_FEATURE_INCOMPAT_SUPP)
+               fprintf(stderr, "Warning: %s: unknown incompatible "
+                       "features: 0x%llx\n", device, features);
+
+       features = le64_to_cpu(sbp->s_feature_compat_ro);
+       if (opts->flags == O_RDWR &&
+           (features & ~NILFS_FEATURE_COMPAT_RO_SUPP))
+               fprintf(stderr, "Warning: %s: unknown read-only compatible "
+                       "features: 0x%llx\n", device, features);
+
+       if (opts->mask & NILFS_SB_LABEL)
+               memcpy(sbp->s_volume_name, opts->label,
+                      sizeof(opts->label));
+       if (opts->mask & NILFS_SB_UUID)
+               memcpy(sbp->s_uuid, opts->uuid, sizeof(opts->uuid));
+       if (opts->mask & NILFS_SB_COMMIT_INTERVAL)
+               sbp->s_c_interval = cpu_to_le32(opts->c_interval);
+       if (opts->mask & NILFS_SB_BLOCK_MAX)
+               sbp->s_c_block_max = cpu_to_le32(opts->c_block_max);
+
+       if (opts->mask)
+               nilfs_sb_write(devfd, sbp, opts->mask);
+
+       if (opts->display)
+               show_nilfs_sb(sbp);
+
+       free(sbp);
+
+ close_fd:
+       close(devfd);
+ out:
+       return ret;
+}
+
+/* Code borrowed from nilfs2-util/sbin/mkfs/mkfs.c */
+static int check_mount(const char *device)
+{
+       FILE *fp;
+       char line[LINE_BUFFER_SIZE];
+
+       fp = fopen(MOUNTS, "r");
+       if (fp == NULL) {
+               fprintf(stderr, "Error: cannot open %s!", MOUNTS);
+               return 1;
+       }
+
+       while (fgets(line, LINE_BUFFER_SIZE, fp) != NULL) {
+               if (strncmp(strtok(line, " "), device, strlen(device)) == 0) {
+                       fclose(fp);
+                       return 1;
+               }
+       }
+       fclose(fp);
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       struct nilfs_tune_options opts;
+       char *device;
+
+       printf("nilfs-tune %s\n", VERSION);
+       if (argc < 2) {
+               nilfs_tune_usage();
+               exit(EXIT_SUCCESS);
+       }
+
+       parse_options(argc, argv, &opts);
+
+       device = argv[argc-1];
+
+       if (!device) {
+               nilfs_tune_usage();
+               exit(EXIT_FAILURE);
+       }
+
+       if (!opts.force && opts.flags == O_RDWR && check_mount(device)) {
+               fprintf(stderr, "Warning: %s is currently mounted.\n"
+                       "Running nilfs-tune on a mounted file system "
+                       "may cause SEVERE damage.\n"
+                       "You can force to modify file system by "
+                       "\"-f\" option.\n",
+                       device);
+               exit(EXIT_SUCCESS);
+       }
+
+       return modify_nilfs(device, &opts);
+}
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to