Implemented automatic /etc/fstab modifications.
authorshort <>
Fri, 29 Aug 2003 23:09:14 +0000 (23:09 +0000)
committershort <>
Fri, 29 Aug 2003 23:09:14 +0000 (23:09 +0000)
+Provide also 'captive-install' package.

12 files changed:
TODO
autogen.pl
captive.spec.in
configure.in
debian/control
debian/install.files [new file with mode: 0644]
debian/install.postinst [new file with mode: 0755]
debian/install.prerm [new file with mode: 0755]
src/Makefile.am
src/install/Makefile.am [new file with mode: 0644]
src/install/fstab/Makefile.am [new file with mode: 0644]
src/install/fstab/main.c [new file with mode: 0644]

diff --git a/TODO b/TODO
index 47b140c..f7b8850 100644 (file)
--- a/TODO
+++ b/TODO
@@ -13,3 +13,4 @@ Better BLKGETSIZE64 vs. BLKGETSIZE run-time availability compatibility.
 'src/client/gnomevfs/captive.conf' should be generated.
 Why native NT autocheck (=w/o errors) the volume after our DISMOUNT_VOLUME?
  - ntfsprogs: not updated last ('boot backup') media sector due to Linux kernel
+'src/install/fstab/' should not reformat '/etc/fstab' - how to modify it?
index 4916143..5b829e4 100755 (executable)
@@ -47,6 +47,7 @@ AutoGen->run(
                                ./src/client/lufs/mount.captive
                                ./src/client/sandbox-server/captive-sandbox-server
                                ./src/client/gnomevfs/captive.conf
+                               ./src/install/fstab/captive-install-fstab
                                ./src/libcaptive/cc/marshallers.[ch]
                                ./src/libcaptive/ke/exports.c
                                ./src/libcaptive/reactos/*/*.[cS]
index 14483d5..3f2c438 100644 (file)
@@ -67,6 +67,18 @@ LUFS is a hybrid userspace filesystem framework.
 Package provides LUFS filesystem module to access Microsoft Windows platform
 filesystems such as NTFS.
 
+%package install
+Summary: Instant installer for Microsoft Windows platform filesystem access.
+Group: System Environment/Base
+Requires: captive-lufs = %{PACKAGE_VERSION}
+BuildRequires: ntfsprogs-devel
+Requires: ntfsprogs
+
+%description install
+Package provides easy enough unattended installation of Microsoft Windows
+platform filesystem access. Installer finds available NTFS partitions and
+tries to acquire needed Microsoft Windows filesystem driver files.
+
 #% %package devel
 #% Summary: Microsoft Windows platform filesystem access development support.
 #% Group: Development/System
@@ -131,6 +143,16 @@ rm -rf $RPM_BUILD_ROOT
 /sbin/mount.@PACKAGE@
 /sbin/mount.@PACKAGE@-*
 
+%post install
+%{_sbindir}/captive-install-fstab --add
+
+%preun install
+%{_sbindir}/captive-install-fstab --remove
+
+%files install
+%defattr(-,root,root)
+%{_sbindir}/captive-install-fstab
+
 # %files devel
 # %defattr(-,root,root)
 # %doc ChangeLog
index 5008643..4d2d916 100644 (file)
@@ -252,6 +252,12 @@ dnl Do not use '[client server]' as $4 to prevent: configure: test: too many arg
 dnl  - currently this argument is not used by 'orbit2-config' in any way anyway
 AM_PATH_ORBIT2(,,[AC_MSG_ERROR([Captive requires ORBit library.])])
 
+AC_CHECK_LIB(ntfs,ntfs_mount,
+       [ LIBNTFS_LIBS="-lntfs" ],
+       [ LIBNTFS_LIBS="" ])
+AC_SUBST(LIBNTFS_LIBS)
+AM_CONDITIONAL(HAVE_LIBNTFS,test -n "$LIBNTFS_LIBS")
+
 
 AC_SUBST(CFLAGS)
 AC_SUBST(LIBS)
@@ -318,6 +324,8 @@ AC_OUTPUT([
 ./src/client/gnomevfs/Makefile
 ./src/client/lufs/Makefile
 ./src/client/sandbox-server/Makefile
+./src/install/Makefile
+./src/install/fstab/Makefile
 ./src/TraceFS/Makefile
 ./doc/Makefile
 ./doc/apiref/Makefile
index eaf28b0..a8b7282 100644 (file)
@@ -45,3 +45,13 @@ Description: LUFS module for Microsoft Windows platform filesystem access.
  .
  Package provides LUFS filesystem module to access Microsoft Windows platform
  filesystems such as NTFS.
+
+Package: captive-install
+Architecture: i386
+Depends: captive-lufs (= ${Source-Version}),
+ ntfsprogs
+Build-Depends: ntfsprogs-dev
+Description: Instant installer for Microsoft Windows platform filesystem access.
+ Package provides easy enough unattended installation of Microsoft Windows
+ platform filesystem access. Installer finds available NTFS partitions and
+ tries to acquire needed Microsoft Windows filesystem driver files.
diff --git a/debian/install.files b/debian/install.files
new file mode 100644 (file)
index 0000000..8b78d25
--- /dev/null
@@ -0,0 +1 @@
+/usr/sbin/captive-install-fstab
diff --git a/debian/install.postinst b/debian/install.postinst
new file mode 100755 (executable)
index 0000000..9e6c06a
--- /dev/null
@@ -0,0 +1,21 @@
+#! /bin/sh
+# post-install script
+# Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
+# 
+# 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; exactly version 2 of June 1991 is required
+# 
+# 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 this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+/usr/sbin/captive-install-fstab --add
+
+exit 0
diff --git a/debian/install.prerm b/debian/install.prerm
new file mode 100755 (executable)
index 0000000..62615c7
--- /dev/null
@@ -0,0 +1,21 @@
+#! /bin/sh
+# pre-remove script
+# Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
+# 
+# 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; exactly version 2 of June 1991 is required
+# 
+# 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 this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+/usr/sbin/captive-install-fstab --remove
+
+exit 0
index a4d4274..10e5aa2 100644 (file)
@@ -18,4 +18,4 @@
 
 include $(top_srcdir)/Makefile-head.am
 
-SUBDIRS=libcaptive client TraceFS
+SUBDIRS=libcaptive client install TraceFS
diff --git a/src/install/Makefile.am b/src/install/Makefile.am
new file mode 100644 (file)
index 0000000..c04a8d9
--- /dev/null
@@ -0,0 +1,21 @@
+# $Id$
+# automake source for installation utilities toplevel Makefile 
+# Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
+# 
+# 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; exactly version 2 of June 1991 is required
+# 
+# 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 this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+include $(top_srcdir)/Makefile-head.am
+
+SUBDIRS=fstab
diff --git a/src/install/fstab/Makefile.am b/src/install/fstab/Makefile.am
new file mode 100644 (file)
index 0000000..da72a87
--- /dev/null
@@ -0,0 +1,28 @@
+# $Id$
+# automake source for /etc/fstab installation Makefile
+# Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
+# 
+# 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; exactly version 2 of June 1991 is required
+# 
+# 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 this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+include $(top_srcdir)/Makefile-head.am
+
+captive_install_fstab_SOURCES= \
+               main.c
+captive_install_fstab_LDADD=$(LIBNTFS_LIBS) $(POPT_LIBS)
+
+if HAVE_LIBNTFS
+captive_install_fstab_cond=captive-install-fstab
+endif
+sbin_PROGRAMS+=$(captive_install_fstab_cond)
diff --git a/src/install/fstab/main.c b/src/install/fstab/main.c
new file mode 100644 (file)
index 0000000..4563fe3
--- /dev/null
@@ -0,0 +1,341 @@
+/* $Id$
+ * /etc/fstab installation utility
+ * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
+ * 
+ * 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; exactly version 2 of June 1991 is required
+ * 
+ * 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "config.h"
+
+#undef FALSE
+#undef TRUE
+#include <ntfs/types.h>        /* for 'FALSE'/'TRUE' libntfs definition */
+#define FALSE FALSE
+#define TRUE TRUE
+
+#include <glib/gmessages.h>
+#include <popt.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mntent.h>
+#include <glib/ghash.h>
+#include <glib/gstrfuncs.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <captive/macros.h>
+
+#include <ntfs/volume.h>
+
+
+/* Config: */
+#define FILENAME_PROC_PARTITIONS  "/proc/partitions"
+#define FILENAME_ETC_FSTAB        "/etc/fstab"
+#define FILENAME_ETC_FSTAB_BACKUP FILENAME_ETC_FSTAB ".pre-captive"
+#define FILENAME_ETC_FSTAB_TMP    FILENAME_ETC_FSTAB ".tmp"
+
+
+static int optarg_verbose;
+static int optarg_dry;
+enum optarg_mode {
+               OPTARG_MODE_UNDEF =0,
+               OPTARG_MODE_ADD   =1,
+               OPTARG_MODE_REMOVE=2,
+               };
+static int     /* Do not use 'enum optarg_mode' as 'poptOption.arg' is '(int *)'. */
+               optarg_mode=OPTARG_MODE_UNDEF;
+
+static const struct poptOption popt_table[]={
+#define BUG_FSTAB_POPT(shortname,longname,argInfoP,argP,valP,descripP,argDescripP) \
+               { \
+                       longName: (longname), \
+                       shortName: (shortname), \
+                       argInfo: (argInfoP)|(!(valP) ? 0 : POPT_ARG_VAL), \
+                       arg: (void *)argP, \
+                       val: (valP), \
+                       descrip: (descripP), \
+                       argDescrip: (argDescripP), \
+               }
+
+               BUG_FSTAB_POPT('v',"verbose",POPT_ARG_NONE,&optarg_verbose,0,N_("Display additional debug information"),NULL),
+               BUG_FSTAB_POPT('n',"dry"    ,POPT_ARG_NONE,&optarg_dry    ,0,N_("No real modifications - simulate only"),NULL),
+               BUG_FSTAB_POPT(0  ,"add"    ,POPT_ARG_NONE,&optarg_mode   ,OPTARG_MODE_ADD   ,N_("Add entries to /etc/fstab"),NULL),
+               BUG_FSTAB_POPT(0  ,"remove" ,POPT_ARG_NONE,&optarg_mode   ,OPTARG_MODE_REMOVE,N_("Remove entries from /etc/fstab"),NULL),
+
+#undef BUG_FSTAB_POPT
+               POPT_AUTOHELP
+               POPT_TABLEEND
+               };
+
+
+static void devices_hash_key_destroy_func(gchar *device)
+{
+       g_return_if_fail(device!=NULL);
+
+       g_free(device);
+}
+
+static void devices_hash_value_destroy_func(gchar *vol_name)
+{
+       g_return_if_fail(vol_name!=NULL);
+
+       g_free(vol_name);
+}
+
+
+static GHashTable *devices_hash_get(void)
+{
+FILE *fpartitions;
+gchar line[LINE_MAX];
+gint lineno;
+/* map: (gchar *)device -> (gchar *)vol_name */
+GHashTable *devices_hash;
+
+       devices_hash=g_hash_table_new_full(g_str_hash,g_str_equal,
+                       (GDestroyNotify)devices_hash_key_destroy_func,
+                       (GDestroyNotify)devices_hash_value_destroy_func);
+
+       if (!(fpartitions=fopen(FILENAME_PROC_PARTITIONS,"r")))
+               g_error(_("Cannot open \"%s\": %m"),FILENAME_PROC_PARTITIONS);
+       lineno=0;
+       while (fgets(line,sizeof(line),fpartitions)) {
+unsigned major,minor;
+unsigned long long blocks;
+char device[strlen("/dev/")+100];
+ntfs_volume *volume;
+
+               lineno++;
+               if (lineno<=2)
+                       continue;
+               if (4!=sscanf(line,"%u%u%llu%100s",&major,&minor,&blocks,device+strlen("/dev/")))
+                       g_error(_("Error parsing line of \"%s\": %s"),FILENAME_PROC_PARTITIONS,line);
+               memcpy(device,"/dev/",strlen("/dev/"));
+               if (!(volume=ntfs_mount(device,MS_RDONLY))) {
+                       if (optarg_verbose)
+                               g_message(_("not ntfs: %s"),device);
+                       continue;
+                       }
+               if (optarg_verbose)
+                       g_message(_("FOUND ntfs: %s\t%s"),device,volume->vol_name);
+               g_hash_table_insert(devices_hash,g_strdup(device),g_strdup(volume->vol_name));
+               if (ntfs_umount(volume,
+                               TRUE))  /* force; close even if it would mean data loss */
+                       g_warning(_("Error unmounting volume: %s"),device);
+               }
+       if (fclose(fpartitions))
+               g_error(_("Cannot close \"%s\": %m"),FILENAME_PROC_PARTITIONS);
+       return devices_hash;
+}
+
+
+/* map: (gchar *)dir -> (gpointer)!NULL */
+static GHashTable *dirs_used_hash;
+
+static void dirs_used_hash_key_destroy_func(gchar *dir)
+{
+       g_return_if_fail(dir!=NULL);
+
+       g_free(dir);
+}
+
+
+static void mntent_add_devices_hash_entry(const gchar *device,const gchar *vol_name,FILE *mntentfilew /* user_data */)
+{
+struct mntent mntent_local;
+gint dir_count;
+
+       g_return_if_fail(device!=NULL);
+       g_return_if_fail(vol_name!=NULL);
+       g_return_if_fail(mntentfilew!=NULL);
+
+       CAPTIVE_MEMZERO(&mntent_local);
+       mntent_local.mnt_fsname=(/* de-const */ gchar *)device;
+       mntent_local.mnt_dir=(/* de-const */ gchar *)captive_printf_alloca("/mnt/captive-%s",vol_name);
+       dir_count=1;
+       while (g_hash_table_lookup(dirs_used_hash,mntent_local.mnt_dir)) {
+               dir_count++;
+               mntent_local.mnt_dir=(/* de-const */ gchar *)captive_printf_alloca("/mnt/captive-%s%d",vol_name,dir_count);
+               }
+       if (optarg_dry || !mkdir("/mnt",0755)) {
+               if (optarg_verbose)
+                       g_message(_("Created base mount directory: %s"),"/mnt");
+               }
+       else if (errno!=EEXIST)
+               g_warning(_("Error creating base mount directory \"%s\" for device \"%s\": %m"),
+                               "/mnt",mntent_local.mnt_fsname);
+       if (optarg_dry || !mkdir(mntent_local.mnt_dir,0755)) {
+               if (optarg_verbose)
+                       g_message(_("Created mount directory for device \"%s\": %s"),
+                                       mntent_local.mnt_fsname,mntent_local.mnt_dir);
+               }
+       else if (errno!=EEXIST)
+               g_warning(_("Error creating mount directory \"%s\" for device \"%s\": %m"),
+                               mntent_local.mnt_dir,mntent_local.mnt_fsname);
+       mntent_local.mnt_type="captive-ntfs";
+       mntent_local.mnt_opts="defaults";       /* 'mntent_local.mnt_opts' must be != NULL ! */
+       if (optarg_verbose)
+               g_message(_("Creating captive-ntfs mntent: %s -> %s"),mntent_local.mnt_fsname,mntent_local.mnt_dir);
+       if (addmntent(mntentfilew,&mntent_local))
+               g_warning(_("Error appending mntent for device \"%s\": %m"),mntent_local.mnt_fsname);
+       g_hash_table_insert(dirs_used_hash,g_strdup(mntent_local.mnt_dir),dirs_used_hash);
+}
+
+
+int main(int argc,char **argv)
+{
+poptContext context;
+int errint;
+FILE *mntentfiler,*mntentfilew;
+gboolean modified=FALSE;
+
+       /* Initialize the i18n stuff */
+       setlocale(LC_ALL,"");
+       bindtextdomain(PACKAGE,LOCALEDIR);
+       textdomain(PACKAGE);
+
+       context=poptGetContext(
+                       PACKAGE,        /* name */
+                       argc,(/*en-const*/const char **)argv,   /* argc,argv */
+                       popt_table,     /* options */
+                       POPT_CONTEXT_POSIXMEHARDER);    /* flags; && !POPT_CONTEXT_KEEP_FIRST */
+       if (context==NULL) {
+               g_assert_not_reached(); /* argument recognization args_error */
+               return EXIT_FAILURE;
+               }
+       errint=poptReadDefaultConfig(context,
+                       TRUE);  /* useEnv */
+       if (errint!=0) {
+               g_assert_not_reached(); /* argument recognization args_error */
+               return EXIT_FAILURE;
+               }
+       errint=poptGetNextOpt(context);
+       if (errint!=-1) {
+               g_assert_not_reached(); /* some non-callbacked argument reached */
+               return EXIT_FAILURE;
+               }
+       if (poptPeekArg(context)) {
+               g_error(_("No arguments expected"));
+               return EXIT_FAILURE;
+               }
+       if (optarg_mode==OPTARG_MODE_UNDEF)
+               g_error(_("No run mode specified"));
+
+       dirs_used_hash=g_hash_table_new_full(g_str_hash,g_str_equal,
+                       (GDestroyNotify)dirs_used_hash_key_destroy_func,
+                       (GDestroyNotify)NULL);
+
+       /* FIXME: locking! */
+       if (!(mntentfiler=setmntent(FILENAME_ETC_FSTAB,"r")))
+               g_error(_("Cannot open \"%s\" for reading: %m"),FILENAME_ETC_FSTAB);
+       if (!(mntentfilew=setmntent((optarg_dry ? "/dev/null" : FILENAME_ETC_FSTAB_TMP),"w")))
+               g_error(_("Cannot open \"%s\" for writing: %m"),FILENAME_ETC_FSTAB_TMP);
+
+       switch (optarg_mode) {
+
+               case OPTARG_MODE_ADD: {
+GHashTable *devices_hash;
+struct mntent *mntent;
+
+                       devices_hash=devices_hash_get();
+                       while ((mntent=getmntent(mntentfiler))) {
+                               if (!g_hash_table_lookup(devices_hash,mntent->mnt_fsname)) {
+                                       if (!strcmp(mntent->mnt_type,"captive-ntfs")
+                                                       && !strncmp(mntent->mnt_fsname,"/dev/",strlen("/dev/"))) {
+                                               g_warning(_("Dropping no-longer valid captive filesystem mntent from \"%s\" of device: %s"),
+                                                               FILENAME_ETC_FSTAB,mntent->mnt_fsname);
+                                               modified=TRUE;
+                                               continue;
+                                               }
+                                       if (addmntent(mntentfilew,mntent))
+                                               g_error(_("Error copying mntent for device \"%s\": %m"),mntent->mnt_fsname);
+                                       g_hash_table_insert(dirs_used_hash,g_strdup(mntent->mnt_dir),dirs_used_hash);
+                                       }
+                               else {
+                                       /* Original mntent is dropped to be replaced by new one. */
+                                       if (optarg_verbose)
+                                               g_message(_("Dropping captive mntent to be replaced by new one: %s"),mntent->mnt_fsname);
+                                       modified=TRUE;
+                                       }
+                               }
+                       if (g_hash_table_size(devices_hash))
+                               modified=TRUE;
+                       g_hash_table_foreach(devices_hash,
+                                       (GHFunc)mntent_add_devices_hash_entry,  /* func */
+                                       mntentfilew);   /* user_data */
+                       g_hash_table_destroy(devices_hash);
+                       } break;
+
+               case OPTARG_MODE_REMOVE: {
+struct mntent *mntent;
+
+                       while ((mntent=getmntent(mntentfiler))) {
+                               if (!strcmp(mntent->mnt_type,"captive-ntfs")
+                                               && !strncmp(mntent->mnt_fsname,"/dev/",strlen("/dev/"))) {
+                                       if (optarg_verbose)
+                                               g_message(_("Dropping captive mntent: %s"),mntent->mnt_fsname);
+                                       if (optarg_dry || !rmdir(mntent->mnt_dir)) {
+                                               if (optarg_verbose)
+                                                       g_message(_("Deleted mount directory for device \"%s\": %s"),
+                                                                       mntent->mnt_fsname,mntent->mnt_dir);
+                                               }
+                                       else if (errno!=EEXIST)
+                                               g_warning(_("Error removing mount directory \"%s\" of device \"%s\": %m"),
+                                                               mntent->mnt_dir,mntent->mnt_fsname);
+                                       modified=TRUE;
+                                       continue;
+                                       }
+                               if (addmntent(mntentfilew,mntent))
+                                       g_error(_("Error copying mntent for device \"%s\": %m"),mntent->mnt_fsname);
+                               }
+                       } break;
+               }
+
+       if (optarg_verbose)
+               g_message(_("Modified status: %s"),(modified ? _("YES") : _("NO")));
+       if (1!=endmntent(mntentfiler))
+               g_error(_("Cannot close \"%s\" after reading: %m"),FILENAME_ETC_FSTAB);
+       if (!optarg_dry) {
+               if (fchmod(fileno(mntentfilew),0644))
+                       g_error(_("Cannot set permissions for \"%s\" after writing: %m"),FILENAME_ETC_FSTAB_TMP);
+               }
+       if (1!=endmntent(mntentfilew))
+               g_error(_("Cannot close \"%s\" after writing: %m"),FILENAME_ETC_FSTAB_TMP);
+       if (!optarg_dry) {
+               if (modified) {
+                       if (!access(FILENAME_ETC_FSTAB_BACKUP,F_OK)) {
+                               if (optarg_verbose)
+                                       g_message(_("Backup file exists - keeping it intact: %s"),FILENAME_ETC_FSTAB_BACKUP);
+                               }
+                       else if (errno==ENOENT) {
+                               if (optarg_verbose)
+                                       g_message(_("File \"%s\" backed up to: %s"),FILENAME_ETC_FSTAB,FILENAME_ETC_FSTAB_BACKUP);
+                               if (rename(FILENAME_ETC_FSTAB,FILENAME_ETC_FSTAB_BACKUP))
+                                       g_warning(_("Cannot backup \"%s\" to \"%s\": %m"),FILENAME_ETC_FSTAB,FILENAME_ETC_FSTAB_BACKUP);
+                               }
+                       else
+                               g_warning(_("Backup file \"%s\" state unknown: %m"),FILENAME_ETC_FSTAB_BACKUP);
+                       if (rename(FILENAME_ETC_FSTAB_TMP,FILENAME_ETC_FSTAB))
+                               g_error(_("Cannot move new \"%s\" over old \"%s\": %m"),FILENAME_ETC_FSTAB_TMP,FILENAME_ETC_FSTAB);
+                       }
+               else {
+                       if (unlink(FILENAME_ETC_FSTAB_TMP))
+                               g_error(_("Cannot remove new unmodified \"%s\": %m"),FILENAME_ETC_FSTAB_TMP);
+                       }
+               }
+
+       return EXIT_SUCCESS;
+}