/* * Copyright (C) 2006 Marcos Diez marcos*AT*unitron.com.br * this program sends SIGUSR1 to all running instances of automount, who is should unmount all automounted directories. is perfect for desktop systems, where users stick USB flash drives, digital cameras and CDs. Unfortumatelly, the program must be suid root to be used by a normal used. at least, it is not interactive! to use: gcc -ansi -Wall -pedantic umounter.c -o /bin/umounter && chmod 4711 /bin/umounter remember that if suid bits do not work on nonsuid partitions * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public Licens * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- * */ #include #include #include #include #include #include #include #include bool verbose=false; int kill(pid_t pid, int sig); #define AUTOMOUNT_IDENT "\nautomount(pid" #define AUTOMOUNT_FSTYPE "autofs" #define NO_AUTOMOUNT_PID_FOUND -10 static long searchStringInFile( FILE *theFile , char *theString ){ /* returns the position of the string in the file colateral effect: changes the position of the file to right after the string was found */ char *toBeSearched = theString; int c; while( (c = fgetc( theFile) ) != EOF ){ if( c == *toBeSearched ){ if( *++toBeSearched == 0){ /* we found it ! */ return ftell( theFile ) - strlen( theString ); } }else{ /* false match... too bad. we have to start if over */ toBeSearched = theString; } } return -1; } static pid_t getNextAutoMountPid( FILE *mountsFile ){ /* return the next automount pid found at /proc/mounts or NO_AUTOMOUNT_PID_FOUND */ char buffer[21]; long fPos; int pid; while( ( fPos = searchStringInFile( mountsFile , AUTOMOUNT_IDENT ) ) != -1 ){ /* it MUST start with \n, or else it is not the beginning of the line, else, an evil user could mount something at /home/evilUser/automount(pidXXXX)/ where pidXXXX is the process a user wants to kill */ /* now we EXTRA verify if the the filesystem type is AUTOMOUNT_FSTYPE */ fseek( mountsFile , fPos +1 , SEEK_SET ); fscanf( mountsFile , "%*s %*s %20s" , buffer ); if( strcmp( buffer , AUTOMOUNT_FSTYPE ) ){ /* invalid filesystem type */ continue; } /* now we believe we have something like [automount(pid4129) /mnt/auto autofs rw 0 0] */ fseek( mountsFile , fPos + sizeof( AUTOMOUNT_IDENT ) -1 , SEEK_SET ); fgets( buffer , sizeof(buffer) , mountsFile ); pid = atoi( buffer ); if( pid <1 ) return NO_AUTOMOUNT_PID_FOUND; return pid; } return NO_AUTOMOUNT_PID_FOUND; } static int sendSignalToAllAutoMounts( int sig ){ /* send sig to all running instances of automount. returns the number of signals sent */ FILE *mountsFile; pid_t pid; int numSignalsSend=0; if( !(mountsFile = fopen( "/proc/mounts" , "r")) ){ fprintf( stderr , "ERROR: Umounter was not able to read /proc/mounts\n"); exit(3); } while( (pid = getNextAutoMountPid( mountsFile ) ) != NO_AUTOMOUNT_PID_FOUND ){ numSignalsSend++; if( kill( pid , SIGUSR1 ) == -1 ){ switch( errno ) { case EINVAL: fprintf( stderr , "ERROR: SIGUSR1 is not a valid signal at this system.\n"); break; /* should not happen, since I am root */ case EPERM: fprintf( stderr , "ERROR: Umounter does not not have permission to send the signal to PID %d\n" , pid); exit( EPERM ); break; case ESRCH: /* ok... lets ignore it */ continue; /* puts( "The pid or process group does not exist. Note that an existing process might be a zombie, a process which already\n" */ /* "committed termination, but has not yet been wait()ed for.\n"); */ break; default: printf("Unexpected error returned by kill: %d\n" , errno ); exit(2); } } if( verbose ){ printf("Sending SIGUSR1 to automount PID %d\n" , pid ); } } fclose( mountsFile ); return numSignalsSend; } static void version(){ printf("umounter 1.00 by marcos*AT*unitron.com.br\n"); } static void gnuSplash(){ printf("This is free software. You may redistribute copies of it under the terms of\n" "the GNU General Public License .\n" "There is NO WARRANTY, to the extent permitted by law."); } static void usage(){ version(); printf("Usage: umounter [OPTION]\n"); printf("Sends USRSIG1 signal to all instances of automount.\nAutomount is suposed to umount ALL automounted filesystems after receiving such a signal.\nUmounter must be suid root and be in a non nosuid partition to be used by non-root users.\n"); printf("Options:\n\t--version\tdisplay version\n\t--help\t\tthis screen\n\t--verbose\tverbose mode\n"); exit(0); } int main( int argc , char **argv ){ if( argc > 1 ){ char *parameter=argv[1]; if( !strcmp( parameter , "--verbose" )){ verbose=true; }else if( !strcmp( parameter , "--help" )) { usage(); }else if( !strcmp( parameter , "--version" )) { version(); gnuSplash(); exit(0); } } if( !sendSignalToAllAutoMounts( SIGUSR1 ) ){ fprintf( stderr , "Warning: no runnung instance of automount found\n"); } return 0; }