GRASS GIS 7 Programmer's Manual  7.9.dev(2021)-e5379bbd7
clean_temp.c
Go to the documentation of this file.
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 
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)
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 
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 
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 }
DIR * opendir()
char * G_file_name(char *, const char *, const char *, const char *)
Builds full path names to GIS data files.
Definition: file_name.c:38
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void clean_dir(const char *pathname, uid_t uid, pid_t pid, time_t now, int max_age)
Definition: clean_temp.c:39
void G_sleep(unsigned int)
Definition: sleep.c:11
#define NULL
Definition: ccmath.h:32
void G_temp_element(char *)
Populates element with a path string.
Definition: tempfile.c:102
Definition: lidar.h:86
dir_entry * readdir()
int find_process(int pid)
Definition: clean_temp.c:171
int int G_strcasecmp(const char *, const char *)
String compare ignoring case (upper or lower)
Definition: strings.c:47
int main(int argc, char *argv[])
Definition: clean_temp.c:119
#define G_gisinit(pgm)
Definition: gis.h:53
#define BUF_MAX
Definition: clean_temp.c:32
const char * G_mapset(void)
Get current mapset name.
Definition: gis/mapset.c:33
int G_snprintf(char *, size_t, const char *,...) __attribute__((format(printf
#define GNAME_MAX
Definition: gis.h:167
void G_warning(const char *,...) __attribute__((format(printf
#define SLEEP
Definition: clean_temp.c:35