Files
extra/pmount-safe-removal/fix-package.patch
2025-06-22 20:39:04 -05:00

1321 lines
46 KiB
Diff

diff -r 97fe1772e5c4 src/Makefile.am
--- a/src/Makefile.am Sun Nov 20 20:46:53 2011 +0100
+++ b/src/Makefile.am Mon Nov 21 15:00:50 2011 +0100
@@ -2,11 +2,12 @@
noinst_LIBRARIES = libpmount-util.a
libpmount_util_a_SOURCES = \
- fs.c \
- luks.c \
- policy.c \
- utils.c \
- realpath.c
+ fs.c \
+ luks.c \
+ policy.c \
+ utils.c \
+ realpath.c \
+ conf.c
if PMOUNT_HAL
EXTRABIN=pmount-hal
@@ -25,11 +26,12 @@
pumount_LDADD = libpmount-util.a
EXTRA_DIST = \
- fs.h \
- luks.h \
- policy.h \
- utils.h \
- realpath.h
+ fs.h \
+ luks.h \
+ policy.h \
+ utils.h \
+ realpath.h \
+ conf.h
INSTALL_DIR = $(DESTDIR)/$(prefix)/bin
INSTALL_SRC = $(top_builddir)/src
diff -r 97fe1772e5c4 src/Makefile.in
--- a/src/Makefile.in Sun Nov 20 20:46:53 2011 +0100
+++ b/src/Makefile.in Mon Nov 21 15:00:50 2011 +0100
@@ -52,7 +52,8 @@
libpmount_util_a_AR = $(AR) $(ARFLAGS)
libpmount_util_a_LIBADD =
am_libpmount_util_a_OBJECTS = fs.$(OBJEXT) luks.$(OBJEXT) \
- policy.$(OBJEXT) utils.$(OBJEXT) realpath.$(OBJEXT)
+ policy.$(OBJEXT) utils.$(OBJEXT) realpath.$(OBJEXT) \
+ conf.$(OBJEXT)
libpmount_util_a_OBJECTS = $(am_libpmount_util_a_OBJECTS)
@PMOUNT_HAL_TRUE@am__EXEEXT_1 = pmount-hal$(EXEEXT)
am__installdirs = "$(DESTDIR)$(bindir)"
@@ -106,6 +107,7 @@
DATADIRNAME = @DATADIRNAME@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
@@ -141,6 +143,7 @@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MKINSTALLDIRS = @MKINSTALLDIRS@
MSGFMT = @MSGFMT@
@@ -179,6 +182,7 @@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
@@ -211,7 +215,6 @@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
-lt_ECHO = @lt_ECHO@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
@@ -230,11 +233,12 @@
INCLUDES = $(HAL_CFLAGS)
noinst_LIBRARIES = libpmount-util.a
libpmount_util_a_SOURCES = \
- fs.c \
- luks.c \
- policy.c \
- utils.c \
- realpath.c
+ fs.c \
+ luks.c \
+ policy.c \
+ utils.c \
+ realpath.c \
+ conf.c
@PMOUNT_HAL_TRUE@EXTRABIN = pmount-hal
pmount_SOURCES = pmount.c
@@ -244,11 +248,12 @@
pumount_SOURCES = pumount.c
pumount_LDADD = libpmount-util.a
EXTRA_DIST = \
- fs.h \
- luks.h \
- policy.h \
- utils.h \
- realpath.h
+ fs.h \
+ luks.h \
+ policy.h \
+ utils.h \
+ realpath.h \
+ conf.h
INSTALL_DIR = $(DESTDIR)/$(prefix)/bin
INSTALL_SRC = $(top_builddir)/src
@@ -361,6 +366,7 @@
distclean-compile:
-rm -f *.tab.c
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/luks.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pmount-hal.Po@am__quote@
diff -r 97fe1772e5c4 src/conf.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/conf.c Mon Nov 21 15:00:50 2011 +0100
@@ -0,0 +1,137 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+
+#include "conf.h"
+#include "utils.h"
+#include "realpath.h"
+
+#define BUFLEN 1024
+
+int
+get_conf_for_device(const char *device, char **fs, char **charset,
+ char **passphrase, char **mntpt, char **options)
+{
+ FILE *f;
+ char buffer[BUFLEN], section[PATH_MAX];
+ char *buf, *sec, *s;
+ int skip_section = 0;
+ int in_section = 0;
+ int len;
+
+ if( NULL == ( f = fopen( CONF_FILE, "r" ) ) ) {
+ debug( "unable to open conf file %s\n", CONF_FILE );
+ return 1;
+ }
+ sec = NULL;
+ while( !feof( f ) ) {
+ if( fgets( buffer, BUFLEN, f ) ) {
+ /* skip spaces & tabs */
+ for ( buf = buffer; *buf == ' ' || *buf == '\t'; ++buf )
+ ;
+ /* ignore commented & empty lines */
+ if( *buf == ';' || *buf == '#' || *buf == '\n' ) {
+ continue;
+ }
+ /* new section? */
+ if( *buf == '[' ) {
+ /* if we were in section, we're done */
+ if( in_section ) {
+ break;
+ }
+ ++buf;
+ if( NULL == ( s = strchr( buf, ']' ) ) ) {
+ fclose( f );
+ fprintf( stderr, "invalid syntax in %s: %s\n", CONF_FILE, buf );
+ return 2;
+ }
+ if( s - buf >= PATH_MAX ) {
+ fclose( f );
+ fprintf( stderr, "invalid section name in %s: %s\n", CONF_FILE, buf );
+ return 3;
+ }
+ strncpy( section, buf, s - buf );
+ /* NULL-terminate the string */
+ s = section + (s - buf);
+ *s = 0;
+ debug( "found section for %s\n", section );
+ /* try to resolve, might be e.g. a /dev/disk/by-uuid/... */
+ if( !realpath( section, section ) ) {
+ if( !is_block( section ) ) {
+ /* probably section for a device not plugged in */
+ debug( "unable to resolve, not a block, skipping section\n" );
+ skip_section = 1;
+ continue;
+ }
+ } else {
+ debug( "resolved to %s\n", section );
+ }
+ /* is this the device we're looking for? */
+ if( strcmp( device, section ) ) {
+ debug( "no match, skipping section\n" );
+ skip_section = 1;
+ continue;
+ }
+ debug( "match found!\n" );
+ sec = section;
+ skip_section = 0;
+ in_section = 1;
+ continue;
+ } else if( skip_section ) {
+ continue;
+ } else if( NULL == sec ) {
+ fclose( f );
+ debug( "no matching section found\n" );
+ return -1;
+ }
+ /* we're in a section, must be a name=value */
+ if ( NULL == ( s = strchr( buf, '=' ) ) ) {
+ fprintf( stderr, "invalid syntax in %s: %s\n", CONF_FILE, buf );
+ continue;
+ }
+ /* ignore spaces & tabs */
+ for ( --s; *s == ' ' || *s == '\t'; --s )
+ ;
+ ++s;
+ len = s - buf;
+ if( NULL != fs && !strncmp( buf, "fs", len ) ) {
+ conf_set_value( buf, fs );
+ debug( "file system set to %s\n", *fs );
+ } else if( NULL != charset && !strncmp( buf, "charset", len )) {
+ conf_set_value( buf, charset );
+ debug( "charset set to %s\n", *charset );
+ } else if( NULL != passphrase && !strncmp( buf, "passphrase", len )) {
+ conf_set_value( buf, passphrase );
+ debug( "passphrase set to %s\n", *passphrase );
+ } else if( NULL != mntpt && !strncmp( buf, "mntpt", len )) {
+ conf_set_value( buf, mntpt );
+ debug( "mount point set to %s\n", *mntpt );
+ } else if( NULL != options && !strncmp( buf, "options", len )) {
+ conf_set_value( buf, options );
+ debug( "options set to %s\n", *options );
+ } else {
+ debug( "ignoring: %s", buf );
+ }
+ }
+ }
+ fclose( f );
+ return !in_section;
+}
+
+void
+conf_set_value( char *buf, char **dest )
+{
+ char *s;
+ /* position to beginning of value */
+ buf = strchr( buf, '=' );
+ /* skip spaces & tabs */
+ for( ++buf; *buf == ' ' || *buf == '\t'; ++buf)
+ ;
+ /* find end position */
+ for( s = buf; *s != ' ' && *s != ';' && *s != '#' && *s != '\n' && *s != 0; ++s)
+ ;
+ /* set value */
+ *dest = strndup( buf, s - buf );
+}
diff -r 97fe1772e5c4 src/conf.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/conf.h Mon Nov 21 15:00:50 2011 +0100
@@ -0,0 +1,17 @@
+
+#ifndef CONF_H
+#define CONF_H
+
+#define CONF_FILE "/etc/pmount.conf"
+
+
+int
+get_conf_for_device(const char *device, char **fs, char **charset,
+ char **passphrase, char **mntpt, char **options);
+
+void
+conf_set_value( char *buf, char **dest );
+
+
+#endif /* CONF_H */
+
diff -r 97fe1772e5c4 src/luks.c
--- a/src/luks.c Sun Nov 20 20:46:53 2011 +0100
+++ b/src/luks.c Mon Nov 21 15:00:50 2011 +0100
@@ -82,7 +82,7 @@
else if( status == 1 )
result = DECRYPT_FAILED;
else {
- fprintf( stderr, "Internal error: cryptsetup luksOpen failed" );
+ fprintf( stderr, "Internal error: cryptsetup luksOpen failed\n" );
exit( 100 );
}
diff -r 97fe1772e5c4 src/pmount.c
--- a/src/pmount.c Sun Nov 20 20:46:53 2011 +0100
+++ b/src/pmount.c Mon Nov 21 15:00:50 2011 +0100
@@ -28,6 +28,7 @@
#include "policy.h"
#include "utils.h"
#include "luks.h"
+#include "conf.h"
#include "config.h"
/* Enable autodetection if possible */
@@ -82,6 +83,7 @@
" -s, --sync : mount <device> with the 'sync' option (default: 'async')\n"
" -A, --noatime\n"
" mount <device> with the 'noatime' option (default: 'atime')\n"
+ " -D : mount all partitions of <device> (or its parent, if a partition)\n"
" -e, --exec : mount <device> with the 'exec' option (default: 'noexec')\n"
" -t <fs> : mount as file system type <fs> (default: autodetected)\n"
" -c <charset>: use given I/O character set (default: 'utf8' if called\n"
@@ -223,6 +225,7 @@
* @param fmask User specified fmask (NULL for umask)
* @param dmask User specified dmask (NULL for umask)
* @param suppress_errors: if true, stderr is redirected to /dev/null
+ * @param fs_options Options to use instead of the default from FS (if not NULL)
* @return exit status of mount, or -1 on failure.
*/
int
@@ -230,7 +233,8 @@
int noatime, int exec, int force_write, const char* iocharset,
int utf8,
const char* umask, const char *fmask, const char *dmask,
- int suppress_errors )
+ int suppress_errors,
+ const char *fs_options )
{
const struct FS* fs;
char ugid_opt[100];
@@ -370,9 +374,13 @@
snprintf( iocharset_opt, sizeof( iocharset_opt ),
fs->iocharset_format, "iso8859-1");
}
+
+ if( NULL == fs_options ) {
+ fs_options = fs->options;
+ }
snprintf( options, sizeof( options ), "%s%s%s%s%s%s%s%s%s",
- fs->options, sync_opt, atime_opt, exec_opt, access_opt, ugid_opt,
+ fs_options, sync_opt, atime_opt, exec_opt, access_opt, ugid_opt,
umask_opt, fdmask_opt, iocharset_opt );
/* go for it */
@@ -397,13 +405,15 @@
* @param umask User specified umask (NULL for default)
* @param fmask User specified fmask (NULL for umask)
* @param dmask User specified dmask (NULL for umask)
+ * @param fs_options Options to use instead of the default from FS (if not NULL)
* @return last return value of do_mount (i. e. 0 on success, != 0 on error)
*/
int
do_mount_auto( const char* device, const char* mntpt, int async,
int noatime, int exec, int force_write, const char* iocharset,
int utf8,
- const char* umask, const char *fmask, const char *dmask )
+ const char* umask, const char *fmask, const char *dmask,
+ const char *fs_options )
{
const struct FS* fs;
int nostderr = 1;
@@ -424,7 +434,7 @@
}
result = do_mount( device, mntpt, tp, async, noatime, exec,
force_write, iocharset, utf8, umask, fmask,
- dmask, nostderr );
+ dmask, nostderr, fs_options );
if(result == 0)
return result;
debug("blkid-detected FS failed, trying manually \n");
@@ -445,14 +455,16 @@
if( (fs+1)->fsname == NULL )
nostderr = 0;
result = do_mount( device, mntpt, fs->fsname, async, noatime, exec,
- force_write, iocharset, utf8, umask, fmask, dmask, nostderr );
+ force_write, iocharset, utf8, umask, fmask, dmask, nostderr,
+ fs_options );
if( result == 0 )
break;
/* sometimes VFAT fails when using iocharset; try again without */
if( iocharset )
result = do_mount( device, mntpt, fs->fsname, async, noatime, exec,
- force_write, NULL, utf8, umask, fmask, dmask, nostderr );
+ force_write, NULL, utf8, umask, fmask, dmask, nostderr,
+ fs_options );
if( result <= 0 )
break;
}
@@ -602,33 +614,207 @@
drop_root();
}
+
+static char *devarg = NULL, *arg2 = NULL;
+static char mntpt[MEDIA_STRING_SIZE];
+static char device[PATH_MAX], mntptdev[PATH_MAX];
+static int async = 1;
+static int noatime = 0;
+static int exec = 0;
+static int force_write = -1; /* 0: ro, 1: rw, -1: default */
+static const char* use_fstype = NULL;
+static const char* iocharset = NULL;
+static const char* _umask = NULL;
+static const char* _fmask = NULL;
+static const char* _dmask = NULL;
+static const char* passphrase = NULL;
+
+static enum { MOUNT, LOCK, UNLOCK } mode = MOUNT;
+
+int
+mount_device( void )
+{
+ char decrypted_device[PATH_MAX];
+ int utf8 = -1; /* Whether we live in a UTF-8 world or not */
+ int result;
+
+ static const char *l_use_fstype;
+ static const char *l_iocharset;
+ static const char *l_passphrase;
+
+ char *o_fs = NULL;
+ char *o_charset = NULL;
+ char *o_passphrase = NULL;
+ char *o_mntpt = NULL;
+ char *o_options = NULL;
+
+ l_use_fstype = use_fstype;
+ l_iocharset = iocharset;
+ l_passphrase = passphrase;
+
+ switch( mode ) {
+ case MOUNT:
+ /* let's see if there are options in CONF_FILE */
+ if( !get_conf_for_device( device, &o_fs, &o_charset, &o_passphrase,
+ &o_mntpt, &o_options ) ) {
+ if( NULL != o_fs ) {
+ l_use_fstype = (const char *) o_fs;
+ }
+ if( NULL != o_charset ) {
+ l_iocharset = (const char *) o_charset;
+ }
+ if( NULL != o_passphrase ) {
+ l_passphrase = (const char *) o_passphrase;
+ }
+ if( NULL != o_mntpt ) {
+ snprintf( mntpt, sizeof (mntpt ), "%s", o_mntpt );
+ }
+ }
+
+ /* determine mount point name; note that we use devarg instead of
+ * device to preserve symlink names (like '/dev/usbflash' instead
+ * of '/dev/sda1') */
+ if( NULL == o_mntpt && make_mountpoint_name( devarg, arg2, mntpt,
+ sizeof( mntpt ) ) )
+ return E_MNTPT;
+
+ /* if no charset was set explicitly, autodetect UTF-8 */
+ if( !l_iocharset ) {
+ const char* codeset;
+ codeset = nl_langinfo( CODESET );
+
+ debug( "no iocharset given, current locale encoding is %s\n", codeset );
+
+ if( codeset && !strcmp( codeset, "UTF-8" ) ) {
+ debug( "locale encoding uses UTF-8, setting iocharset to 'utf8'\n" );
+ l_iocharset = "utf8";
+ }
+ }
+ /* If user did not choose explicitly for or against utf8 */
+ if( utf8 == -1 ) {
+ const char* codeset;
+ codeset = nl_langinfo( CODESET );
+ if( codeset && !strcmp( codeset, "UTF-8" ) ) {
+ debug( "locale encoding uses UTF-8: will mount FAT with utf8 option" );
+ utf8 = 1;
+ } else {
+ utf8 = 0;
+ }
+ }
+
+ /* clean stale locks */
+ clean_lock_dir( device );
+
+ if( check_mount_policy( device, mntpt ) )
+ return E_POLICY;
+
+ /* check for encrypted device */
+ enum decrypt_status decrypt = luks_decrypt( device,
+ decrypted_device, sizeof( decrypted_device ), l_passphrase,
+ force_write == 0 ? 1 : 0 );
+
+ switch (decrypt) {
+ case DECRYPT_FAILED:
+ fprintf( stderr, _("Error: could not decrypt device (wrong passphrase?)\n") );
+ return E_POLICY;
+ case DECRYPT_EXISTS:
+ fprintf( stderr, _("Error: mapped device already exists\n") );
+ return E_POLICY;
+ case DECRYPT_OK:
+ /* We create a luks lockfile _on the decrypted device !_*/
+ if(! luks_create_lockfile(decrypted_device))
+ fprintf(stderr, _("Warning: could not create luks lockfile\n"));
+ case DECRYPT_NOTENCRYPTED:
+ break;
+ default:
+ fprintf( stderr, "Internal error: unhandled decrypt_status %i\n",
+ (int) decrypt);
+ return E_INTERNAL;
+ }
+
+ /* lock the mount directory */
+ debug( "locking mount point directory\n" );
+ if( lock_dir( mntpt ) < 0) {
+ fprintf( stderr, _("Error: could not lock the mount directory. Another pmount is probably running for this mount point.\n"));
+ return E_LOCKED;
+ }
+ debug( "mount point directory locked\n" );
+
+ /* off we go */
+ if( l_use_fstype )
+ result = do_mount( decrypted_device, mntpt, l_use_fstype, async, noatime,
+ exec, force_write, l_iocharset, utf8, _umask, _fmask, _dmask, 0,
+ o_options);
+ else
+ result = do_mount_auto( decrypted_device, mntpt, async, noatime, exec,
+ force_write, l_iocharset, utf8, _umask, _fmask, _dmask, o_options );
+
+ /* unlock the mount point again */
+ debug( "unlocking mount point directory\n" );
+ unlock_dir( mntpt );
+ debug( "mount point directory unlocked\n" );
+
+ if( NULL != o_fs ) {
+ free( o_fs );
+ }
+ if( NULL != o_charset ) {
+ free( o_charset );
+ }
+ if( NULL != o_passphrase ) {
+ free( o_passphrase );
+ }
+ if( NULL != o_mntpt ) {
+ free( o_mntpt );
+ }
+ if( NULL != o_options ) {
+ free( o_options );
+ }
+
+ if( result ) {
+ if( decrypt == DECRYPT_OK )
+ luks_release( decrypted_device, 0 );
+
+ /* mount failed, delete the mount point again */
+ if( remove_pmount_mntpt( mntpt ) ) {
+ perror( _("Error: could not delete mount point") );
+ return -1;
+ }
+ return E_EXECMOUNT;
+ }
+
+ return 0;
+
+ case LOCK:
+ if( device_valid( device ) )
+ if( do_lock( device, parse_unsigned( arg2, E_PID ) ) )
+ return E_INTERNAL;
+ return 0;
+
+ case UNLOCK:
+ if( device_valid( device ) )
+ if( do_unlock( device, parse_unsigned( arg2, E_PID ) ) )
+ return E_UNLOCK;
+ return 0;
+ }
+
+ fprintf( stderr, _("Internal error: mode %i not handled.\n"), (int) mode );
+ return E_INTERNAL;
+}
+
+
+
/**
* Entry point.
*/
int
main( int argc, char** argv )
{
- char *devarg = NULL, *arg2 = NULL;
- char mntpt[MEDIA_STRING_SIZE];
- char device[PATH_MAX], mntptdev[PATH_MAX];
- char decrypted_device[PATH_MAX];
const char* fstab_device;
int is_real_path = 0;
- int async = 1;
- int noatime = 0;
- int exec = 0;
- int force_write = -1; /* 0: ro, 1: rw, -1: default */
- const char* use_fstype = NULL;
- const char* iocharset = NULL;
- const char* umask = NULL;
- const char* fmask = NULL;
- const char* dmask = NULL;
- const char* passphrase = NULL;
- int utf8 = -1; /* Whether we live in a UTF-8 world or not */
- int result;
+ int full_device = 0;
- enum { MOUNT, LOCK, UNLOCK } mode = MOUNT;
-
+ int result, error_occurred = 0;
+
int option;
static struct option long_opts[] = {
{ "help", 0, NULL, 'h'},
@@ -647,6 +833,7 @@
{ "read-only", 0, NULL, 'r' },
{ "read-write", 0, NULL, 'w' },
{ "version", 0, NULL, 'V' },
+ { "full-device", 0, NULL, 'D' },
{ NULL, 0, NULL, 0}
};
@@ -678,7 +865,7 @@
/* parse command line options */
do {
- switch( option = getopt_long( argc, argv, "+hdelLsArwp:t:c:u:V", long_opts, NULL ) ) {
+ switch( option = getopt_long( argc, argv, "+hdelLsArwp:t:c:u:DV", long_opts, NULL ) ) {
case -1: break; /* end of arguments */
case ':':
case '?': return E_ARGS; /* unknown argument */
@@ -701,17 +888,19 @@
case 'c': iocharset = optarg; break;
- case 'u': umask = optarg; break;
+ case 'u': _umask = optarg; break;
- case OPT_FMASK: fmask = optarg; break;
+ case OPT_FMASK: _fmask = optarg; break;
- case OPT_DMASK: dmask = optarg; break;
+ case OPT_DMASK: _dmask = optarg; break;
case 'p': passphrase = optarg; break;
case 'r': force_write = 0; break;
case 'w': force_write = 1; break;
+
+ case 'D': full_device = 1; break;
case 'V': puts(VERSION); return 0;
@@ -793,117 +982,76 @@
fprintf( stderr, _("Error: invalid device %s (must be in /dev/)\n"), device );
return E_DEVICE;
}
+
+ /* we need to get the full device name (e.g. /dev/sde), get list of all its
+ partitions, and try to mount them all... */
+ if( full_device ) {
+ char devdirname[MEDIA_STRING_SIZE];
+ if( !find_sysfs_device( device, devdirname, MEDIA_STRING_SIZE) ) {
+ fprintf( stderr, _("Warning: unable to find device path for %s,"
+ " full-device mode disabled\n"), device );
+ full_device = 0;
+ } else {
+ debug( "device path for %s is %s\n", device, devdirname );
+
+ DIR *partdir;
+ struct dirent *partdirent;
+ char partdirname[MEDIA_STRING_SIZE];
+ struct stat stat_info;
+
+ partdir = opendir( devdirname );
+ if( !partdir ) {
+ perror( _("Error: could not open <sysfs dir>/block/<device>/") );
+ exit( -1 );
+ }
+ while( ( partdirent = readdir( partdir ) ) != NULL ) {
+ if( partdirent->d_type != DT_DIR
+ || !strcmp( partdirent->d_name, "." )
+ || !strcmp( partdirent->d_name, ".." ) )
+ continue;
+
+ /* construct /sys/block/<device>/<partition>/dev */
+ snprintf( partdirname, sizeof( partdirname ), "%s/%s/%s",
+ devdirname, partdirent->d_name, "dev" );
- switch( mode ) {
- case MOUNT:
- /* determine mount point name; note that we use devarg instead of
- * device to preserve symlink names (like '/dev/usbflash' instead
- * of '/dev/sda1') */
- if( make_mountpoint_name( devarg, arg2, mntpt, sizeof( mntpt ) ) )
- return E_MNTPT;
+ /* make sure it is a device, i.e has a file dev */
+ if( 0 != stat( partdirname, &stat_info ) ) {
+ /* ENOENT (does not exist) is "okay" we just ignore this one */
+ if( ENOENT != errno ) {
+ perror( _("Error: could not stat <sysfs dir>/block/<device>/<part>/dev") );
+ exit( -1 );
+ }
+ continue;
+ }
+ /* must be a file */
+ if( !S_ISREG( stat_info.st_mode ) ) {
+ continue;
+ }
- /* if no charset was set explicitly, autodetect UTF-8 */
- if( !iocharset ) {
- const char* codeset;
- codeset = nl_langinfo( CODESET );
-
- debug( "no iocharset given, current locale encoding is %s\n", codeset );
-
- if( codeset && !strcmp( codeset, "UTF-8" ) ) {
- debug( "locale encoding uses UTF-8, setting iocharset to 'utf8'\n" );
- iocharset = "utf8";
+ /* construct /dev/<partition> */
+ snprintf( device, sizeof( device ), "%s%s", DEVDIR, partdirent->d_name );
+ debug( "processing found partition: %s\n", device );
+
+ /* We need to lookup again in fstab: */
+ fstab_device = fstab_has_device( "/etc/fstab", device, NULL, NULL );
+ if( mode == MOUNT && fstab_device ) {
+ fprintf( stderr, _("Error: device %s handled by fstab\n"), fstab_device );
+ exit( -1 );
+ }
+
+ devarg = device;
+ result = mount_device();
+ if( result != 0 ) {
+ fprintf( stderr, _("Failed to mount device %s : error %d\n"), device, result );
+ error_occurred = -1;
+ } else {
+ printf( _("Device %s mounted\n"), device );
}
}
- /* If user did not choose explicitly for or against utf8 */
- if( utf8 == -1 ) {
- const char* codeset;
- codeset = nl_langinfo( CODESET );
- if( codeset && !strcmp( codeset, "UTF-8" ) ) {
- debug( "locale encoding uses UTF-8: will mount FAT with utf8 option" );
- utf8 = 1;
- } else {
- utf8 = 0;
- }
- }
-
- /* clean stale locks */
- clean_lock_dir( device );
-
- if( check_mount_policy( device, mntpt ) )
- return E_POLICY;
-
- /* check for encrypted device */
- enum decrypt_status decrypt = luks_decrypt( device,
- decrypted_device, sizeof( decrypted_device ), passphrase,
- force_write == 0 ? 1 : 0 );
-
- switch (decrypt) {
- case DECRYPT_FAILED:
- fprintf( stderr, _("Error: could not decrypt device (wrong passphrase?)\n") );
- exit( E_POLICY );
- case DECRYPT_EXISTS:
- fprintf( stderr, _("Error: mapped device already exists\n") );
- exit( E_POLICY );
- case DECRYPT_OK:
- /* We create a luks lockfile _on the decrypted device !_*/
- if(! luks_create_lockfile(decrypted_device))
- fprintf(stderr, _("Warning: could not create luks lockfile\n"));
- case DECRYPT_NOTENCRYPTED:
- break;
- default:
- fprintf( stderr, "Internal error: unhandled decrypt_status %i\n",
- (int) decrypt);
- exit( E_INTERNAL );
- }
-
- /* lock the mount directory */
- debug( "locking mount point directory\n" );
- if( lock_dir( mntpt ) < 0) {
- fprintf( stderr, _("Error: could not lock the mount directory. Another pmount is probably running for this mount point.\n"));
- exit( E_LOCKED );
- }
- debug( "mount point directory locked\n" );
-
- /* off we go */
- if( use_fstype )
- result = do_mount( decrypted_device, mntpt, use_fstype, async, noatime,
- exec, force_write, iocharset, utf8, umask, fmask, dmask, 0 );
- else
- result = do_mount_auto( decrypted_device, mntpt, async, noatime, exec,
- force_write, iocharset, utf8, umask, fmask, dmask );
-
- /* unlock the mount point again */
- debug( "unlocking mount point directory\n" );
- unlock_dir( mntpt );
- debug( "mount point directory unlocked\n" );
-
- if( result ) {
- if( decrypt == DECRYPT_OK )
- luks_release( decrypted_device, 0 );
-
- /* mount failed, delete the mount point again */
- if( remove_pmount_mntpt( mntpt ) ) {
- perror( _("Error: could not delete mount point") );
- return -1;
- }
- return E_EXECMOUNT;
- }
-
- return 0;
-
- case LOCK:
- if( device_valid( device ) )
- if( do_lock( device, parse_unsigned( arg2, E_PID ) ) )
- return E_INTERNAL;
- return 0;
-
- case UNLOCK:
- if( device_valid( device ) )
- if( do_unlock( device, parse_unsigned( arg2, E_PID ) ) )
- return E_UNLOCK;
- return 0;
+ closedir( partdir );
+ return error_occurred;
+ }
}
-
- fprintf( stderr, _("Internal error: mode %i not handled.\n"), (int) mode );
- return E_INTERNAL;
+
+ return mount_device();
}
diff -r 97fe1772e5c4 src/policy.c
--- a/src/policy.c Sun Nov 20 20:46:53 2011 +0100
+++ b/src/policy.c Mon Nov 21 15:00:50 2011 +0100
@@ -164,7 +164,9 @@
exit( -1 );
}
while( ( partdirent = readdir( partdir ) ) != NULL ) {
- if( partdirent->d_type != DT_DIR )
+ if( partdirent->d_type != DT_DIR
+ || !strcmp( partdirent->d_name, "." )
+ || !strcmp( partdirent->d_name, ".." ) )
continue;
/* construct /sys/block/<device>/<partition>/dev */
@@ -549,7 +551,7 @@
blockdevpath, whitelisted_bus);
}
else
- debug("Device %s does not belong to any whitelisted bus\n");
+ debug("Device %s does not belong to any whitelisted bus\n", blockdevpath);
}
return removable;
}
diff -r 97fe1772e5c4 src/pumount.c
--- a/src/pumount.c Sun Nov 20 20:46:53 2011 +0100
+++ b/src/pumount.c Mon Nov 21 15:00:50 2011 +0100
@@ -19,10 +19,14 @@
#include <getopt.h>
#include <libintl.h>
#include <locale.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <dirent.h>
#include "policy.h"
#include "utils.h"
#include "luks.h"
+#include "conf.h"
#include "config.h"
/* error codes */
@@ -46,11 +50,12 @@
" are met (see pumount(1) for details). The mount point directory is removed\n"
" afterwards.\n\n"
"Options:\n"
- " -l, --lazy : umount lazily, see umount(8)\n"
- " --luks-force : luksClose devices pmount didn't open\n"
- " -d, --debug : enable debug output (very verbose)\n"
- " -h, --help : print help message and exit successfuly\n"
- " --version : print version number and exit successfully\n"),
+ " -l, --lazy : umount lazily, see umount(8)\n"
+ " --luks-force : luksClose devices pmount didn't open\n"
+ " -D : umount all partitions of the device, then stops it for safe removal\n"
+ " -d, --debug : enable debug output (very verbose)\n"
+ " -h, --help : print help message and exit successfuly\n"
+ " -V, --version : print version number and exit successfully\n"),
exename, MEDIADIR );
}
@@ -88,9 +93,23 @@
/* mount point must be below MEDIADIR */
if( strncmp( mntpt, mediadir, strlen( mediadir ) ) ) {
- fprintf( stderr, _("Error: mount point %s is not below %s\n"), mntpt,
- MEDIADIR );
- return -1;
+ /* check CONF_FILE, it might be okay */
+ char *o_mntpt = NULL;
+ int passed = 0;
+ if( !get_conf_for_device( device, NULL, NULL, NULL, &o_mntpt, NULL ) ) {
+ if( NULL != o_mntpt ) {
+ if( !strcmp( mntpt, o_mntpt ) ) {
+ debug( "mount point allowed from config: %s\n", mntpt );
+ passed = 1;
+ }
+ free( o_mntpt );
+ }
+ }
+ if( !passed ) {
+ fprintf( stderr, _("Error: mount point %s is not below %s\n"), mntpt,
+ MEDIADIR );
+ return -1;
+ }
}
debug( "policy check passed\n" );
@@ -98,13 +117,15 @@
}
/**
- * Drop all privileges and exec 'umount device'. Does not return on success, if
- * it returns, UMOUNTPROG could not be executed.
+ * Drop all privileges and exec 'umount device'.
* @param lazy 0 for normal umount, 1 for lazy umount
+ * @return 0 on success, E_EXECUMOUNT if UMOUNTPROG could not be executed.
*/
-void
+int
do_umount_fstab( const char* device, int lazy, const char * fstab_mntpt )
{
+ int status;
+
/* drop all privileges */
get_root();
if( setuid( getuid() ) ) {
@@ -120,10 +141,16 @@
}
if( lazy )
- execl( UMOUNTPROG, UMOUNTPROG, "-l", device, NULL );
+ status = spawnl( 0, UMOUNTPROG, UMOUNTPROG, "-l", device, NULL );
else
- execl( UMOUNTPROG, UMOUNTPROG, device, NULL );
- perror( _("Error: could not execute umount") );
+ status = spawnl( 0, UMOUNTPROG, UMOUNTPROG, device, NULL );
+
+ if( status != 0 ) {
+ perror( _("Error: could not execute umount") );
+ return E_EXECUMOUNT;
+ }
+
+ return 0;
}
/**
@@ -152,6 +179,41 @@
return 0;
}
+int
+umount_device( const char* device, size_t devicesize, const char* mntpt,
+ int do_lazy, int full_device )
+{
+ const char* fstab_device;
+ char fstab_mntpt[MEDIA_STRING_SIZE];
+
+ /* in full device mode, we need to check is the device is handled by fstab */
+ if( full_device ) {
+ fstab_device = fstab_has_device( "/etc/fstab", device, fstab_mntpt, NULL );
+ if( fstab_device && device_mounted( device, 1, NULL ) ) {
+ return do_umount_fstab( fstab_device, do_lazy, fstab_mntpt );
+ }
+ /* in regular mode, we check if we have a dmcrypt device */
+ } else if( luks_get_mapped_device( device, (char *) device, devicesize ) ) {
+ debug( "Unmounting mapped device %s instead.\n", device );
+ }
+
+ /* Now, we accept when devices have gone missing */
+ if( check_umount_policy( device, 1 ) )
+ return E_POLICY;
+
+ /* go for it */
+ if( do_umount( device, do_lazy ) )
+ return E_EXECUMOUNT;
+
+ /* release LUKS device, if appropriate */
+ luks_release( device, 1 );
+
+ /* delete mount point */
+ remove_pmount_mntpt( mntpt );
+
+ return 0;
+}
+
/**
* Entry point.
*
@@ -165,6 +227,10 @@
int is_real_path = 0;
int do_lazy = 0;
int luks_force = 0;
+ int full_device = 0;
+
+ int error_occurred = 0;
+ int result;
int option;
static struct option long_opts[] = {
@@ -173,6 +239,7 @@
{ "lazy", 0, NULL, 'l'},
{ "yes-I-really-want-lazy-unmount", 0, NULL, 'R'},
{ "luks-force", 0, NULL, 'L'},
+ { "full-device", 0, NULL, 'D'},
{ "version", 0, NULL, 'V' },
{ NULL, 0, NULL, 0}
};
@@ -193,7 +260,7 @@
/* parse command line options */
do {
- switch( option = getopt_long( argc, argv, "+hdluV", long_opts, NULL ) ) {
+ switch( option = getopt_long( argc, argv, "+hdluDV", long_opts, NULL ) ) {
case -1: break; /* end of arguments */
case '?': return E_ARGS; /* unknown argument */
@@ -212,6 +279,8 @@
do_lazy = 1; break;
case 'L': luks_force = 1; break;
+
+ case 'D': full_device = 1; break;
case 'V': puts(VERSION); return 0;
@@ -251,11 +320,17 @@
snprintf( device, sizeof( device ), "%s", argv[optind] );
}
- /* is the device already handled by fstab? */
- fstab_device = fstab_has_device( "/etc/fstab", device, fstab_mntpt, NULL );
- if( fstab_device ) {
- do_umount_fstab( fstab_device, do_lazy, fstab_mntpt );
- return E_EXECUMOUNT;
+ /* in full_device mode, we'll deal with all partitions anyways */
+ if( !full_device ) {
+ /* is the device already handled by fstab? */
+ fstab_device = fstab_has_device( "/etc/fstab", device, fstab_mntpt, NULL );
+ if( fstab_device ) {
+ if( device_mounted( device, 1, NULL ) ) {
+ return do_umount_fstab( fstab_device, do_lazy, fstab_mntpt );
+ } else {
+ return 0;
+ }
+ }
}
/* we cannot really check the real path when unmounting lazily since the
@@ -271,13 +346,18 @@
}
debug( "trying to prepend '" DEVDIR
"' to device argument, now '%s'\n", device );
- /* We need to lookup again in fstab: */
- fstab_device = fstab_has_device( "/etc/fstab", device,
- fstab_mntpt, NULL );
- if( fstab_device ) {
- do_umount_fstab( fstab_device, do_lazy, fstab_mntpt );
- return E_EXECUMOUNT;
- }
+ if( !full_device ) {
+ /* We need to lookup again in fstab: */
+ fstab_device = fstab_has_device( "/etc/fstab", device,
+ fstab_mntpt, NULL );
+ if( fstab_device ) {
+ if( device_mounted( device, 1, NULL ) ) {
+ return do_umount_fstab( fstab_device, do_lazy, fstab_mntpt );
+ } else {
+ return 0;
+ }
+ }
+ }
}
}
@@ -286,24 +366,151 @@
fprintf( stderr, _("Error: invalid device %s (must be in /dev/)\n"), device );
return E_DEVICE;
}
+
+ /* we need to get the full device name (e.g. /dev/sde), get list of all its
+ partitions, and try to unmount them all... */
+ if( full_device ) {
+ char devdirname[MEDIA_STRING_SIZE];
+ if( !find_sysfs_device( device, devdirname, MEDIA_STRING_SIZE) ) {
+ fprintf( stderr, _("Warning: unable to find device path for %s, "
+ "full-device mode disabled\n"),
+ device );
+ full_device = 0;
+ } else {
+ debug( "device path for %s is %s\n", device, devdirname );
+
+ DIR *partdir;
+ struct dirent *partdirent;
+ char partdirname[MEDIA_STRING_SIZE];
+ struct stat stat_info;
+
+ partdir = opendir( devdirname );
+ if( !partdir ) {
+ perror( _("Error: could not open <sysfs dir>/block/<device>/") );
+ exit( -1 );
+ }
+ while( ( partdirent = readdir( partdir ) ) != NULL ) {
+ if( partdirent->d_type != DT_DIR
+ || !strcmp( partdirent->d_name, "." )
+ || !strcmp( partdirent->d_name, ".." ) )
+ continue;
+
+ /* construct /sys/block/<device>/<partition>/dev */
+ snprintf( partdirname, sizeof( partdirname ), "%s/%s/%s",
+ devdirname, partdirent->d_name, "dev" );
- /* check if we have a dmcrypt device */
- if( luks_get_mapped_device( device, device, sizeof( device ) ) )
- debug( "Unmounting mapped device %s instead.\n", device );
+ /* make sure it is a device, i.e has a file dev */
+ if( 0 != stat( partdirname, &stat_info ) ) {
+ /* ENOENT (does not exist) is "okay" we just ignore this one */
+ if( ENOENT != errno ) {
+ perror( _("Error: could not stat <sysfs dir>/block/<device>/<part>/dev") );
+ exit( -1 );
+ }
+ continue;
+ }
+ /* must be a file */
+ if( !S_ISREG( stat_info.st_mode ) ) {
+ continue;
+ }
- /* Now, we accept when devices have gone missing */
- if( check_umount_policy( device, 1 ) )
- return E_POLICY;
+ /* construct /dev/<partition> */
+ snprintf( device, sizeof( device ), "%s%s", DEVDIR, partdirent->d_name );
+ debug( "processing found partition: %s\n", device );
+
+ /* check if we have a dmcrypt device */
+ if( luks_get_mapped_device( device, device, sizeof( device ) ) )
+ debug( "Using mapped device %s instead.\n", device );
- /* go for it */
- if( do_umount( device, do_lazy ) )
- return E_EXECUMOUNT;
+ if( device_mounted( device, 1, mntpt ) ) {
+ debug( "device %s mounted, unmounting\n", device );
+ result = umount_device( device, sizeof( device ), mntpt,
+ do_lazy, full_device );
+ if( result != 0 ) {
+ fprintf( stderr, _("Failed to umount device %s : error %d\n"),
+ device, result );
+ error_occurred = -1;
+ } else {
+ printf( _("Device %s umounted\n"), device );
+ }
+ }
+ }
+ closedir( partdir );
+
+ /* no errors: let's stop the device completely, for safe removal */
+ if ( !error_occurred ) {
+ char *c;
+ FILE *f;
- /* release LUKS device, if appropriate */
- luks_release( device, 1 );
+ /* flush buffers */
+ sync();
+
+ /* resolve devdirname (<sysfs>/block/<device> to something like:
+ * /sys/devices/pci0000:00/0000:00:06.0/usb1/1-2/1-2:1.0/host5/target5:0:0/5:0:0:0/block/sdd */
+ if( !realpath( devdirname, device ) ) {
+ debug( "unable to resolve %s\n", device );
+ goto err_stop;
+ }
+ debug( "device %s resolved to %s\n", devdirname, device );
+
+ /* now extract the part we want, up to the grand-parent of the host
+ e.g: /sys/devices/pci0000:00/0000:00:06.0/usb1/1-2 */
+ while( c = strrchr( device, '/' ) ) {
+ /* end the string there, to move back */
+ *c = 0;
+ /* found the host part? */
+ if( !strncmp( c + 1, "host", 4 ) ) {
+ break;
+ }
+ }
+ if( c == NULL ) {
+ debug( "unable to find host for %s\n", device );
+ goto err_stop;
+ }
+ /* we need to move back one more time */
+ if( NULL == ( c = strrchr( device, '/' ) ) ) {
+ debug( "cannot move back one last time in %s\n", device );
+ goto err_stop;
+ }
+ /* end the string there */
+ *c = 0;
+ debug( "full name is %s\n", device );
+ /* now we need the last component, aka the bus id */
+ if( NULL == ( c = strrchr( device, '/' ) ) ) {
+ debug( "cannot extract last component of %s\n", device );
+ goto err_stop;
+ }
+ /* move up, so this points to the name only, e.g. 1-2 */
+ ++c;
+
+ /* unbind driver: write the bus id to <device>/driver/unbind */
+ snprintf( path, sizeof( path ), "%s/driver/unbind", device );
+ if ( root_write_to_file( path, c ) ) {
+ goto err_stop;
+ }
+
+ /* suspend device. step 1: write "0" to <device>/power/autosuspend */
+ snprintf( path, sizeof( path ), "%s/power/autosuspend", device );
+ if ( root_write_to_file( path, "0" ) ) {
+ goto err_stop;
+ }
+ /* step 2: write "auto" to <device>/power/control */
+ snprintf( path, sizeof( path ), "%s/power/control", device );
+ if ( root_write_to_file( path, "auto" ) ) {
+ goto err_stop;
+ }
+
+ c = strrchr( devdirname, '/' );
+ printf( _("Device %s%s stopped, you should now be able to safely unplug it\n"),
+ DEVDIR, c + 1);
+ }
+
+ return error_occurred;
- /* delete mount point */
- remove_pmount_mntpt( mntpt );
+err_stop:
+ fputs( _("Error: Unable to stop device\n"), stderr );
+ return -1;
+ }
+ }
- return 0;
+ return umount_device( device, sizeof( device ), mntpt, do_lazy, full_device );
}
diff -r 97fe1772e5c4 src/utils.c
--- a/src/utils.c Sun Nov 20 20:46:53 2011 +0100
+++ b/src/utils.c Mon Nov 21 15:00:50 2011 +0100
@@ -439,3 +439,27 @@
drop_root();
}
+int
+root_write_to_file( const char* path, const char* data )
+{
+ FILE *f;
+ size_t expected, actual;
+
+ get_root();
+ f = fopen( path, "w" );
+ drop_root();
+ if( !f ) {
+ debug( "could not open %s\n", path );
+ return -1;
+ }
+ expected = sizeof( char ) * strlen( data );
+ actual = fwrite( data, sizeof( char ), strlen( data ), f );
+ if( actual != expected ) {
+ fclose( f );
+ debug( "error when writing to %s; expected %d bytes, only %d written\n",
+ path, expected, actual );
+ return -1;
+ }
+ fclose( f );
+ return 0;
+}
diff -r 97fe1772e5c4 src/utils.h
--- a/src/utils.h Sun Nov 20 20:46:53 2011 +0100
+++ b/src/utils.h Mon Nov 21 15:00:50 2011 +0100
@@ -90,6 +90,16 @@
int read_number_colon_number( const char* file, unsigned char* first, unsigned char* second );
/**
+ * Writes given data to the specified, opening it as root
+ * (this is used to unbind driver, etc)
+ * @param path path/file to write to
+ * @param data data to write
+ * @return 0 on success, else -1
+ */
+int
+root_write_to_file( const char* path, const char* data );
+
+/**
* Parse s as nonnegative number. Exits the program immediately if s cannot be
* parsed as a number.
* @param s string to parse as a number