1 diff -r 97fe1772e5c4 src/Makefile.am
2 --- a/src/Makefile.am Sun Nov 20 20:46:53 2011 +0100
3 +++ b/src/Makefile.am Mon Nov 21 15:00:50 2011 +0100
6 noinst_LIBRARIES = libpmount-util.a
7 libpmount_util_a_SOURCES = \
23 pumount_LDADD = libpmount-util.a
38 INSTALL_DIR = $(DESTDIR)/$(prefix)/bin
39 INSTALL_SRC = $(top_builddir)/src
40 diff -r 97fe1772e5c4 src/Makefile.in
41 --- a/src/Makefile.in Sun Nov 20 20:46:53 2011 +0100
42 +++ b/src/Makefile.in Mon Nov 21 15:00:50 2011 +0100
44 libpmount_util_a_AR = $(AR) $(ARFLAGS)
45 libpmount_util_a_LIBADD =
46 am_libpmount_util_a_OBJECTS = fs.$(OBJEXT) luks.$(OBJEXT) \
47 - policy.$(OBJEXT) utils.$(OBJEXT) realpath.$(OBJEXT)
48 + policy.$(OBJEXT) utils.$(OBJEXT) realpath.$(OBJEXT) \
50 libpmount_util_a_OBJECTS = $(am_libpmount_util_a_OBJECTS)
51 @PMOUNT_HAL_TRUE@am__EXEEXT_1 = pmount-hal$(EXEEXT)
52 am__installdirs = "$(DESTDIR)$(bindir)"
54 DATADIRNAME = @DATADIRNAME@
62 LTLIBOBJS = @LTLIBOBJS@
65 +MANIFEST_TOOL = @MANIFEST_TOOL@
67 MKINSTALLDIRS = @MKINSTALLDIRS@
70 abs_srcdir = @abs_srcdir@
71 abs_top_builddir = @abs_top_builddir@
72 abs_top_srcdir = @abs_top_srcdir@
73 +ac_ct_AR = @ac_ct_AR@
75 ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
76 am__include = @am__include@
78 libexecdir = @libexecdir@
79 localedir = @localedir@
80 localstatedir = @localstatedir@
84 oldincludedir = @oldincludedir@
86 INCLUDES = $(HAL_CFLAGS)
87 noinst_LIBRARIES = libpmount-util.a
88 libpmount_util_a_SOURCES = \
101 @PMOUNT_HAL_TRUE@EXTRABIN = pmount-hal
102 pmount_SOURCES = pmount.c
103 @@ -244,11 +248,12 @@
104 pumount_SOURCES = pumount.c
105 pumount_LDADD = libpmount-util.a
119 INSTALL_DIR = $(DESTDIR)/$(prefix)/bin
120 INSTALL_SRC = $(top_builddir)/src
125 +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf.Po@am__quote@
126 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs.Po@am__quote@
127 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/luks.Po@am__quote@
128 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pmount-hal.Po@am__quote@
129 diff -r 97fe1772e5c4 src/conf.c
130 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
131 +++ b/src/conf.c Mon Nov 21 15:00:50 2011 +0100
141 +#include "realpath.h"
146 +get_conf_for_device(const char *device, char **fs, char **charset,
147 + char **passphrase, char **mntpt, char **options)
150 + char buffer[BUFLEN], section[PATH_MAX];
151 + char *buf, *sec, *s;
152 + int skip_section = 0;
153 + int in_section = 0;
156 + if( NULL == ( f = fopen( CONF_FILE, "r" ) ) ) {
157 + debug( "unable to open conf file %s\n", CONF_FILE );
161 + while( !feof( f ) ) {
162 + if( fgets( buffer, BUFLEN, f ) ) {
163 + /* skip spaces & tabs */
164 + for ( buf = buffer; *buf == ' ' || *buf == '\t'; ++buf )
166 + /* ignore commented & empty lines */
167 + if( *buf == ';' || *buf == '#' || *buf == '\n' ) {
171 + if( *buf == '[' ) {
172 + /* if we were in section, we're done */
177 + if( NULL == ( s = strchr( buf, ']' ) ) ) {
179 + fprintf( stderr, "invalid syntax in %s: %s\n", CONF_FILE, buf );
182 + if( s - buf >= PATH_MAX ) {
184 + fprintf( stderr, "invalid section name in %s: %s\n", CONF_FILE, buf );
187 + strncpy( section, buf, s - buf );
188 + /* NULL-terminate the string */
189 + s = section + (s - buf);
191 + debug( "found section for %s\n", section );
192 + /* try to resolve, might be e.g. a /dev/disk/by-uuid/... */
193 + if( !realpath( section, section ) ) {
194 + if( !is_block( section ) ) {
195 + /* probably section for a device not plugged in */
196 + debug( "unable to resolve, not a block, skipping section\n" );
201 + debug( "resolved to %s\n", section );
203 + /* is this the device we're looking for? */
204 + if( strcmp( device, section ) ) {
205 + debug( "no match, skipping section\n" );
209 + debug( "match found!\n" );
214 + } else if( skip_section ) {
216 + } else if( NULL == sec ) {
218 + debug( "no matching section found\n" );
221 + /* we're in a section, must be a name=value */
222 + if ( NULL == ( s = strchr( buf, '=' ) ) ) {
223 + fprintf( stderr, "invalid syntax in %s: %s\n", CONF_FILE, buf );
226 + /* ignore spaces & tabs */
227 + for ( --s; *s == ' ' || *s == '\t'; --s )
231 + if( NULL != fs && !strncmp( buf, "fs", len ) ) {
232 + conf_set_value( buf, fs );
233 + debug( "file system set to %s\n", *fs );
234 + } else if( NULL != charset && !strncmp( buf, "charset", len )) {
235 + conf_set_value( buf, charset );
236 + debug( "charset set to %s\n", *charset );
237 + } else if( NULL != passphrase && !strncmp( buf, "passphrase", len )) {
238 + conf_set_value( buf, passphrase );
239 + debug( "passphrase set to %s\n", *passphrase );
240 + } else if( NULL != mntpt && !strncmp( buf, "mntpt", len )) {
241 + conf_set_value( buf, mntpt );
242 + debug( "mount point set to %s\n", *mntpt );
243 + } else if( NULL != options && !strncmp( buf, "options", len )) {
244 + conf_set_value( buf, options );
245 + debug( "options set to %s\n", *options );
247 + debug( "ignoring: %s", buf );
252 + return !in_section;
256 +conf_set_value( char *buf, char **dest )
259 + /* position to beginning of value */
260 + buf = strchr( buf, '=' );
261 + /* skip spaces & tabs */
262 + for( ++buf; *buf == ' ' || *buf == '\t'; ++buf)
264 + /* find end position */
265 + for( s = buf; *s != ' ' && *s != ';' && *s != '#' && *s != '\n' && *s != 0; ++s)
268 + *dest = strndup( buf, s - buf );
270 diff -r 97fe1772e5c4 src/conf.h
271 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
272 +++ b/src/conf.h Mon Nov 21 15:00:50 2011 +0100
278 +#define CONF_FILE "/etc/pmount.conf"
282 +get_conf_for_device(const char *device, char **fs, char **charset,
283 + char **passphrase, char **mntpt, char **options);
286 +conf_set_value( char *buf, char **dest );
291 diff -r 97fe1772e5c4 src/luks.c
292 --- a/src/luks.c Sun Nov 20 20:46:53 2011 +0100
293 +++ b/src/luks.c Mon Nov 21 15:00:50 2011 +0100
295 else if( status == 1 )
296 result = DECRYPT_FAILED;
298 - fprintf( stderr, "Internal error: cryptsetup luksOpen failed" );
299 + fprintf( stderr, "Internal error: cryptsetup luksOpen failed\n" );
303 diff -r 97fe1772e5c4 src/pmount.c
304 --- a/src/pmount.c Sun Nov 20 20:46:53 2011 +0100
305 +++ b/src/pmount.c Mon Nov 21 15:00:50 2011 +0100
313 /* Enable autodetection if possible */
315 " -s, --sync : mount <device> with the 'sync' option (default: 'async')\n"
317 " mount <device> with the 'noatime' option (default: 'atime')\n"
318 + " -D : mount all partitions of <device> (or its parent, if a partition)\n"
319 " -e, --exec : mount <device> with the 'exec' option (default: 'noexec')\n"
320 " -t <fs> : mount as file system type <fs> (default: autodetected)\n"
321 " -c <charset>: use given I/O character set (default: 'utf8' if called\n"
323 * @param fmask User specified fmask (NULL for umask)
324 * @param dmask User specified dmask (NULL for umask)
325 * @param suppress_errors: if true, stderr is redirected to /dev/null
326 + * @param fs_options Options to use instead of the default from FS (if not NULL)
327 * @return exit status of mount, or -1 on failure.
331 int noatime, int exec, int force_write, const char* iocharset,
333 const char* umask, const char *fmask, const char *dmask,
334 - int suppress_errors )
335 + int suppress_errors,
336 + const char *fs_options )
341 snprintf( iocharset_opt, sizeof( iocharset_opt ),
342 fs->iocharset_format, "iso8859-1");
345 + if( NULL == fs_options ) {
346 + fs_options = fs->options;
349 snprintf( options, sizeof( options ), "%s%s%s%s%s%s%s%s%s",
350 - fs->options, sync_opt, atime_opt, exec_opt, access_opt, ugid_opt,
351 + fs_options, sync_opt, atime_opt, exec_opt, access_opt, ugid_opt,
352 umask_opt, fdmask_opt, iocharset_opt );
355 @@ -397,13 +405,15 @@
356 * @param umask User specified umask (NULL for default)
357 * @param fmask User specified fmask (NULL for umask)
358 * @param dmask User specified dmask (NULL for umask)
359 + * @param fs_options Options to use instead of the default from FS (if not NULL)
360 * @return last return value of do_mount (i. e. 0 on success, != 0 on error)
363 do_mount_auto( const char* device, const char* mntpt, int async,
364 int noatime, int exec, int force_write, const char* iocharset,
366 - const char* umask, const char *fmask, const char *dmask )
367 + const char* umask, const char *fmask, const char *dmask,
368 + const char *fs_options )
374 result = do_mount( device, mntpt, tp, async, noatime, exec,
375 force_write, iocharset, utf8, umask, fmask,
377 + dmask, nostderr, fs_options );
380 debug("blkid-detected FS failed, trying manually \n");
381 @@ -445,14 +455,16 @@
382 if( (fs+1)->fsname == NULL )
384 result = do_mount( device, mntpt, fs->fsname, async, noatime, exec,
385 - force_write, iocharset, utf8, umask, fmask, dmask, nostderr );
386 + force_write, iocharset, utf8, umask, fmask, dmask, nostderr,
391 /* sometimes VFAT fails when using iocharset; try again without */
393 result = do_mount( device, mntpt, fs->fsname, async, noatime, exec,
394 - force_write, NULL, utf8, umask, fmask, dmask, nostderr );
395 + force_write, NULL, utf8, umask, fmask, dmask, nostderr,
400 @@ -602,33 +614,207 @@
405 +static char *devarg = NULL, *arg2 = NULL;
406 +static char mntpt[MEDIA_STRING_SIZE];
407 +static char device[PATH_MAX], mntptdev[PATH_MAX];
408 +static int async = 1;
409 +static int noatime = 0;
410 +static int exec = 0;
411 +static int force_write = -1; /* 0: ro, 1: rw, -1: default */
412 +static const char* use_fstype = NULL;
413 +static const char* iocharset = NULL;
414 +static const char* _umask = NULL;
415 +static const char* _fmask = NULL;
416 +static const char* _dmask = NULL;
417 +static const char* passphrase = NULL;
419 +static enum { MOUNT, LOCK, UNLOCK } mode = MOUNT;
422 +mount_device( void )
424 + char decrypted_device[PATH_MAX];
425 + int utf8 = -1; /* Whether we live in a UTF-8 world or not */
428 + static const char *l_use_fstype;
429 + static const char *l_iocharset;
430 + static const char *l_passphrase;
433 + char *o_charset = NULL;
434 + char *o_passphrase = NULL;
435 + char *o_mntpt = NULL;
436 + char *o_options = NULL;
438 + l_use_fstype = use_fstype;
439 + l_iocharset = iocharset;
440 + l_passphrase = passphrase;
444 + /* let's see if there are options in CONF_FILE */
445 + if( !get_conf_for_device( device, &o_fs, &o_charset, &o_passphrase,
446 + &o_mntpt, &o_options ) ) {
447 + if( NULL != o_fs ) {
448 + l_use_fstype = (const char *) o_fs;
450 + if( NULL != o_charset ) {
451 + l_iocharset = (const char *) o_charset;
453 + if( NULL != o_passphrase ) {
454 + l_passphrase = (const char *) o_passphrase;
456 + if( NULL != o_mntpt ) {
457 + snprintf( mntpt, sizeof (mntpt ), "%s", o_mntpt );
461 + /* determine mount point name; note that we use devarg instead of
462 + * device to preserve symlink names (like '/dev/usbflash' instead
463 + * of '/dev/sda1') */
464 + if( NULL == o_mntpt && make_mountpoint_name( devarg, arg2, mntpt,
465 + sizeof( mntpt ) ) )
468 + /* if no charset was set explicitly, autodetect UTF-8 */
469 + if( !l_iocharset ) {
470 + const char* codeset;
471 + codeset = nl_langinfo( CODESET );
473 + debug( "no iocharset given, current locale encoding is %s\n", codeset );
475 + if( codeset && !strcmp( codeset, "UTF-8" ) ) {
476 + debug( "locale encoding uses UTF-8, setting iocharset to 'utf8'\n" );
477 + l_iocharset = "utf8";
480 + /* If user did not choose explicitly for or against utf8 */
482 + const char* codeset;
483 + codeset = nl_langinfo( CODESET );
484 + if( codeset && !strcmp( codeset, "UTF-8" ) ) {
485 + debug( "locale encoding uses UTF-8: will mount FAT with utf8 option" );
492 + /* clean stale locks */
493 + clean_lock_dir( device );
495 + if( check_mount_policy( device, mntpt ) )
498 + /* check for encrypted device */
499 + enum decrypt_status decrypt = luks_decrypt( device,
500 + decrypted_device, sizeof( decrypted_device ), l_passphrase,
501 + force_write == 0 ? 1 : 0 );
504 + case DECRYPT_FAILED:
505 + fprintf( stderr, _("Error: could not decrypt device (wrong passphrase?)\n") );
507 + case DECRYPT_EXISTS:
508 + fprintf( stderr, _("Error: mapped device already exists\n") );
511 + /* We create a luks lockfile _on the decrypted device !_*/
512 + if(! luks_create_lockfile(decrypted_device))
513 + fprintf(stderr, _("Warning: could not create luks lockfile\n"));
514 + case DECRYPT_NOTENCRYPTED:
517 + fprintf( stderr, "Internal error: unhandled decrypt_status %i\n",
522 + /* lock the mount directory */
523 + debug( "locking mount point directory\n" );
524 + if( lock_dir( mntpt ) < 0) {
525 + fprintf( stderr, _("Error: could not lock the mount directory. Another pmount is probably running for this mount point.\n"));
528 + debug( "mount point directory locked\n" );
532 + result = do_mount( decrypted_device, mntpt, l_use_fstype, async, noatime,
533 + exec, force_write, l_iocharset, utf8, _umask, _fmask, _dmask, 0,
536 + result = do_mount_auto( decrypted_device, mntpt, async, noatime, exec,
537 + force_write, l_iocharset, utf8, _umask, _fmask, _dmask, o_options );
539 + /* unlock the mount point again */
540 + debug( "unlocking mount point directory\n" );
541 + unlock_dir( mntpt );
542 + debug( "mount point directory unlocked\n" );
544 + if( NULL != o_fs ) {
547 + if( NULL != o_charset ) {
550 + if( NULL != o_passphrase ) {
551 + free( o_passphrase );
553 + if( NULL != o_mntpt ) {
556 + if( NULL != o_options ) {
561 + if( decrypt == DECRYPT_OK )
562 + luks_release( decrypted_device, 0 );
564 + /* mount failed, delete the mount point again */
565 + if( remove_pmount_mntpt( mntpt ) ) {
566 + perror( _("Error: could not delete mount point") );
569 + return E_EXECMOUNT;
575 + if( device_valid( device ) )
576 + if( do_lock( device, parse_unsigned( arg2, E_PID ) ) )
581 + if( device_valid( device ) )
582 + if( do_unlock( device, parse_unsigned( arg2, E_PID ) ) )
587 + fprintf( stderr, _("Internal error: mode %i not handled.\n"), (int) mode );
597 main( int argc, char** argv )
599 - char *devarg = NULL, *arg2 = NULL;
600 - char mntpt[MEDIA_STRING_SIZE];
601 - char device[PATH_MAX], mntptdev[PATH_MAX];
602 - char decrypted_device[PATH_MAX];
603 const char* fstab_device;
604 int is_real_path = 0;
608 - int force_write = -1; /* 0: ro, 1: rw, -1: default */
609 - const char* use_fstype = NULL;
610 - const char* iocharset = NULL;
611 - const char* umask = NULL;
612 - const char* fmask = NULL;
613 - const char* dmask = NULL;
614 - const char* passphrase = NULL;
615 - int utf8 = -1; /* Whether we live in a UTF-8 world or not */
617 + int full_device = 0;
619 - enum { MOUNT, LOCK, UNLOCK } mode = MOUNT;
621 + int result, error_occurred = 0;
624 static struct option long_opts[] = {
625 { "help", 0, NULL, 'h'},
627 { "read-only", 0, NULL, 'r' },
628 { "read-write", 0, NULL, 'w' },
629 { "version", 0, NULL, 'V' },
630 + { "full-device", 0, NULL, 'D' },
636 /* parse command line options */
638 - switch( option = getopt_long( argc, argv, "+hdelLsArwp:t:c:u:V", long_opts, NULL ) ) {
639 + switch( option = getopt_long( argc, argv, "+hdelLsArwp:t:c:u:DV", long_opts, NULL ) ) {
640 case -1: break; /* end of arguments */
642 case '?': return E_ARGS; /* unknown argument */
643 @@ -701,17 +888,19 @@
645 case 'c': iocharset = optarg; break;
647 - case 'u': umask = optarg; break;
648 + case 'u': _umask = optarg; break;
650 - case OPT_FMASK: fmask = optarg; break;
651 + case OPT_FMASK: _fmask = optarg; break;
653 - case OPT_DMASK: dmask = optarg; break;
654 + case OPT_DMASK: _dmask = optarg; break;
656 case 'p': passphrase = optarg; break;
658 case 'r': force_write = 0; break;
660 case 'w': force_write = 1; break;
662 + case 'D': full_device = 1; break;
664 case 'V': puts(VERSION); return 0;
666 @@ -793,117 +982,76 @@
667 fprintf( stderr, _("Error: invalid device %s (must be in /dev/)\n"), device );
671 + /* we need to get the full device name (e.g. /dev/sde), get list of all its
672 + partitions, and try to mount them all... */
673 + if( full_device ) {
674 + char devdirname[MEDIA_STRING_SIZE];
675 + if( !find_sysfs_device( device, devdirname, MEDIA_STRING_SIZE) ) {
676 + fprintf( stderr, _("Warning: unable to find device path for %s,"
677 + " full-device mode disabled\n"), device );
680 + debug( "device path for %s is %s\n", device, devdirname );
683 + struct dirent *partdirent;
684 + char partdirname[MEDIA_STRING_SIZE];
685 + struct stat stat_info;
687 + partdir = opendir( devdirname );
689 + perror( _("Error: could not open <sysfs dir>/block/<device>/") );
692 + while( ( partdirent = readdir( partdir ) ) != NULL ) {
693 + if( partdirent->d_type != DT_DIR
694 + || !strcmp( partdirent->d_name, "." )
695 + || !strcmp( partdirent->d_name, ".." ) )
698 + /* construct /sys/block/<device>/<partition>/dev */
699 + snprintf( partdirname, sizeof( partdirname ), "%s/%s/%s",
700 + devdirname, partdirent->d_name, "dev" );
704 - /* determine mount point name; note that we use devarg instead of
705 - * device to preserve symlink names (like '/dev/usbflash' instead
706 - * of '/dev/sda1') */
707 - if( make_mountpoint_name( devarg, arg2, mntpt, sizeof( mntpt ) ) )
709 + /* make sure it is a device, i.e has a file dev */
710 + if( 0 != stat( partdirname, &stat_info ) ) {
711 + /* ENOENT (does not exist) is "okay" we just ignore this one */
712 + if( ENOENT != errno ) {
713 + perror( _("Error: could not stat <sysfs dir>/block/<device>/<part>/dev") );
718 + /* must be a file */
719 + if( !S_ISREG( stat_info.st_mode ) ) {
723 - /* if no charset was set explicitly, autodetect UTF-8 */
725 - const char* codeset;
726 - codeset = nl_langinfo( CODESET );
728 - debug( "no iocharset given, current locale encoding is %s\n", codeset );
730 - if( codeset && !strcmp( codeset, "UTF-8" ) ) {
731 - debug( "locale encoding uses UTF-8, setting iocharset to 'utf8'\n" );
732 - iocharset = "utf8";
733 + /* construct /dev/<partition> */
734 + snprintf( device, sizeof( device ), "%s%s", DEVDIR, partdirent->d_name );
735 + debug( "processing found partition: %s\n", device );
737 + /* We need to lookup again in fstab: */
738 + fstab_device = fstab_has_device( "/etc/fstab", device, NULL, NULL );
739 + if( mode == MOUNT && fstab_device ) {
740 + fprintf( stderr, _("Error: device %s handled by fstab\n"), fstab_device );
745 + result = mount_device();
746 + if( result != 0 ) {
747 + fprintf( stderr, _("Failed to mount device %s : error %d\n"), device, result );
748 + error_occurred = -1;
750 + printf( _("Device %s mounted\n"), device );
753 - /* If user did not choose explicitly for or against utf8 */
755 - const char* codeset;
756 - codeset = nl_langinfo( CODESET );
757 - if( codeset && !strcmp( codeset, "UTF-8" ) ) {
758 - debug( "locale encoding uses UTF-8: will mount FAT with utf8 option" );
765 - /* clean stale locks */
766 - clean_lock_dir( device );
768 - if( check_mount_policy( device, mntpt ) )
771 - /* check for encrypted device */
772 - enum decrypt_status decrypt = luks_decrypt( device,
773 - decrypted_device, sizeof( decrypted_device ), passphrase,
774 - force_write == 0 ? 1 : 0 );
777 - case DECRYPT_FAILED:
778 - fprintf( stderr, _("Error: could not decrypt device (wrong passphrase?)\n") );
780 - case DECRYPT_EXISTS:
781 - fprintf( stderr, _("Error: mapped device already exists\n") );
784 - /* We create a luks lockfile _on the decrypted device !_*/
785 - if(! luks_create_lockfile(decrypted_device))
786 - fprintf(stderr, _("Warning: could not create luks lockfile\n"));
787 - case DECRYPT_NOTENCRYPTED:
790 - fprintf( stderr, "Internal error: unhandled decrypt_status %i\n",
792 - exit( E_INTERNAL );
795 - /* lock the mount directory */
796 - debug( "locking mount point directory\n" );
797 - if( lock_dir( mntpt ) < 0) {
798 - fprintf( stderr, _("Error: could not lock the mount directory. Another pmount is probably running for this mount point.\n"));
801 - debug( "mount point directory locked\n" );
805 - result = do_mount( decrypted_device, mntpt, use_fstype, async, noatime,
806 - exec, force_write, iocharset, utf8, umask, fmask, dmask, 0 );
808 - result = do_mount_auto( decrypted_device, mntpt, async, noatime, exec,
809 - force_write, iocharset, utf8, umask, fmask, dmask );
811 - /* unlock the mount point again */
812 - debug( "unlocking mount point directory\n" );
813 - unlock_dir( mntpt );
814 - debug( "mount point directory unlocked\n" );
817 - if( decrypt == DECRYPT_OK )
818 - luks_release( decrypted_device, 0 );
820 - /* mount failed, delete the mount point again */
821 - if( remove_pmount_mntpt( mntpt ) ) {
822 - perror( _("Error: could not delete mount point") );
825 - return E_EXECMOUNT;
831 - if( device_valid( device ) )
832 - if( do_lock( device, parse_unsigned( arg2, E_PID ) ) )
837 - if( device_valid( device ) )
838 - if( do_unlock( device, parse_unsigned( arg2, E_PID ) ) )
841 + closedir( partdir );
842 + return error_occurred;
846 - fprintf( stderr, _("Internal error: mode %i not handled.\n"), (int) mode );
849 + return mount_device();
851 diff -r 97fe1772e5c4 src/policy.c
852 --- a/src/policy.c Sun Nov 20 20:46:53 2011 +0100
853 +++ b/src/policy.c Mon Nov 21 15:00:50 2011 +0100
857 while( ( partdirent = readdir( partdir ) ) != NULL ) {
858 - if( partdirent->d_type != DT_DIR )
859 + if( partdirent->d_type != DT_DIR
860 + || !strcmp( partdirent->d_name, "." )
861 + || !strcmp( partdirent->d_name, ".." ) )
864 /* construct /sys/block/<device>/<partition>/dev */
866 blockdevpath, whitelisted_bus);
869 - debug("Device %s does not belong to any whitelisted bus\n");
870 + debug("Device %s does not belong to any whitelisted bus\n", blockdevpath);
874 diff -r 97fe1772e5c4 src/pumount.c
875 --- a/src/pumount.c Sun Nov 20 20:46:53 2011 +0100
876 +++ b/src/pumount.c Mon Nov 21 15:00:50 2011 +0100
881 +#include <sys/stat.h>
893 " are met (see pumount(1) for details). The mount point directory is removed\n"
896 - " -l, --lazy : umount lazily, see umount(8)\n"
897 - " --luks-force : luksClose devices pmount didn't open\n"
898 - " -d, --debug : enable debug output (very verbose)\n"
899 - " -h, --help : print help message and exit successfuly\n"
900 - " --version : print version number and exit successfully\n"),
901 + " -l, --lazy : umount lazily, see umount(8)\n"
902 + " --luks-force : luksClose devices pmount didn't open\n"
903 + " -D : umount all partitions of the device, then stops it for safe removal\n"
904 + " -d, --debug : enable debug output (very verbose)\n"
905 + " -h, --help : print help message and exit successfuly\n"
906 + " -V, --version : print version number and exit successfully\n"),
912 /* mount point must be below MEDIADIR */
913 if( strncmp( mntpt, mediadir, strlen( mediadir ) ) ) {
914 - fprintf( stderr, _("Error: mount point %s is not below %s\n"), mntpt,
917 + /* check CONF_FILE, it might be okay */
918 + char *o_mntpt = NULL;
920 + if( !get_conf_for_device( device, NULL, NULL, NULL, &o_mntpt, NULL ) ) {
921 + if( NULL != o_mntpt ) {
922 + if( !strcmp( mntpt, o_mntpt ) ) {
923 + debug( "mount point allowed from config: %s\n", mntpt );
930 + fprintf( stderr, _("Error: mount point %s is not below %s\n"), mntpt,
936 debug( "policy check passed\n" );
941 - * Drop all privileges and exec 'umount device'. Does not return on success, if
942 - * it returns, UMOUNTPROG could not be executed.
943 + * Drop all privileges and exec 'umount device'.
944 * @param lazy 0 for normal umount, 1 for lazy umount
945 + * @return 0 on success, E_EXECUMOUNT if UMOUNTPROG could not be executed.
949 do_umount_fstab( const char* device, int lazy, const char * fstab_mntpt )
953 /* drop all privileges */
955 if( setuid( getuid() ) ) {
956 @@ -120,10 +141,16 @@
960 - execl( UMOUNTPROG, UMOUNTPROG, "-l", device, NULL );
961 + status = spawnl( 0, UMOUNTPROG, UMOUNTPROG, "-l", device, NULL );
963 - execl( UMOUNTPROG, UMOUNTPROG, device, NULL );
964 - perror( _("Error: could not execute umount") );
965 + status = spawnl( 0, UMOUNTPROG, UMOUNTPROG, device, NULL );
967 + if( status != 0 ) {
968 + perror( _("Error: could not execute umount") );
969 + return E_EXECUMOUNT;
981 +umount_device( const char* device, size_t devicesize, const char* mntpt,
982 + int do_lazy, int full_device )
984 + const char* fstab_device;
985 + char fstab_mntpt[MEDIA_STRING_SIZE];
987 + /* in full device mode, we need to check is the device is handled by fstab */
988 + if( full_device ) {
989 + fstab_device = fstab_has_device( "/etc/fstab", device, fstab_mntpt, NULL );
990 + if( fstab_device && device_mounted( device, 1, NULL ) ) {
991 + return do_umount_fstab( fstab_device, do_lazy, fstab_mntpt );
993 + /* in regular mode, we check if we have a dmcrypt device */
994 + } else if( luks_get_mapped_device( device, (char *) device, devicesize ) ) {
995 + debug( "Unmounting mapped device %s instead.\n", device );
998 + /* Now, we accept when devices have gone missing */
999 + if( check_umount_policy( device, 1 ) )
1003 + if( do_umount( device, do_lazy ) )
1004 + return E_EXECUMOUNT;
1006 + /* release LUKS device, if appropriate */
1007 + luks_release( device, 1 );
1009 + /* delete mount point */
1010 + remove_pmount_mntpt( mntpt );
1018 @@ -165,6 +227,10 @@
1019 int is_real_path = 0;
1022 + int full_device = 0;
1024 + int error_occurred = 0;
1028 static struct option long_opts[] = {
1030 { "lazy", 0, NULL, 'l'},
1031 { "yes-I-really-want-lazy-unmount", 0, NULL, 'R'},
1032 { "luks-force", 0, NULL, 'L'},
1033 + { "full-device", 0, NULL, 'D'},
1034 { "version", 0, NULL, 'V' },
1039 /* parse command line options */
1041 - switch( option = getopt_long( argc, argv, "+hdluV", long_opts, NULL ) ) {
1042 + switch( option = getopt_long( argc, argv, "+hdluDV", long_opts, NULL ) ) {
1043 case -1: break; /* end of arguments */
1044 case '?': return E_ARGS; /* unknown argument */
1049 case 'L': luks_force = 1; break;
1051 + case 'D': full_device = 1; break;
1053 case 'V': puts(VERSION); return 0;
1055 @@ -251,11 +320,17 @@
1056 snprintf( device, sizeof( device ), "%s", argv[optind] );
1059 - /* is the device already handled by fstab? */
1060 - fstab_device = fstab_has_device( "/etc/fstab", device, fstab_mntpt, NULL );
1061 - if( fstab_device ) {
1062 - do_umount_fstab( fstab_device, do_lazy, fstab_mntpt );
1063 - return E_EXECUMOUNT;
1064 + /* in full_device mode, we'll deal with all partitions anyways */
1065 + if( !full_device ) {
1066 + /* is the device already handled by fstab? */
1067 + fstab_device = fstab_has_device( "/etc/fstab", device, fstab_mntpt, NULL );
1068 + if( fstab_device ) {
1069 + if( device_mounted( device, 1, NULL ) ) {
1070 + return do_umount_fstab( fstab_device, do_lazy, fstab_mntpt );
1077 /* we cannot really check the real path when unmounting lazily since the
1078 @@ -271,13 +346,18 @@
1080 debug( "trying to prepend '" DEVDIR
1081 "' to device argument, now '%s'\n", device );
1082 - /* We need to lookup again in fstab: */
1083 - fstab_device = fstab_has_device( "/etc/fstab", device,
1084 - fstab_mntpt, NULL );
1085 - if( fstab_device ) {
1086 - do_umount_fstab( fstab_device, do_lazy, fstab_mntpt );
1087 - return E_EXECUMOUNT;
1089 + if( !full_device ) {
1090 + /* We need to lookup again in fstab: */
1091 + fstab_device = fstab_has_device( "/etc/fstab", device,
1092 + fstab_mntpt, NULL );
1093 + if( fstab_device ) {
1094 + if( device_mounted( device, 1, NULL ) ) {
1095 + return do_umount_fstab( fstab_device, do_lazy, fstab_mntpt );
1104 @@ -286,24 +366,151 @@
1105 fprintf( stderr, _("Error: invalid device %s (must be in /dev/)\n"), device );
1109 + /* we need to get the full device name (e.g. /dev/sde), get list of all its
1110 + partitions, and try to unmount them all... */
1111 + if( full_device ) {
1112 + char devdirname[MEDIA_STRING_SIZE];
1113 + if( !find_sysfs_device( device, devdirname, MEDIA_STRING_SIZE) ) {
1114 + fprintf( stderr, _("Warning: unable to find device path for %s, "
1115 + "full-device mode disabled\n"),
1119 + debug( "device path for %s is %s\n", device, devdirname );
1122 + struct dirent *partdirent;
1123 + char partdirname[MEDIA_STRING_SIZE];
1124 + struct stat stat_info;
1126 + partdir = opendir( devdirname );
1128 + perror( _("Error: could not open <sysfs dir>/block/<device>/") );
1131 + while( ( partdirent = readdir( partdir ) ) != NULL ) {
1132 + if( partdirent->d_type != DT_DIR
1133 + || !strcmp( partdirent->d_name, "." )
1134 + || !strcmp( partdirent->d_name, ".." ) )
1137 + /* construct /sys/block/<device>/<partition>/dev */
1138 + snprintf( partdirname, sizeof( partdirname ), "%s/%s/%s",
1139 + devdirname, partdirent->d_name, "dev" );
1141 - /* check if we have a dmcrypt device */
1142 - if( luks_get_mapped_device( device, device, sizeof( device ) ) )
1143 - debug( "Unmounting mapped device %s instead.\n", device );
1144 + /* make sure it is a device, i.e has a file dev */
1145 + if( 0 != stat( partdirname, &stat_info ) ) {
1146 + /* ENOENT (does not exist) is "okay" we just ignore this one */
1147 + if( ENOENT != errno ) {
1148 + perror( _("Error: could not stat <sysfs dir>/block/<device>/<part>/dev") );
1153 + /* must be a file */
1154 + if( !S_ISREG( stat_info.st_mode ) ) {
1158 - /* Now, we accept when devices have gone missing */
1159 - if( check_umount_policy( device, 1 ) )
1161 + /* construct /dev/<partition> */
1162 + snprintf( device, sizeof( device ), "%s%s", DEVDIR, partdirent->d_name );
1163 + debug( "processing found partition: %s\n", device );
1165 + /* check if we have a dmcrypt device */
1166 + if( luks_get_mapped_device( device, device, sizeof( device ) ) )
1167 + debug( "Using mapped device %s instead.\n", device );
1170 - if( do_umount( device, do_lazy ) )
1171 - return E_EXECUMOUNT;
1172 + if( device_mounted( device, 1, mntpt ) ) {
1173 + debug( "device %s mounted, unmounting\n", device );
1174 + result = umount_device( device, sizeof( device ), mntpt,
1175 + do_lazy, full_device );
1176 + if( result != 0 ) {
1177 + fprintf( stderr, _("Failed to umount device %s : error %d\n"),
1179 + error_occurred = -1;
1181 + printf( _("Device %s umounted\n"), device );
1185 + closedir( partdir );
1187 + /* no errors: let's stop the device completely, for safe removal */
1188 + if ( !error_occurred ) {
1192 - /* release LUKS device, if appropriate */
1193 - luks_release( device, 1 );
1194 + /* flush buffers */
1197 + /* resolve devdirname (<sysfs>/block/<device> to something like:
1198 + * /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 */
1199 + if( !realpath( devdirname, device ) ) {
1200 + debug( "unable to resolve %s\n", device );
1203 + debug( "device %s resolved to %s\n", devdirname, device );
1205 + /* now extract the part we want, up to the grand-parent of the host
1206 + e.g: /sys/devices/pci0000:00/0000:00:06.0/usb1/1-2 */
1207 + while( c = strrchr( device, '/' ) ) {
1208 + /* end the string there, to move back */
1210 + /* found the host part? */
1211 + if( !strncmp( c + 1, "host", 4 ) ) {
1216 + debug( "unable to find host for %s\n", device );
1219 + /* we need to move back one more time */
1220 + if( NULL == ( c = strrchr( device, '/' ) ) ) {
1221 + debug( "cannot move back one last time in %s\n", device );
1224 + /* end the string there */
1226 + debug( "full name is %s\n", device );
1227 + /* now we need the last component, aka the bus id */
1228 + if( NULL == ( c = strrchr( device, '/' ) ) ) {
1229 + debug( "cannot extract last component of %s\n", device );
1232 + /* move up, so this points to the name only, e.g. 1-2 */
1235 + /* unbind driver: write the bus id to <device>/driver/unbind */
1236 + snprintf( path, sizeof( path ), "%s/driver/unbind", device );
1237 + if ( root_write_to_file( path, c ) ) {
1241 + /* suspend device. step 1: write "0" to <device>/power/autosuspend */
1242 + snprintf( path, sizeof( path ), "%s/power/autosuspend", device );
1243 + if ( root_write_to_file( path, "0" ) ) {
1246 + /* step 2: write "auto" to <device>/power/control */
1247 + snprintf( path, sizeof( path ), "%s/power/control", device );
1248 + if ( root_write_to_file( path, "auto" ) ) {
1252 + c = strrchr( devdirname, '/' );
1253 + printf( _("Device %s%s stopped, you should now be able to safely unplug it\n"),
1257 + return error_occurred;
1259 - /* delete mount point */
1260 - remove_pmount_mntpt( mntpt );
1262 + fputs( _("Error: Unable to stop device\n"), stderr );
1268 + return umount_device( device, sizeof( device ), mntpt, do_lazy, full_device );
1270 diff -r 97fe1772e5c4 src/utils.c
1271 --- a/src/utils.c Sun Nov 20 20:46:53 2011 +0100
1272 +++ b/src/utils.c Mon Nov 21 15:00:50 2011 +0100
1273 @@ -439,3 +439,27 @@
1278 +root_write_to_file( const char* path, const char* data )
1281 + size_t expected, actual;
1284 + f = fopen( path, "w" );
1287 + debug( "could not open %s\n", path );
1290 + expected = sizeof( char ) * strlen( data );
1291 + actual = fwrite( data, sizeof( char ), strlen( data ), f );
1292 + if( actual != expected ) {
1294 + debug( "error when writing to %s; expected %d bytes, only %d written\n",
1295 + path, expected, actual );
1301 diff -r 97fe1772e5c4 src/utils.h
1302 --- a/src/utils.h Sun Nov 20 20:46:53 2011 +0100
1303 +++ b/src/utils.h Mon Nov 21 15:00:50 2011 +0100
1305 int read_number_colon_number( const char* file, unsigned char* first, unsigned char* second );
1308 + * Writes given data to the specified, opening it as root
1309 + * (this is used to unbind driver, etc)
1310 + * @param path path/file to write to
1311 + * @param data data to write
1312 + * @return 0 on success, else -1
1315 +root_write_to_file( const char* path, const char* data );
1318 * Parse s as nonnegative number. Exits the program immediately if s cannot be
1319 * parsed as a number.
1320 * @param s string to parse as a number