*/
+#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>
};
-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 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);
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))
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 */
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)) {
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")));