updated on Thu Jan 12 04:00:44 UTC 2012
[aur-mirror.git] / pmount-safe-removal / patch
blobe7a4a8f736a4855dd255e7cc005d08a7c6877f59
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
4 @@ -2,11 +2,12 @@
5  
6  noinst_LIBRARIES = libpmount-util.a
7  libpmount_util_a_SOURCES = \
8 -       fs.c     \
9 -       luks.c   \
10 -       policy.c \
11 -       utils.c  \
12 -       realpath.c
13 +       fs.c       \
14 +       luks.c     \
15 +       policy.c   \
16 +       utils.c    \
17 +       realpath.c \
18 +       conf.c
20  if PMOUNT_HAL
21  EXTRABIN=pmount-hal
22 @@ -25,11 +26,12 @@
23  pumount_LDADD = libpmount-util.a
25  EXTRA_DIST = \
26 -       fs.h     \
27 -       luks.h   \
28 -       policy.h \
29 -       utils.h  \
30 -       realpath.h
31 +       fs.h       \
32 +       luks.h     \
33 +       policy.h   \
34 +       utils.h    \
35 +       realpath.h \
36 +       conf.h
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
43 @@ -52,7 +52,8 @@
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) \
49 +       conf.$(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)"
53 @@ -106,6 +107,7 @@
54  DATADIRNAME = @DATADIRNAME@
55  DEFS = @DEFS@
56  DEPDIR = @DEPDIR@
57 +DLLTOOL = @DLLTOOL@
58  DSYMUTIL = @DSYMUTIL@
59  DUMPBIN = @DUMPBIN@
60  ECHO_C = @ECHO_C@
61 @@ -141,6 +143,7 @@
62  LTLIBOBJS = @LTLIBOBJS@
63  MAINT = @MAINT@
64  MAKEINFO = @MAKEINFO@
65 +MANIFEST_TOOL = @MANIFEST_TOOL@
66  MKDIR_P = @MKDIR_P@
67  MKINSTALLDIRS = @MKINSTALLDIRS@
68  MSGFMT = @MSGFMT@
69 @@ -179,6 +182,7 @@
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@
74  ac_ct_CC = @ac_ct_CC@
75  ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
76  am__include = @am__include@
77 @@ -211,7 +215,6 @@
78  libexecdir = @libexecdir@
79  localedir = @localedir@
80  localstatedir = @localstatedir@
81 -lt_ECHO = @lt_ECHO@
82  mandir = @mandir@
83  mkdir_p = @mkdir_p@
84  oldincludedir = @oldincludedir@
85 @@ -230,11 +233,12 @@
86  INCLUDES = $(HAL_CFLAGS)
87  noinst_LIBRARIES = libpmount-util.a
88  libpmount_util_a_SOURCES = \
89 -       fs.c     \
90 -       luks.c   \
91 -       policy.c \
92 -       utils.c  \
93 -       realpath.c
94 +       fs.c       \
95 +       luks.c     \
96 +       policy.c   \
97 +       utils.c    \
98 +       realpath.c \
99 +       conf.c
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
106  EXTRA_DIST = \
107 -       fs.h     \
108 -       luks.h   \
109 -       policy.h \
110 -       utils.h  \
111 -       realpath.h
112 +       fs.h       \
113 +       luks.h     \
114 +       policy.h   \
115 +       utils.h    \
116 +       realpath.h \
117 +       conf.h
119  INSTALL_DIR = $(DESTDIR)/$(prefix)/bin
120  INSTALL_SRC = $(top_builddir)/src
121 @@ -361,6 +366,7 @@
122  distclean-compile:
123         -rm -f *.tab.c
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
132 @@ -0,0 +1,137 @@
134 +#include <stdio.h>
135 +#include <stdlib.h>
136 +#include <limits.h>
137 +#include <string.h>
139 +#include "conf.h"
140 +#include "utils.h"
141 +#include "realpath.h"
143 +#define BUFLEN                  1024
145 +int
146 +get_conf_for_device(const char *device, char **fs, char **charset,
147 +        char **passphrase, char **mntpt, char **options)
149 +    FILE *f;
150 +    char buffer[BUFLEN], section[PATH_MAX];
151 +    char *buf, *sec, *s;
152 +    int skip_section = 0;
153 +    int in_section = 0;
154 +    int len;
156 +    if( NULL == ( f = fopen( CONF_FILE, "r" ) ) ) {
157 +        debug( "unable to open conf file %s\n", CONF_FILE );
158 +        return 1;
159 +    }
160 +    sec = NULL;
161 +    while( !feof( f ) ) {
162 +        if( fgets( buffer, BUFLEN, f ) ) {
163 +            /* skip spaces & tabs */
164 +            for ( buf = buffer; *buf == ' ' || *buf == '\t'; ++buf )
165 +                ;
166 +            /* ignore commented & empty lines */
167 +            if( *buf == ';' || *buf == '#' || *buf == '\n' ) {
168 +                continue;
169 +            }
170 +            /* new section? */
171 +            if( *buf == '[' ) {
172 +                /* if we were in section, we're done */
173 +                if( in_section ) {
174 +                    break;
175 +                }
176 +                ++buf;
177 +                if( NULL == ( s = strchr( buf, ']' ) ) ) {
178 +                    fclose( f );
179 +                    fprintf( stderr, "invalid syntax in %s: %s\n", CONF_FILE, buf );
180 +                    return 2;
181 +                }
182 +                if( s - buf >= PATH_MAX ) {
183 +                    fclose( f );
184 +                    fprintf( stderr, "invalid section name in %s: %s\n", CONF_FILE, buf );
185 +                    return 3;
186 +                }
187 +                strncpy( section, buf, s - buf );
188 +                /* NULL-terminate the string */
189 +                s = section + (s - buf);
190 +                *s = 0;
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" );
197 +                        skip_section = 1;
198 +                        continue;
199 +                    }
200 +                } else {
201 +                    debug( "resolved to %s\n", section );
202 +                }
203 +                /* is this the device we're looking for? */
204 +                if( strcmp( device, section ) ) {
205 +                    debug( "no match, skipping section\n" );
206 +                    skip_section = 1;
207 +                    continue;
208 +                }
209 +                debug( "match found!\n" );
210 +                sec = section;
211 +                skip_section = 0;
212 +                in_section = 1;
213 +                continue;
214 +            } else if( skip_section ) {
215 +                continue;
216 +            } else if( NULL == sec ) {
217 +                fclose( f );
218 +                debug( "no matching section found\n" );
219 +                return -1;
220 +            }
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 );
224 +                continue;
225 +            }
226 +            /* ignore spaces & tabs */
227 +            for ( --s; *s == ' ' || *s == '\t'; --s )
228 +                ;
229 +            ++s;
230 +            len = s - buf;
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 );
246 +            } else {
247 +                debug( "ignoring: %s", buf );
248 +            }
249 +        }
250 +    }
251 +    fclose( f );
252 +    return !in_section;
255 +void
256 +conf_set_value( char *buf, char **dest )
258 +    char *s;
259 +    /* position to beginning of value */
260 +    buf = strchr( buf, '=' );
261 +    /* skip spaces & tabs */
262 +    for( ++buf; *buf == ' ' || *buf == '\t'; ++buf)
263 +        ;
264 +    /* find end position */
265 +    for( s = buf; *s != ' ' && *s != ';' && *s != '#' && *s != '\n' && *s != 0; ++s)
266 +        ;
267 +    /* set value */
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
273 @@ -0,0 +1,17 @@
275 +#ifndef CONF_H
276 +#define        CONF_H
278 +#define CONF_FILE               "/etc/pmount.conf"
281 +int
282 +get_conf_for_device(const char *device, char **fs, char **charset,
283 +        char **passphrase, char **mntpt, char **options);
285 +void
286 +conf_set_value( char *buf, char **dest );
289 +#endif /* CONF_H */
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
294 @@ -82,7 +82,7 @@
295      else if( status == 1 )
296          result = DECRYPT_FAILED;
297      else {
298 -        fprintf( stderr, "Internal error: cryptsetup luksOpen failed" );
299 +        fprintf( stderr, "Internal error: cryptsetup luksOpen failed\n" );
300          exit( 100 );
301      }
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
306 @@ -28,6 +28,7 @@
307  #include "policy.h"
308  #include "utils.h"
309  #include "luks.h"
310 +#include "conf.h"
311  #include "config.h"
313  /* Enable autodetection if possible */
314 @@ -82,6 +83,7 @@
315      "  -s, --sync  : mount <device> with the 'sync' option (default: 'async')\n"
316      "  -A, --noatime\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"
322 @@ -223,6 +225,7 @@
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.
328   */
329  int
330 @@ -230,7 +233,8 @@
331           int noatime, int exec, int force_write, const char* iocharset, 
332           int utf8, 
333           const char* umask, const char *fmask, const char *dmask, 
334 -         int suppress_errors )
335 +         int suppress_errors,
336 +          const char *fs_options )
338      const struct FS* fs;
339      char ugid_opt[100];
340 @@ -370,9 +374,13 @@
341        snprintf( iocharset_opt, sizeof( iocharset_opt ), 
342                 fs->iocharset_format, "iso8859-1");
343      }
344 +    
345 +    if( NULL == fs_options ) {
346 +        fs_options = fs->options;
347 +    }
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 );
354      /* go for it */
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)
361   */
362  int
363  do_mount_auto( const char* device, const char* mntpt, int async, 
364                int noatime, int exec, int force_write, const char* iocharset, 
365                int utf8, 
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 )
370      const struct FS* fs;
371      int nostderr = 1;
372 @@ -424,7 +434,7 @@
373        }
374        result = do_mount( device, mntpt, tp, async, noatime, exec, 
375                          force_write, iocharset, utf8, umask, fmask, 
376 -                        dmask, nostderr );
377 +                        dmask, nostderr, fs_options );
378        if(result == 0)
379         return result;
380        debug("blkid-detected FS failed, trying manually \n");
381 @@ -445,14 +455,16 @@
382        if( (fs+1)->fsname == NULL )
383         nostderr = 0;
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,
387 +                          fs_options );
388        if( result == 0 )
389         break;
391        /* sometimes VFAT fails when using iocharset; try again without */
392        if( iocharset )
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,
396 +                           fs_options );
397        if( result <= 0 )
398         break;
399      }
400 @@ -602,33 +614,207 @@
401      drop_root();
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;
421 +int
422 +mount_device( void )
424 +    char decrypted_device[PATH_MAX];
425 +    int utf8 = -1;             /* Whether we live in a UTF-8 world or not */
426 +    int result;
427 +    
428 +    static const char *l_use_fstype;
429 +    static const char *l_iocharset;
430 +    static const char *l_passphrase;
431 +    
432 +    char *o_fs = NULL;
433 +    char *o_charset = NULL;
434 +    char *o_passphrase = NULL;
435 +    char *o_mntpt = NULL;
436 +    char *o_options = NULL;
437 +    
438 +    l_use_fstype = use_fstype;
439 +    l_iocharset = iocharset;
440 +    l_passphrase = passphrase;
442 +    switch( mode ) {
443 +        case MOUNT:
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;
449 +                }
450 +                if( NULL != o_charset ) {
451 +                    l_iocharset = (const char *) o_charset;
452 +                }
453 +                if( NULL != o_passphrase ) {
454 +                    l_passphrase = (const char *) o_passphrase;
455 +                }
456 +                if( NULL != o_mntpt ) {
457 +                    snprintf( mntpt, sizeof (mntpt ), "%s", o_mntpt );
458 +                }
459 +            }
460 +            
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 ) ) )
466 +                return E_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";
478 +                }
479 +            }
480 +           /* If user did not choose explicitly for or against utf8 */
481 +           if( utf8 == -1 ) {
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" );
486 +               utf8 = 1;
487 +             } else {
488 +               utf8 = 0;
489 +             }
490 +           }
492 +            /* clean stale locks */
493 +            clean_lock_dir( device );
495 +            if( check_mount_policy( device, mntpt )  )
496 +                return E_POLICY;
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 ); 
503 +            switch (decrypt) {
504 +                case DECRYPT_FAILED:
505 +                    fprintf( stderr, _("Error: could not decrypt device (wrong passphrase?)\n") );
506 +                    return E_POLICY;
507 +                case DECRYPT_EXISTS:
508 +                    fprintf( stderr, _("Error: mapped device already exists\n") );
509 +                    return E_POLICY;
510 +                case DECRYPT_OK:
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:
515 +                    break;
516 +                default:
517 +                    fprintf( stderr, "Internal error: unhandled decrypt_status %i\n", 
518 +                        (int) decrypt);
519 +                    return E_INTERNAL;
520 +            }
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"));
526 +                return E_LOCKED;
527 +            }
528 +            debug( "mount point directory locked\n" );
530 +            /* off we go */
531 +            if( l_use_fstype )
532 +                result = do_mount( decrypted_device, mntpt, l_use_fstype, async, noatime,
533 +                                  exec, force_write, l_iocharset, utf8, _umask, _fmask, _dmask, 0,
534 +                                   o_options);
535 +            else
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" );
543 +            
544 +            if( NULL != o_fs ) {
545 +               free( o_fs ); 
546 +            }
547 +            if( NULL != o_charset ) {
548 +               free( o_charset ); 
549 +            }
550 +            if( NULL != o_passphrase ) {
551 +               free( o_passphrase ); 
552 +            }
553 +            if( NULL != o_mntpt ) {
554 +               free( o_mntpt ); 
555 +            }
556 +            if( NULL != o_options ) {
557 +               free( o_options ); 
558 +            }
560 +            if( result ) {
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") );
567 +                    return -1;
568 +                }
569 +                return E_EXECMOUNT;
570 +            }
572 +            return 0;
574 +        case LOCK:
575 +            if( device_valid( device ) )
576 +                if( do_lock( device, parse_unsigned( arg2, E_PID ) ) )
577 +                    return E_INTERNAL;
578 +            return 0;
580 +        case UNLOCK:
581 +            if( device_valid( device ) )
582 +                if( do_unlock( device, parse_unsigned( arg2, E_PID ) ) )
583 +                    return E_UNLOCK;
584 +            return 0;
585 +    }
587 +    fprintf( stderr, _("Internal error: mode %i not handled.\n"), (int) mode );
588 +    return E_INTERNAL;
593  /**
594   * Entry point.
595   */
596  int
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;
605 -    int async = 1;
606 -    int noatime = 0;
607 -    int exec = 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 */
616 -    int result;
617 +    int full_device = 0;
619 -    enum { MOUNT, LOCK, UNLOCK } mode = MOUNT;
621 +    int result, error_occurred = 0;
622 +    
623      int  option;
624      static struct option long_opts[] = {
625          { "help", 0, NULL, 'h'},
626 @@ -647,6 +833,7 @@
627          { "read-only", 0, NULL, 'r' },
628          { "read-write", 0, NULL, 'w' },
629          { "version", 0, NULL, 'V' },
630 +        { "full-device", 0, NULL, 'D' },
631          { NULL, 0, NULL, 0}
632      };
634 @@ -678,7 +865,7 @@
636      /* parse command line options */
637      do {
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 */
641              case ':':
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;
649             
650 -           case OPT_FMASK: fmask = optarg; break;
651 +           case OPT_FMASK: _fmask = optarg; break;
652             
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;
661 +            
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 ); 
668          return E_DEVICE;
669      }
670 +    
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 );
678 +            full_device = 0;
679 +        } else {
680 +            debug( "device path for %s is %s\n", device, devdirname );
681 +            
682 +            DIR *partdir;
683 +            struct dirent *partdirent;
684 +            char partdirname[MEDIA_STRING_SIZE];
685 +            struct stat stat_info;
686 +            
687 +            partdir = opendir( devdirname );
688 +            if( !partdir ) {
689 +                perror( _("Error: could not open <sysfs dir>/block/<device>/") );
690 +                exit( -1 );
691 +            }
692 +            while( ( partdirent = readdir( partdir ) ) != NULL ) {
693 +                if( partdirent->d_type != DT_DIR
694 +                        || !strcmp( partdirent->d_name, "." )
695 +                        || !strcmp( partdirent->d_name, ".." ) )
696 +                    continue;
697 +                
698 +                /* construct /sys/block/<device>/<partition>/dev */
699 +                snprintf( partdirname, sizeof( partdirname ), "%s/%s/%s",
700 +                        devdirname, partdirent->d_name, "dev" );
702 -    switch( mode ) {
703 -        case MOUNT:
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 ) ) )
708 -                return E_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") );
714 +                        exit( -1 );
715 +                    }
716 +                    continue;
717 +                }
718 +                /* must be a file */
719 +                if( !S_ISREG( stat_info.st_mode ) ) {
720 +                    continue;
721 +                }
723 -            /* if no charset was set explicitly, autodetect UTF-8 */
724 -            if( !iocharset ) {
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 );
736 +                
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 );
741 +                  exit( -1 );
742 +                }
743 +                
744 +                devarg = 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;
749 +                } else {
750 +                    printf( _("Device %s mounted\n"), device );
751                  }
752              }
753 -           /* If user did not choose explicitly for or against utf8 */
754 -           if( utf8 == -1 ) {
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" );
759 -               utf8 = 1;
760 -             } else {
761 -               utf8 = 0;
762 -             }
763 -           }
765 -            /* clean stale locks */
766 -            clean_lock_dir( device );
768 -            if( check_mount_policy( device, mntpt )  )
769 -                return E_POLICY;
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 ); 
776 -            switch (decrypt) {
777 -                case DECRYPT_FAILED:
778 -                    fprintf( stderr, _("Error: could not decrypt device (wrong passphrase?)\n") );
779 -                    exit( E_POLICY );
780 -                case DECRYPT_EXISTS:
781 -                    fprintf( stderr, _("Error: mapped device already exists\n") );
782 -                    exit( E_POLICY );
783 -                case DECRYPT_OK:
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:
788 -                    break;
789 -                default:
790 -                    fprintf( stderr, "Internal error: unhandled decrypt_status %i\n", 
791 -                        (int) decrypt);
792 -                    exit( E_INTERNAL );
793 -            }
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"));
799 -                exit( E_LOCKED );
800 -            }
801 -            debug( "mount point directory locked\n" );
803 -            /* off we go */
804 -            if( use_fstype )
805 -                result = do_mount( decrypted_device, mntpt, use_fstype, async, noatime,
806 -                                  exec, force_write, iocharset, utf8, umask, fmask, dmask, 0 );
807 -            else
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" );
816 -            if( result ) {
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") );
823 -                    return -1;
824 -                }
825 -                return E_EXECMOUNT;
826 -            }
828 -            return 0;
830 -        case LOCK:
831 -            if( device_valid( device ) )
832 -                if( do_lock( device, parse_unsigned( arg2, E_PID ) ) )
833 -                    return E_INTERNAL;
834 -            return 0;
836 -        case UNLOCK:
837 -            if( device_valid( device ) )
838 -                if( do_unlock( device, parse_unsigned( arg2, E_PID ) ) )
839 -                    return E_UNLOCK;
840 -            return 0;
841 +            closedir( partdir );
842 +            return error_occurred;
843 +        }
844      }
846 -    fprintf( stderr, _("Internal error: mode %i not handled.\n"), (int) mode );
847 -    return E_INTERNAL;
848 +    
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
854 @@ -164,7 +164,9 @@
855                      exit( -1 );
856                  }
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, ".." ) )
862                          continue;
864                      /* construct /sys/block/<device>/<partition>/dev */
865 @@ -549,7 +551,7 @@
866             blockdevpath, whitelisted_bus);
867      }
868      else
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);
871    } 
872    return removable;
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
877 @@ -19,10 +19,14 @@
878  #include <getopt.h>
879  #include <libintl.h>
880  #include <locale.h>
881 +#include <sys/stat.h>
882 +#include <errno.h>
883 +#include <dirent.h>
885  #include "policy.h"
886  #include "utils.h"
887  #include "luks.h"
888 +#include "conf.h"
889  #include "config.h"
891  /* error codes */
892 @@ -46,11 +50,12 @@
893      "  are met (see pumount(1) for details). The mount point directory is removed\n"
894      "  afterwards.\n\n"
895      "Options:\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"),
907          exename, MEDIADIR );
910 @@ -88,9 +93,23 @@
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,
915 -                MEDIADIR );
916 -        return -1;
917 +        /* check CONF_FILE, it might be okay */
918 +        char *o_mntpt = NULL;
919 +        int passed = 0;
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 );
924 +                    passed = 1;
925 +                }
926 +                free( o_mntpt );
927 +            }
928 +        }
929 +        if( !passed ) {
930 +            fprintf( stderr, _("Error: mount point %s is not below %s\n"), mntpt,
931 +                    MEDIADIR );
932 +            return -1;
933 +        }
934      }
936      debug( "policy check passed\n" );
937 @@ -98,13 +117,15 @@
940  /**
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.
946   */
947 -void
948 +int
949  do_umount_fstab( const char* device, int lazy, const char * fstab_mntpt )
951 +    int status;
952 +    
953      /* drop all privileges */
954      get_root();
955      if( setuid( getuid() ) ) {
956 @@ -120,10 +141,16 @@
957      }
959      if( lazy )
960 -        execl( UMOUNTPROG, UMOUNTPROG, "-l", device, NULL );
961 +        status = spawnl( 0, UMOUNTPROG, UMOUNTPROG, "-l", device, NULL );
962      else
963 -        execl( UMOUNTPROG, UMOUNTPROG, device, NULL );
964 -    perror( _("Error: could not execute umount") );
965 +        status = spawnl( 0, UMOUNTPROG, UMOUNTPROG, device, NULL );
966 +    
967 +    if( status != 0 ) {
968 +        perror( _("Error: could not execute umount") );
969 +        return E_EXECUMOUNT;
970 +    }
971 +    
972 +    return 0;
975  /**
976 @@ -152,6 +179,41 @@
977      return 0;
980 +int
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 );
992 +        }
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 );
996 +    }
998 +    /* Now, we accept when devices have gone missing */
999 +    if( check_umount_policy( device, 1 ) )
1000 +        return E_POLICY;
1002 +    /* go for it */
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 );
1011 +    
1012 +    return 0;
1015  /**
1016   * Entry point.
1017   *
1018 @@ -165,6 +227,10 @@
1019      int is_real_path = 0;
1020      int do_lazy = 0;
1021      int luks_force = 0;
1022 +    int full_device = 0;
1023 +    
1024 +    int error_occurred = 0;
1025 +    int result;
1027      int  option;
1028      static struct option long_opts[] = {
1029 @@ -173,6 +239,7 @@
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' },
1035          { NULL, 0, NULL, 0}
1036      };
1037 @@ -193,7 +260,7 @@
1039      /* parse command line options */
1040      do {
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 */
1046 @@ -212,6 +279,8 @@
1047               do_lazy = 1; break;
1049              case 'L':        luks_force = 1; break;
1050 +            
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] );
1057      }
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 );
1071 +            } else {
1072 +                return 0;
1073 +            }
1074 +        }
1075      }
1077      /* we cannot really check the real path when unmounting lazily since the
1078 @@ -271,13 +346,18 @@
1079              }
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;
1088 -           }
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 );
1096 +                  } else {
1097 +                      return 0;
1098 +                  }
1099 +                }
1100 +            }
1101         }
1102      }
1104 @@ -286,24 +366,151 @@
1105          fprintf( stderr, _("Error: invalid device %s (must be in /dev/)\n"), device );
1106          return E_DEVICE;
1107      }
1108 +    
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"),
1116 +                    device );
1117 +            full_device = 0;
1118 +        } else {
1119 +            debug( "device path for %s is %s\n", device, devdirname );
1120 +            
1121 +            DIR *partdir;
1122 +            struct dirent *partdirent;
1123 +            char partdirname[MEDIA_STRING_SIZE];
1124 +            struct stat stat_info;
1125 +            
1126 +            partdir = opendir( devdirname );
1127 +            if( !partdir ) {
1128 +                perror( _("Error: could not open <sysfs dir>/block/<device>/") );
1129 +                exit( -1 );
1130 +            }
1131 +            while( ( partdirent = readdir( partdir ) ) != NULL ) {
1132 +                if( partdirent->d_type != DT_DIR
1133 +                        || !strcmp( partdirent->d_name, "." )
1134 +                        || !strcmp( partdirent->d_name, ".." ) )
1135 +                    continue;
1136 +                
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") );
1149 +                        exit( -1 );
1150 +                    }
1151 +                    continue;
1152 +                }
1153 +                /* must be a file */
1154 +                if( !S_ISREG( stat_info.st_mode ) ) {
1155 +                    continue;
1156 +                }
1158 -    /* Now, we accept when devices have gone missing */
1159 -    if( check_umount_policy( device, 1 ) )
1160 -        return E_POLICY;
1161 +                /* construct /dev/<partition> */
1162 +                snprintf( device, sizeof( device ), "%s%s", DEVDIR, partdirent->d_name );
1163 +                debug( "processing found partition: %s\n", device );
1164 +                
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 );
1169 -    /* go for it */
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"),
1178 +                                device, result );
1179 +                        error_occurred = -1;
1180 +                    } else {
1181 +                        printf( _("Device %s umounted\n"), device );
1182 +                    }
1183 +                }
1184 +            }
1185 +            closedir( partdir );
1186 +            
1187 +            /* no errors: let's stop the device completely, for safe removal */
1188 +            if ( !error_occurred ) {
1189 +                char *c;
1190 +                FILE *f;
1192 -    /* release LUKS device, if appropriate */
1193 -    luks_release( device, 1 );
1194 +                /* flush buffers */
1195 +                sync();
1196 +                
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 );
1201 +                    goto err_stop;
1202 +                }
1203 +                debug( "device %s resolved to %s\n", devdirname, device );
1204 +                
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 */
1209 +                    *c = 0;
1210 +                    /* found the host part? */
1211 +                    if( !strncmp( c + 1, "host", 4 ) ) {
1212 +                        break;
1213 +                    }
1214 +                }
1215 +                if( c == NULL ) {
1216 +                    debug( "unable to find host for %s\n", device );
1217 +                    goto err_stop;
1218 +                }
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 );
1222 +                    goto err_stop;
1223 +                }
1224 +                /* end the string there */
1225 +                *c = 0;
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 );
1230 +                    goto err_stop;
1231 +                }
1232 +                /* move up, so this points to the name only, e.g. 1-2 */
1233 +                ++c;
1234 +                
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 ) ) {
1238 +                    goto err_stop;
1239 +                }
1240 +                
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" ) ) {
1244 +                    goto err_stop;
1245 +                }
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" ) ) {
1249 +                    goto err_stop;
1250 +                }
1251 +                
1252 +                c = strrchr( devdirname, '/' );
1253 +                printf( _("Device %s%s stopped, you should now be able to safely unplug it\n"),
1254 +                        DEVDIR, c + 1);
1255 +            }
1256 +            
1257 +            return error_occurred;
1259 -    /* delete mount point */
1260 -    remove_pmount_mntpt( mntpt );
1261 +err_stop:
1262 +            fputs( _("Error: Unable to stop device\n"), stderr );
1263 +            return -1;
1264 +        }
1265 +    }
1267 -    return 0; 
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 @@
1274      drop_root();
1277 +int
1278 +root_write_to_file( const char* path, const char* data )
1280 +    FILE *f;
1281 +    size_t expected, actual;
1282 +    
1283 +    get_root();
1284 +    f = fopen( path, "w" );
1285 +    drop_root();
1286 +    if( !f ) {
1287 +        debug( "could not open %s\n", path );
1288 +        return -1;
1289 +    }
1290 +    expected = sizeof( char ) * strlen( data );
1291 +    actual = fwrite( data, sizeof( char ), strlen( data ), f );
1292 +    if( actual != expected ) {
1293 +        fclose( f );
1294 +        debug( "error when writing to %s; expected %d bytes, only %d written\n",
1295 +                path, expected, actual );
1296 +        return -1;
1297 +    }
1298 +    fclose( f );
1299 +    return 0;
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
1304 @@ -90,6 +90,16 @@
1305  int read_number_colon_number( const char* file, unsigned char* first, unsigned char* second );
1307  /**
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
1313 + */
1314 +int
1315 +root_write_to_file( const char* path, const char* data );
1317 +/**
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