1 #include <grass/config.h>
2 #include <stdlib.h>
3 #include <signal.h>
4 #include <unistd.h>
5 #include <time.h>
6 #include <sys/types.h>
7 #include <dirent.h>
8 #include <sys/stat.h>
9 #include <grass/gis.h>
10 #include "local_proto.h"
11 
12 /**************************************************************
13  * clean_temp
14  *
15  *   looks for all files in mapset temp directory
16  *   of the form pid.n and removes those which have
17  *   been abandoned their processes (pid).
18  *
19  *   also removes any other file found which is "old"
20  *   with an modification time greater then 4 days
21  *
22  *   2006: Rewritten for GRASS 6 by Roberto Flor, ITC-irst
23  *
24  **************************************************************/
25 
26 #include <limits.h>
27 #include <string.h>
28 #include <errno.h>
29 #ifdef PATH_MAX
30 #define BUF_MAX PATH_MAX
31 #else
32 #define BUF_MAX 4096
33 #endif
34 
35 #define SLEEP 30		/* 30 seconds */
36 
37 /* Recursively scan the directory pathname, removing directory and files */
38 
clean_dir(const char * pathname,uid_t uid,pid_t pid,time_t now,int max_age)39 void clean_dir(const char *pathname, uid_t uid, pid_t pid, time_t now,
40 	       int max_age)
41 {
42     char buf[BUF_MAX];
43     DIR *curdir;
44     struct dirent *cur_entry;
45     struct stat info;
46     int n, pathlen;
47 
48     curdir = opendir(pathname);
49     if (curdir == NULL) {
50 	G_warning("Can't open directory %s: %s,skipping\n", pathname,
51 		  strerror(errno));
52 	return;
53     }
54     /* loop over current dir */
55     while ((cur_entry = readdir(curdir))) {
56 	if ((G_strcasecmp(cur_entry->d_name, ".") == 0) ||
57 	    (G_strcasecmp(cur_entry->d_name, "..") == 0))
58 	    continue;		/* Skip dir and parent dir entries */
59 
60 	if ((pathlen =
61 	     G_snprintf(buf, BUF_MAX, "%s/%s", pathname,
62 			cur_entry->d_name)) >= BUF_MAX)
63 	    G_fatal_error
64 		("clean_temp: exceeded maximum pathname length %d, got %d, shouldn't happen",
65 		 BUF_MAX, pathlen);
66 
67 	if (stat(buf, &info) != 0) {
68 	    G_warning("Can't stat file %s: %s,skipping\n", buf,
69 		      strerror(errno));
70 	    continue;
71 	}
72 	if (S_ISDIR(info.st_mode)) {	/* It's a dir, recurring */
73 	    clean_dir(buf, uid, pid, now, max_age);
74 	    /* Return here means we have completed the subdir recursion */
75 	    /* Trying to remove the now empty dir */
76 	    if (info.st_uid != uid)	/* Not owners of dir */
77 		continue;
78 #ifndef DEBUG_CLEAN
79 	    if (rmdir(buf) != 0) {
80 		if (errno != ENOTEMPTY) {
81 		    G_warning
82 			("Can't remove empty directory %s: %s,skipping\n",
83 			 buf, strerror(errno));
84 		}
85 	    }
86 #else
87 	    G_warning("Removing directory %s\n", buf);
88 #endif
89 	}
90 	else {			/* It's a file check it */
91 	    if (info.st_uid == uid) {	/* Remove only files owned by current user */
92 		if (sscanf(cur_entry->d_name, "%d.%d", &pid, &n) == 2) {
93 		    if (!find_process(pid))
94 #ifndef DEBUG_CLEAN
95 			if (unlink(buf) != 0)
96 			    G_warning("Can't remove file %s: %s,skipping\n",
97 				      buf, strerror(errno));
98 #else
99 			G_warning("Removing file %s\n", buf);
100 #endif
101 		}
102 		else {
103 		    if ((now - info.st_mtime) > max_age)	/* Not modified in 4 days: TODO configurable param */
104 #ifndef DEBUG_CLEAN
105 			if (unlink(buf) != 0)
106 			    G_warning("Can't remove file %s: %s,skipping\n",
107 				      buf, strerror(errno));
108 #else
109 			G_warning("Removing file %s\n", buf);
110 #endif
111 		}
112 	    }
113 	}
114     }
115     closedir(curdir);
116     return;
117 }
118 
main(int argc,char * argv[])119 int main(int argc, char *argv[])
120 {
121     const char *mapset;
122     char element[GNAME_MAX];
123     char tmppath[BUF_MAX];
124     pid_t ppid;
125     pid_t pid;
126     uid_t uid;
127     time_t now;
128     long max_age;
129 
130     G_gisinit(argv[0]);
131     pid = 0;
132     ppid = 0;
133     if (argc > 1)
134 	sscanf(argv[1], "%d", &ppid);
135 
136     /* Get the mapset temp directory */
137     G_temp_element(element);
138     G_file_name(tmppath, element, "", mapset = G_mapset());
139 
140     /* get user id and current time in seconds */
141 #ifdef __MINGW32__
142     /* TODO */
143     uid = -1;
144 #else
145     uid = getuid();
146 #endif
147 
148     now = time(NULL);
149 
150     /* set maximum age in seconds (4 days) */
151     max_age = 4 * 24 * 60 * 60;
152 
153     /*
154      * Scan the temp directory and subdirectory for
155      * files owned by the user and of the form pid.n
156      * to be removed if the process is not running
157      * all "old" files are removed as well
158      */
159 
160     while (1) {
161 	if (ppid > 0 && !find_process(ppid))
162 	    break;
163 	clean_dir(tmppath, uid, pid, now, max_age);
164 	if (ppid <= 0)
165 	    break;
166 	G_sleep(SLEEP);
167     }
168     exit(0);
169 }
170 
find_process(int pid)171 int find_process(int pid)
172 {
173 #ifdef __MINGW32__
174     /* TODO */
175     return -1;
176 #else
177     return (kill(pid, 0) == 0 || errno != ESRCH);
178 #endif
179 }
180