GRASS Programmer's Manual  6.4.2(2012)
clean_temp.c
Go to the documentation of this file.
00001 #include <stdlib.h>
00002 #include <signal.h>
00003 #include <unistd.h>
00004 #include <time.h>
00005 #include <sys/types.h>
00006 #include <dirent.h>
00007 #include <sys/stat.h>
00008 #include <grass/gis.h>
00009 #include "local_proto.h"
00010 
00011 /**************************************************************
00012  * clean_temp
00013  *
00014  *   looks for all files in mapset temp directory
00015  *   of the form pid.n and removes those which have
00016  *   been abandoned their processes (pid).
00017  *
00018  *   also removes any other file found which is "old"
00019  *   with an modification time greater then 4 days
00020  *
00021  *   2006: Rewritten for GRASS 6 by Roberto Flor, ITC-irst
00022  *
00023  **************************************************************/
00024 
00025 #include <limits.h>
00026 #include <string.h>
00027 #include <errno.h>
00028 #ifdef PATH_MAX
00029 #define BUF_MAX PATH_MAX
00030 #else
00031 #define BUF_MAX 4096
00032 #endif
00033 
00034 extern int errno;
00035 
00036 #define SLEEP 30                /* 30 minutes */
00037 
00038 /* Recursively scan the directory pathname, removing directory and files */
00039 
00040 void clean_dir(const char *pathname, uid_t uid, pid_t pid, time_t now,
00041                int max_age)
00042 {
00043     char buf[BUF_MAX];
00044     DIR *curdir;
00045     struct dirent *cur_entry;
00046     struct stat info;
00047     int n, pathlen;
00048 
00049     curdir = opendir(pathname);
00050     if (curdir == NULL) {
00051         G_warning("Can't open directory %s: %s,skipping\n", pathname,
00052                   strerror(errno));
00053         return;
00054     }
00055     /* loop over current dir */
00056     while ((cur_entry = readdir(curdir))) {
00057         if ((G_strcasecmp(cur_entry->d_name, ".") == 0) ||
00058             (G_strcasecmp(cur_entry->d_name, "..") == 0))
00059             continue;           /* Skip dir and parent dir entries */
00060 
00061         if ((pathlen =
00062              G_snprintf(buf, BUF_MAX, "%s/%s", pathname,
00063                         cur_entry->d_name)) >= BUF_MAX)
00064             G_fatal_error
00065                 ("clean_temp: exceeded maximum pathname length %d, got %d, should'nt happen",
00066                  BUF_MAX, pathlen);
00067 
00068         if (stat(buf, &info) != 0) {
00069             G_warning("Can't stat file %s: %s,skipping\n", buf,
00070                       strerror(errno));
00071             continue;
00072         }
00073         if (S_ISDIR(info.st_mode)) {    /* It's a dir, recurring */
00074             clean_dir(buf, uid, pid, now, max_age);
00075             /* Return here means we have completed the subdir recursion */
00076             /* Trying to remove the now empty dir */
00077             if (info.st_uid != uid)     /* Not owners of dir */
00078                 continue;
00079 #ifndef DEBUG_CLEAN
00080             if (rmdir(buf) != 0) {
00081                 if (errno != ENOTEMPTY) {
00082                     G_warning
00083                         ("Can't remove empty directory %s: %s,skipping\n",
00084                          buf, strerror(errno));
00085                 }
00086             }
00087 #else
00088             G_warning("Removing directory %s\n", buf);
00089 #endif
00090         }
00091         else {                  /* It's a file check it */
00092             if (info.st_uid == uid) {   /* Remove only files owned by current user */
00093                 if (sscanf(cur_entry->d_name, "%d.%d", &pid, &n) == 2) {
00094                     if (!find_process(pid))
00095 #ifndef DEBUG_CLEAN
00096                         if (unlink(buf) != 0)
00097                             G_warning("Can't remove file %s: %s,skipping\n",
00098                                       buf, strerror(errno));
00099 #else
00100                         G_warning("Removing file %s\n", buf);
00101 #endif
00102                 }
00103                 else {
00104                     if ((now - info.st_mtime) > max_age)        /* Not modified in 4 days: TODO configurable param */
00105 #ifndef DEBUG_CLEAN
00106                         if (unlink(buf) != 0)
00107                             G_warning("Can't remove file %s: %s,skipping\n",
00108                                       buf, strerror(errno));
00109 #else
00110                         G_warning("Removing file %s\n", buf);
00111 #endif
00112                 }
00113             }
00114         }
00115     }
00116     closedir(curdir);
00117     return;
00118 }
00119 
00120 int main(int argc, char *argv[])
00121 {
00122     char *mapset;
00123     char element[GNAME_MAX];
00124     char tmppath[BUF_MAX];
00125     pid_t ppid;
00126     pid_t pid;
00127     uid_t uid;
00128     time_t now;
00129     long max_age;
00130 
00131     G_gisinit(argv[0]);
00132     pid = 0;
00133     ppid = 0;
00134     if (argc > 1)
00135         sscanf(argv[1], "%d", &ppid);
00136 
00137     /* Get the mapset temp directory */
00138     G__temp_element(element);
00139     G__file_name(tmppath, element, "", mapset = G_mapset());
00140 
00141     /* get user id and current time in seconds */
00142 #ifdef __MINGW32__
00143     /* TODO */
00144     uid = -1;
00145 #else
00146     uid = getuid();
00147 #endif
00148 
00149     now = time(NULL);
00150 
00151     /* set maximum age in seconds (4 days) */
00152     max_age = 4 * 24 * 60 * 60;
00153 
00154     /*
00155      * Scan the temp directory and subdirectory for 
00156      * files owned by the user and of the form pid.n
00157      * to be removed if the process is not running
00158      * all "old" files are removed as well
00159      */
00160 
00161     while (1) {
00162         if (ppid > 0 && !find_process(ppid))
00163             break;
00164         clean_dir(tmppath, uid, pid, now, max_age);
00165         if (ppid <= 0)
00166             break;
00167         G_sleep(SLEEP);
00168     }
00169     exit(0);
00170 }
00171 
00172 int find_process(int pid)
00173 {
00174 #ifdef __MINGW32__
00175     /* TODO */
00176     return -1;
00177 #else
00178     return (kill(pid, 0) == 0 || errno != ESRCH);
00179 #endif
00180 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines