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