Initial original import from: fuse-2.4.2-2.fc4
[captive.git] / src / install / fstab / main.c
index 4563fe3..1739a44 100644 (file)
@@ -17,6 +17,8 @@
  */
 
 
+#define _GNU_SOURCE 1  /* for memrchr() */
+
 #include "config.h"
 
 #undef FALSE
 #include <sys/stat.h>
 #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>
 
@@ -82,66 +87,6 @@ static const struct poptOption popt_table[]={
                };
 
 
-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;
 
@@ -153,15 +98,27 @@ static void dirs_used_hash_key_destroy_func(gchar *dir)
 }
 
 
-static void mntent_add_devices_hash_entry(const gchar *device,const gchar *vol_name,FILE *mntentfilew /* user_data */)
+static void mntent_add_proc_partitions_ntfs_hash_entry
+               (const gchar *device,const gchar *vol_name,FILE *mntentfilew /* user_data */)
 {
 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);
@@ -186,7 +143,7 @@ gint dir_count;
                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 ! */
+       mntent_local.mnt_opts="defaults,noauto";        /* '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))
@@ -201,11 +158,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 */
@@ -244,47 +202,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 *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;
-                                       }
+       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(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;
+                       }
+               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)) {
@@ -297,12 +261,38 @@ 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 {
+                                               /* 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;
+                                       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")));