/* save.c */ /* code for saving our search as a shell script */ /* Copyright (C) 1999 Matthew Grossman This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include"save.h" /* externs */ extern void print_error(char *format, ...); extern char *get_search_directory(GtkWidget *directory); extern GtkWidget *directory; extern GtkWidget *pattern; extern GtkWidget *login_entry; extern GtkWidget *group_entry; extern GtkWidget *atime_month_spin, *atime_day_spin, *atime_hour_spin, *atime_minute_spin, *atime_year_spin, *atime_second_spin; extern GtkWidget *ctime_month_spin, *ctime_day_spin, *ctime_hour_spin, *ctime_minute_spin, *ctime_year_spin, *ctime_second_spin; extern GtkWidget *mtime_month_spin, *mtime_day_spin, *mtime_hour_spin, *mtime_minute_spin, *mtime_year_spin, *mtime_second_spin; extern time_t get_user_time(GtkWidget *month, GtkWidget *day, GtkWidget *year, GtkWidget *hour, GtkWidget *minute, GtkWidget *second); extern GtkWidget *content_pattern; static char * dec_sec(time_t t) /* decrement time by 1 second */ { char *rv = NULL; static char s[32]; struct tm tm; time_t dec = 0; memset(s, 0, 32); dec = t - 1; memcpy(&tm, localtime(&dec), sizeof(struct tm)); strftime(s, 32, "%m%d%H%M%Y.%S", &tm); rv = s; return(rv); } static char * inc_sec(time_t t) /* increment time by 1 second */ { static char s[32]; struct tm tm; time_t inc = 0; char *rv = NULL; memset(s, 0, 32); inc = t + 1; memcpy(&tm, localtime(&inc), sizeof(struct tm)); strftime(s, 32, "%m%d%H%M%Y.%S", &tm); rv = s; return(rv); } static int timing_match_p() { int rv = 0; if(get_flag(ATIME_ET_P) || get_flag(ATIME_LT_P) || get_flag(ATIME_EQ_P) || get_flag(MTIME_ET_P) || get_flag(MTIME_LT_P) || get_flag(MTIME_EQ_P) || get_flag(CTIME_ET_P) || get_flag(CTIME_LT_P) || get_flag(CTIME_EQ_P)) rv = 1; return(rv); } static char * rm_timing_files() /* make the string that deletes the timing files */ { char *s = NULL; char *rv = NULL; s = (char *)g_malloc0(sizeof(char) * 2048); if(!s) { print_error("rm_timing_files: g_malloc0 failed"); goto ERROR; } if(get_flag(ATIME_ET_P) || get_flag(ATIME_LT_P)) strcat(s, "/bin/rm -f $afile\n"); if(get_flag(ATIME_EQ_P)) strcat(s, "/bin/rm -f $aeqfile1 $aeqfile2\n"); if(get_flag(CTIME_ET_P) || get_flag(CTIME_LT_P)) strcat(s, "/bin/rm -f $cfile\n"); if(get_flag(CTIME_EQ_P)) strcat(s, "/bin/rm -f $ceqfile1 $ceqfile2\n"); if(get_flag(MTIME_ET_P) || get_flag(MTIME_LT_P)) strcat(s, "/bin/rm -f $mfile\n"); if(get_flag(MTIME_EQ_P)) strcat(s, "/bin/rm -f $meqfile1 $meqfile2\n"); rv = s; DONE: return(rv); ERROR: goto DONE; } static char * make_timing_string() { char *rv = NULL; char *s = NULL; /* big enough */ char tmp[128]; s = (char *)g_malloc0(sizeof(char) * 2048); if(!s) { print_error("make_timing_string: g_malloc0 failed"); goto ERROR; } strcat(s, "\\( "); if(get_flag(ATIME_ET_P)) { sprintf(tmp, "\\( ! -anewer $afile ! -path $afile \\) -o "); strcat(s, tmp); } if(get_flag(ATIME_LT_P)) { sprintf(tmp, "\\( -anewer $afile ! -path $afile \\) -o "); strcat(s, tmp); } if(get_flag(ATIME_EQ_P)) { sprintf(tmp, "\\( ! -anewer $aeqfile2 -anewer $aeqfile1 ! \\( -path $aeqfile1 -o -path $aeqfile2 \\) \\) -o "); strcat(s, tmp); } if(get_flag(CTIME_ET_P)) { sprintf(tmp, "\\( ! -cnewer $cfile ! -path $cfile \\) -o "); strcat(s, tmp); } if(get_flag(CTIME_LT_P)) { sprintf(tmp, "\\( -cnewer $cfile ! -path $cfile \\) -o "); strcat(s, tmp); } if(get_flag(CTIME_EQ_P)) { sprintf(tmp, "\\( ! -cnewer $ceqfile2 -cnewer $ceqfile1 ! \\( -path $ceqfile1 -o -path $ceqfile2 \\) \\) -o "); strcat(s, tmp); } if(get_flag(MTIME_ET_P)) { sprintf(tmp, "\\( ! -newer $mfile ! -path $mfile \\) -o "); strcat(s, tmp); } if(get_flag(MTIME_LT_P)) { sprintf(tmp, "\\( -newer $mfile ! -path $mfile \\) -o "); strcat(s, tmp); } if(get_flag(MTIME_EQ_P)) { sprintf(tmp, "\\( ! -newer $meqfile2 -newer $meqfile1 ! \\( -path $meqfile1 -o -path $meqfile2 \\) \\) -o "); strcat(s, tmp); } strcat(s, "-false \\) "); rv = s; DONE: return(rv); ERROR: goto DONE; } static char * make_timing_files() /* return the string to make the timing files or NULL */ { char *s = NULL; char time[32]; char tmp[128]; time_t t = 0; char *rv = NULL; s = (char *)g_malloc0(sizeof(char) * 2048); if(!s) { print_error("make_timing_files: g_malloc0 failed"); goto ERROR; } if(get_flag(ATIME_ET_P) || get_flag(ATIME_LT_P)) { sprintf(tmp, "afile=`mktmp`\n"); strcat(s, tmp); sprintf(time, "%02d%02d%02d%02d%04d.%02d", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (atime_month_spin)), gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (atime_day_spin)), gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (atime_hour_spin)), gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (atime_minute_spin)), gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (atime_year_spin)), gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (atime_second_spin))); sprintf(tmp, "touch -t %s $afile\n", time); strcat(s, tmp); } if(get_flag(ATIME_EQ_P)) { sprintf(tmp, "aeqfile1=`mktmp`\naeqfile2=`mktmp`\n"); strcat(s, tmp); t = get_user_time(atime_month_spin, atime_day_spin, atime_year_spin, atime_hour_spin, atime_minute_spin, atime_second_spin); sprintf(tmp, "touch -t %s $aeqfile1\n", dec_sec(t)); strcat(s, tmp); sprintf(tmp, "touch -t %s $aeqfile2\n", inc_sec(t)); strcat(s, tmp); } if(get_flag(CTIME_ET_P) || get_flag(CTIME_LT_P)) { sprintf(tmp, "cfile=`mktmp`\n"); strcat(s, tmp); sprintf(time, "%02d%02d%02d%02d%04d.%02d", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (ctime_month_spin)), gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (ctime_day_spin)), gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (ctime_hour_spin)), gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (ctime_minute_spin)), gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (ctime_year_spin)), gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (ctime_second_spin))); sprintf(tmp, "touch -t %s $cfile\n", time); strcat(s, tmp); } if(get_flag(CTIME_EQ_P)) { sprintf(tmp, "ceqfile1=`mktmp`\nceqfile2=`mktmp`\n"); strcat(s, tmp); t = get_user_time(ctime_month_spin, ctime_day_spin, ctime_year_spin, ctime_hour_spin, ctime_minute_spin, ctime_second_spin); sprintf(tmp, "touch -t %s $ceqfile1\n", dec_sec(t)); strcat(s, tmp); sprintf(tmp, "touch -t %s $ceqfile2\n", inc_sec(t)); strcat(s, tmp); } if(get_flag(MTIME_ET_P) || get_flag(MTIME_LT_P)) { sprintf(tmp, "mfile=`mktmp`\n"); strcat(s, tmp); sprintf(time, "%02d%02d%02d%02d%04d.%02d", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (mtime_month_spin)), gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(mtime_day_spin)), gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(mtime_hour_spin)), gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (mtime_minute_spin)), gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (mtime_year_spin)), gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (mtime_second_spin))); sprintf(tmp, "touch -t %s $mfile\n", time); strcat(s, tmp); } if(get_flag(MTIME_EQ_P)) { sprintf(tmp, "meqfile1=`mktmp`\nmeqfile2=`mktmp`\n"); strcat(s, tmp); t = get_user_time(mtime_month_spin, mtime_day_spin, mtime_year_spin, mtime_hour_spin, mtime_minute_spin, mtime_second_spin); sprintf(tmp, "touch -t %s $meqfile1\n", dec_sec(t)); strcat(s, tmp); sprintf(tmp, "touch -t %s $meqfile2\n", inc_sec(t)); strcat(s, tmp); } rv = s; DONE: return(rv); ERROR: goto DONE; } static char * make_group_string() /* make the string to match the group or gid */ { char *rv = NULL; static char group[128]; char *g = NULL; int gid = 0; struct group *grp = NULL; memset(group, 0, 128); g = gtk_entry_get_text(GTK_ENTRY(group_entry)); if(strlen(g) > 0) { if(get_flag(GID_NOT_GROUP_P)) { gid = atoi(g); } else { if((grp = getgrnam(g))) gid = grp->gr_gid; else { print_error("make_group_string: invalid group"); goto DONE; } } sprintf(group, " -gid %d", gid); } if(get_flag(NOGROUP_P)) { if(*group != 0x0) strncat(group, " -o ", 64); strncat(group, " -nogroup ", 64); } if(*group) { rv = group; } DONE: return(rv); } static char * make_user_string() /* make the string to match the user (or uid) */ { char *rv = NULL; static char user[128]; char *login = NULL; int uid = 0; struct passwd *passwd = NULL; memset(user, 0, 128); login = gtk_entry_get_text(GTK_ENTRY(login_entry)); if(strlen(login) > 0) { if(get_flag(UID_NOT_LOGIN_P)) uid = atoi(login); else { if((passwd = getpwnam(login))) uid = passwd->pw_uid; else { print_error("make_user_string: invalid login"); goto DONE; } } sprintf(user, " -uid %d", uid); } if(get_flag(NOUSER_P)) { if(*user != 0x0) strncat(user, " -o ", 64); strncat(user, " -nouser ", 64); } if(*user) { rv = user; } DONE: return(rv); } static char * make_type_string() /* return the -type string that we can use, or NULL if no types */ { char *rv = NULL; static char type[100]; /* enough space for all possible types plus parens */ memset(type, 0, 100); strcat(type, "\\( "); if(get_flag(DIRECTORY_P)) strcat(type, "-type d -o "); if(get_flag(REGULAR_P)) strcat(type, "-type f -o "); if(get_flag(RAW_DEVICE_P)) strcat(type, "-type c -o "); if(get_flag(BLOCK_DEVICE_P)) strcat(type, "-type b -o "); if(get_flag(SYMLINK_P)) strcat(type, "-type l -o "); if(get_flag(SOCKET_P)) strcat(type, "-type s -o "); if(get_flag(FIFO_P)) strcat(type, "-type f -o "); if(type[3]) { strcat(type, "-false \\) "); rv = type; } return rv; } static char * make_sticky_string() /* handle the sticky bit and such */ { char *rv = NULL; static char mode[6]; int sticky = 0; if(get_flag(SETUID_P)) sticky += 4; if(get_flag(SETGID_P)) sticky += 2; if(get_flag(STICKY_P)) sticky += 1; if(sticky) { sprintf(mode, "+%d000", sticky); rv = mode; } else rv = NULL; return(rv); } static char * make_mode_string() /* return a pointer to a string of the mode, or NULL if we're not filtering by mode */ { char *rv = NULL; static char mode[6]; int op = 0, gp = 0, wp = 0; memset(mode, 0, 6); if(get_flag(OWNER_READ_P)) op += 4; if(get_flag(OWNER_WRITE_P)) op += 2; if(get_flag(OWNER_EXEC_P)) op += 1; if(get_flag(GROUP_READ_P)) gp += 4; if(get_flag(GROUP_WRITE_P)) gp += 2; if(get_flag(GROUP_EXEC_P)) gp += 1; if(get_flag(WORLD_READ_P)) wp += 4; if(get_flag(WORLD_WRITE_P)) wp += 2; if(get_flag(WORLD_EXEC_P)) wp += 1; if(op || gp || wp) { sprintf(mode, "+%d%d%d", op, gp, wp); rv = mode; } else rv = NULL; return(rv); } int save_search_command(char *filename) /* open filename, print out the search command to it, close it */ { FILE *output = NULL; int rv = 0; int matching_times = 0; output = fopen(filename, "w"); if(!output) { print_error("save_search_command: Can't write %s", filename); goto ERROR; } fprintf(output, "#!/bin/sh\n"); fprintf(output, "# program generated by gtkfind\n"); fprintf(output, "# this script requires that the mktmp program be in your path\n"); fprintf(output, "# mktmp is distributed with gtkfind\n"); fprintf(output, "# get the latest gktfind at http://www.oz.net/~mattg/download.html\n"); fprintf(output, "# This script may not work with non-GNU find\n\n"); /* mktmp && touch the timing files */ { char *s = NULL; matching_times = timing_match_p(); if(matching_times) { s = make_timing_files(); if(s) fprintf(output, "%s\n", s); g_free(s); } } fprintf(output, "find "); { char *search_directory = NULL; search_directory = get_search_directory(directory); if(strlen(search_directory)) fprintf(output, "%s ", search_directory); else fprintf(output, "/ "); } /* do we want to only search this directory? */ if(!get_flag(SEARCH_SUBDIRS_P)) fprintf(output, "-prune "); /* match on filename */ { char *search_pattern = NULL; char *s = NULL; search_pattern = gtk_entry_get_text(GTK_ENTRY(pattern)); if(search_pattern && strlen(search_pattern)) { if(get_flag(WILDCARD_FILENAME_MATCH_P)) fprintf(output, "-name \'%s\' ", search_pattern); else { s = escape_wildcards(search_pattern); if(s) { fprintf(output, "-name \'*%s*\' ", escape_wildcards(search_pattern)); } } } /* if we don't have a search pattern, then don't match on it... */ } /* match on permissions */ { char *s = make_mode_string(); if(s) { fprintf(output, "-perm %s ", s); } } /* match on the sticky bit */ { char *s = make_sticky_string(); if(s) { fprintf(output, "-perm %s ", s); } } /* match on types */ { char *s = make_type_string(); if(s) { fprintf(output, "%s ", s); } } /* match on user */ { char *s = make_user_string(); if(s) { fprintf(output, "%s ", s); } } /* match on group */ { char *s = make_group_string(); if(s) { fprintf(output, "%s ", s); } } /* match on times */ { char *s = NULL; if(matching_times) { s = make_timing_string(); if(s) { fprintf(output, "%s ", s); g_free(s); } } } fprintf(output, "-print "); /* match on contents with | xargs grep */ { char *pattern = NULL; char *s = NULL; pattern = gtk_entry_get_text(GTK_ENTRY(content_pattern)); if(pattern && strlen(pattern)) { fprintf(output, "| xargs egrep "); /* gotta use egrep */ if(get_flag(WILDCARD_CONTENTS_SEARCH_P)) { s = glob2regex(pattern); if(s) { fprintf(output, "'%s' ", s); free(s); } } else fprintf(output, "'%s' ", pattern); } } fprintf(output, "\n"); /* delete the timing files */ { char *s = NULL; if(matching_times) { s = rm_timing_files(); if(s) { fprintf(output, "%s\n", s); g_free(s); } } } if(output) fclose(output); /* make filename executable (mode 0744) */ { if(chmod(filename, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IROTH) < 0) { print_error("save_search_command: chmod: %s", strerror(errno)); goto ERROR; } } rv = 1; DONE: return(rv); ERROR: rv = 0; goto DONE; } char * escape_wildcards(char *s) /* copy s to rv, escaping any wildcards or quotes with \ */ { static char *rv = NULL; char *wilds = "*?\"'`[]{}"; char *p = NULL, *q = NULL; if(!s || !strlen(s)) { print_error("escape_wildcards: NULL or empty string passed"); goto ERROR; } if(rv) free(rv); rv = (char *)malloc(sizeof(char) * strlen(s) * 2); if(!rv) { print_error("escape_wildcards: Can't malloc rv"); goto ERROR; } p = s; q = rv; while(*p) { if(strchr(wilds, *p)) { *q++ = '\\'; } *q++ = *p++; } *q = '\0'; DONE: return(rv); ERROR: if(rv) free(rv); rv = NULL; goto DONE; }