--add no longer replaces existing "captive-ntfs" entries by default.
[captive.git] / src / install / fstab / main.c
index 8ceb142..29d1410 100644 (file)
@@ -17,6 +17,8 @@
  */
 
 
+#define _GNU_SOURCE 1  /* for memrchr() */
+
 #include "config.h"
 
 #undef FALSE
 #include <errno.h>
 #include <unistd.h>
 #include "../libcaptive-install/proc_partitions.h"
+#include <ctype.h>
 
 #include <captive/macros.h>
+#include <captive/client.h>
 
 #include <ntfs/volume.h>
 
@@ -52,6 +56,7 @@
 
 static int optarg_verbose;
 static int optarg_dry;
+static int optarg_replace;
 enum optarg_mode {
                OPTARG_MODE_UNDEF =0,
                OPTARG_MODE_ADD   =1,
@@ -76,6 +81,7 @@ static const struct poptOption popt_table[]={
                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),
+               BUG_FSTAB_POPT(0  ,"replace",POPT_ARG_NONE,&optarg_replace,0,N_("Replace existing entries by new ones on --add"),NULL),
 
 #undef BUG_FSTAB_POPT
                POPT_AUTOHELP
@@ -99,11 +105,22 @@ static void mntent_add_proc_partitions_ntfs_hash_entry
 {
 struct mntent mntent_local;
 gint dir_count;
+gchar *s;
 
        g_return_if_fail(device!=NULL);
        g_return_if_fail(vol_name!=NULL);
        g_return_if_fail(mntentfilew!=NULL);
 
+       vol_name=captive_strdup_alloca(vol_name);
+       for (s=(/* de-const */ gchar *)vol_name;*s;s++) {
+               if (!isalnum(*s))
+                       *s='_';
+               else
+                       *s=tolower(*s);
+               }
+       if (!*vol_name)
+               vol_name="noname";
+
        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);
@@ -143,11 +160,12 @@ poptContext context;
 int errint;
 FILE *mntentfiler,*mntentfilew;
 gboolean modified=FALSE;
+GHashTable *proc_partitions_ntfs_hash;
+struct mntent *mntent;
+gchar *mntent_mem=NULL;
+size_t mntent_mem_alloc=0;
 
-       /* Initialize the i18n stuff */
-       setlocale(LC_ALL,"");
-       bindtextdomain(PACKAGE,LOCALEDIR);
-       textdomain(PACKAGE);
+       captive_standalone_init();
 
        context=poptGetContext(
                        PACKAGE,        /* name */
@@ -186,47 +204,53 @@ gboolean modified=FALSE;
        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 *proc_partitions_ntfs_hash;
-struct mntent *mntent;
-
-                       proc_partitions_ntfs_hash=proc_partitions_ntfs_hash_get(optarg_verbose);
-                       while ((mntent=getmntent(mntentfiler))) {
-                               if (!g_hash_table_lookup(proc_partitions_ntfs_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;
-                                       }
+       proc_partitions_ntfs_hash=proc_partitions_ntfs_hash_get(optarg_verbose);
+       do {
+long mntent_offset_start,mntent_offset_end;
+gchar *mntent_mem_last_line;
+size_t mntent_mem_len, mntent_mem_last_line_len;
+
+               mntent_offset_start=ftell(mntentfiler);
+               mntent=getmntent(mntentfiler);
+               mntent_offset_end=ftell(mntentfiler);
+               g_assert(mntent_offset_end>=mntent_offset_start);
+               mntent_mem_len=mntent_offset_end-mntent_offset_start;
+               if (mntent_mem_len>mntent_mem_alloc) {
+                       g_free(mntent_mem);
+                       mntent_mem_alloc=2*mntent_mem_len;
+                       mntent_mem=g_malloc(mntent_mem_alloc);
+                       }
+               if (fseek(mntentfiler,mntent_offset_start,SEEK_SET))
+                       g_warning(_("Error seeking in \"%s\": %m"),FILENAME_ETC_FSTAB);
+               if (mntent_mem_len!=fread(mntent_mem,1,mntent_mem_len,mntentfiler))
+                       g_warning(_("Error reading \"%s\": %m"),FILENAME_ETC_FSTAB);
+               mntent_mem_last_line=NULL;
+               if (mntent_offset_end!=ftell(mntentfiler))
+                       g_warning(_("Invalid position in \"%s\" after fread(3): %m"),FILENAME_ETC_FSTAB);
+               if (mntent_mem_len) {
+size_t comments_len;
+
+                       if (mntent_mem[mntent_mem_len-1]!='\n')
+                               g_warning(_("mntent memory block not newline-terminated from \"%s\""),FILENAME_ETC_FSTAB);
+                       if ((mntent_mem_last_line=memrchr(mntent_mem,'\n',mntent_mem_len-1))) {
+                               mntent_mem_last_line++;
+                               comments_len=mntent_mem_last_line-mntent_mem;
+                               mntent_mem_last_line_len=mntent_mem_len-comments_len;
+                               if (comments_len!=fwrite(mntent_mem,1,comments_len,mntentfilew))
+                                       g_error(_("Error copying comments before device \"%s\" to \"%s\": %m"),
+                                                       (!mntent ? "<none>" : mntent->mnt_fsname),FILENAME_ETC_FSTAB_TMP);
                                }
-                       if (g_hash_table_size(proc_partitions_ntfs_hash))
-                               modified=TRUE;
-                       g_hash_table_foreach(proc_partitions_ntfs_hash,
-                                       (GHFunc)mntent_add_proc_partitions_ntfs_hash_entry,     /* func */
-                                       mntentfilew);   /* user_data */
-                       g_hash_table_destroy(proc_partitions_ntfs_hash);
-                       } break;
-
-               case OPTARG_MODE_REMOVE: {
-struct mntent *mntent;
+                       }
+               if (!mntent_mem_last_line) {
+                       mntent_mem_last_line=mntent_mem;
+                       mntent_mem_last_line_len=mntent_mem_len;
+                       }
+               if (mntent
+                               && !strcmp(mntent->mnt_type,"captive-ntfs")
+                               && !strncmp(mntent->mnt_fsname,"/dev/",strlen("/dev/"))) {
+                       switch (optarg_mode) {
 
-                       while ((mntent=getmntent(mntentfiler))) {
-                               if (!strcmp(mntent->mnt_type,"captive-ntfs")
-                                               && !strncmp(mntent->mnt_fsname,"/dev/",strlen("/dev/"))) {
+                               case OPTARG_MODE_REMOVE:
                                        if (optarg_verbose)
                                                g_message(_("Dropping captive mntent: %s"),mntent->mnt_fsname);
                                        if (optarg_dry || !rmdir(mntent->mnt_dir)) {
@@ -239,12 +263,47 @@ struct mntent *mntent;
                                                                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);
+                                       /* NOTREACHED */
+
+                               case OPTARG_MODE_ADD:
+                                       if (!g_hash_table_lookup(proc_partitions_ntfs_hash,mntent->mnt_fsname))
+                                               g_warning(_("Dropping no-longer valid captive filesystem mntent from \"%s\" of device: %s"),
+                                                               FILENAME_ETC_FSTAB,mntent->mnt_fsname);
+                                       else if (optarg_replace) {
+                                               /* 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);
+                                               }
+                                       else {
+gboolean errbool;
+
+                                               errbool=g_hash_table_remove(proc_partitions_ntfs_hash,mntent->mnt_fsname);
+                                               g_assert(errbool);
+                                               if (optarg_verbose)
+                                                       g_message(_("Keeping existing captive mntent: %s"),mntent->mnt_fsname);
+                                               break;
+                                               }
+                                       modified=TRUE;
+                                       continue;
+                                       /* NOTREACHED */
+                               
+                               default: g_assert_not_reached();
                                }
-                       } break;
+                       }
+               if (mntent_mem_last_line_len!=fwrite(mntent_mem_last_line,1,mntent_mem_last_line_len,mntentfilew))
+                       g_error(_("Error copying mntent for device \"%s\" to \"%s\": %m"),mntent->mnt_fsname,FILENAME_ETC_FSTAB_TMP);
+               if (mntent)
+                       g_hash_table_insert(dirs_used_hash,g_strdup(mntent->mnt_dir),dirs_used_hash);
+               } while (mntent);
+       g_free(mntent_mem);
+       if (optarg_mode==OPTARG_MODE_ADD) {
+               if (g_hash_table_size(proc_partitions_ntfs_hash))
+                       modified=TRUE;
+               g_hash_table_foreach(proc_partitions_ntfs_hash,
+                               (GHFunc)mntent_add_proc_partitions_ntfs_hash_entry,     /* func */
+                               mntentfilew);   /* user_data */
                }
+       g_hash_table_destroy(proc_partitions_ntfs_hash);
 
        if (optarg_verbose)
                g_message(_("Modified status: %s"),(modified ? _("YES") : _("NO")));