/*******************************************************************************\ * strrm.c * * * * Streaming remove command: Remove all files and empty directories * * sent in on the stdin. * * * \*******************************************************************************/ #include #include #include #include #include #include #include #include void strrmUsage(char *CommandName) { fprintf(stderr,"Usage: %s [--dryrun|-n] [--verbose|-v] [--help|-h]\n",CommandName) ; fprintf(stderr,"Remove any files or empty directories listed on the standard input\n\ --dryrun|-n Echo the files/directories that would be deleted, but don't do the deletions.\n\ --verbose|-v Normally strrm silently deletes, outputting only errors: this option echoes the names of files and directories being deleted.\n\ --help|-h This help message.\n") ; } /* * strrm_error() * * Print out useful error messages. For some reason perror()'s error * messages aren't always helpful. */ static void strrm_error(char *String) { extern int errno ; switch(errno) { case EEXIST: fprintf(stderr,"%s: Directory not empty.\n",String) ; break ; default: perror(String) ; } } /**** * sanitise() * * Change a string so any non-printable characters are translated to their * octal value preceded by \. When calling this function you should be on * the safe side and set the destination buffer to four times the source. ****/ static char *sanitise(char *SrcStr,char *DstStr) { char *StartDstStr = DstStr ; // Keep the pointer to the start of the destination string. while(*SrcStr!=0) { if(*SrcStr<0x20 || *SrcStr>0x7E) { sprintf(DstStr,"\\%03o",*SrcStr++) ; DstStr += 4 ; } else *DstStr++ = *SrcStr++ ; } *DstStr = 0 ; // Terminate the desintation string. return(StartDstStr) ; } int main(int argc,char *argv[]) { int RetVal=0,DryRun=0,Verbosity=0,ArgErr=0,Help=0 ; char PathName[PATH_MAX+1],sanPathName[4*PATH_MAX+1],*fgRetVal ; int optchar,shift_argc ; char **shift_argv ; // Options descriptor static struct option longopts[] = { {"dryrun", no_argument, NULL, 'n' }, {"verbose", no_argument, NULL, 'v' }, {"help", no_argument, NULL, 'h' }, {NULL, 0, NULL, 0 } }; while((optchar = getopt_long(argc,argv,"nvh",longopts,NULL))!=-1) { switch(optchar) { case 'n': DryRun = 1 ; break ; case 'v': Verbosity = 1 ; break ; case 'h': Help = 1 ; break ; case '?': ArgErr = 1 ; } } shift_argc = argc-optind ; shift_argv = &argv[optind] ; // Now the first non-opt argument will be at 0 if(Help==1 || ArgErr==1) strrmUsage(argv[0]) ; else while((fgRetVal=fgets(PathName,PATH_MAX,stdin))!=0) { *strchr(PathName,'\n')=0 ; // Get rid of the terminating `\n' that fgets() adds if(strlen(PathName)!=0) { // Silently skip empty lines, doesn't preclude file names consisting entirely of spaces if(DryRun==0) { // If it's not a dry-run then let remove() figure out the permissions if(remove(PathName)==-1) { // Given the right permissions remove() will remove files and empty directories. strrm_error(PathName) ; RetVal++ ; // Count the number of failures. } else { if(Verbosity==1) printf("%s\n",sanitise(PathName,sanPathName)) ; } } else { // It's a dry run so let's do some checks before echoing the result struct stat StatBuf ; if(stat(PathName,&StatBuf)==-1) perror(PathName) ; else if(access(dirname(PathName),W_OK)!=0) fprintf(stderr,"The parent directory for %s is not writable\n",sanitise(PathName,sanPathName)) ; else printf("%s\n",sanitise(PathName,sanPathName)) ; } } } return(RetVal) ; // Return count of files which could not be removed. } //****************************************************************************** // Change log // // $Log: strrm.c,v $ // Revision 2.3 2013/01/22 11:57:25 pkearns // Improve comments and error/help messages. // // Revision 2.2 2013/01/21 17:12:37 pkearns // Add new function, sanitise(), to handle the outputting of awkward // filenames. // Declare a new variable to hold sanitise()d strings. // Change include file strings.h to string.h so it will compile on Linux. // Move Usage() to the top, and rename to strrmUsage(). // // Revision 2.1 2012/11/29 13:07:13 pkearns // Substantial revision to introduce command line options and skip empty lines. // // Revision 1.1 2006/04/04 11:13:59 pkearns // Initial revision //