GRASS GIS 8 Programmer's Manual  8.5.0dev(2024)-d6dec75dd4
clean_temp.c
Go to the documentation of this file.
1 #include <grass/config.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <signal.h>
5 #include <unistd.h>
6 #include <time.h>
7 #include <sys/types.h>
8 #include <dirent.h>
9 #include <sys/stat.h>
10 #include <grass/gis.h>
11 #include "local_proto.h"
12 
13 /**************************************************************
14  * clean_temp
15  *
16  * looks for all files in mapset temp directory
17  * of the form pid.n and removes those which have
18  * been abandoned their processes (pid).
19  *
20  * also removes any other file found which is "old"
21  * with an modification time greater then 4 days
22  *
23  * 2006: Rewritten for GRASS 6 by Roberto Flor, ITC-irst
24  *
25  **************************************************************/
26 
27 #include <limits.h>
28 #include <string.h>
29 #include <errno.h>
30 #ifdef PATH_MAX
31 #define BUF_MAX PATH_MAX
32 #else
33 #define BUF_MAX 4096
34 #endif
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 = snprintf(buf, BUF_MAX, "%s/%s", pathname,
62  cur_entry->d_name)) >= BUF_MAX)
63  G_fatal_error("clean_temp: exceeded maximum pathname length %d, "
64  "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("Can't remove empty directory %s: %s,skipping\n",
82  buf, strerror(errno));
83  }
84  }
85 #else
86  G_warning("Removing directory %s\n", buf);
87 #endif
88  }
89  else { /* It's a file check it */
90  if (info.st_uid ==
91  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) >
104  max_age) /* Not modified in 4 days: TODO configurable
105  param */
106 #ifndef DEBUG_CLEAN
107  if (unlink(buf) != 0)
108  G_warning("Can't remove file %s: %s,skipping\n",
109  buf, strerror(errno));
110 #else
111  G_warning("Removing file %s\n", buf);
112 #endif
113  }
114  }
115  }
116  }
117  closedir(curdir);
118  return;
119 }
120 
121 int main(int argc, char *argv[])
122 {
123  const char *mapset;
124  char element[GNAME_MAX];
125  char tmppath[BUF_MAX];
126  pid_t ppid;
127  pid_t pid;
128  uid_t uid;
129  time_t now;
130  long max_age;
131 
132  G_gisinit(argv[0]);
133  pid = 0;
134  ppid = 0;
135  if (argc > 1)
136  sscanf(argv[1], "%d", &ppid);
137 
138  /* Get the mapset temp directory */
140  G_file_name(tmppath, element, "", mapset = G_mapset());
141 
142  /* get user id and current time in seconds */
143 #ifdef __MINGW32__
144  /* TODO */
145  uid = -1;
146 #else
147  uid = getuid();
148 #endif
149 
150  now = time(NULL);
151 
152  /* set maximum age in seconds (4 days) */
153  max_age = 4 * 24 * 60 * 60;
154 
155  /*
156  * Scan the temp directory and subdirectory for
157  * files owned by the user and of the form pid.n
158  * to be removed if the process is not running
159  * all "old" files are removed as well
160  */
161 
162  while (1) {
163  if (ppid > 0 && !find_process(ppid))
164  break;
165  clean_dir(tmppath, uid, pid, now, max_age);
166  if (ppid <= 0)
167  break;
168  G_sleep(SLEEP);
169  }
170  exit(0);
171 }
172 
173 int find_process(int pid)
174 {
175 #ifdef __MINGW32__
176  /* TODO */
177  return -1;
178 #else
179  return (kill(pid, 0) == 0 || errno != ESRCH);
180 #endif
181 }
#define NULL
Definition: ccmath.h:32
int main(int argc, char *argv[])
Definition: clean_temp.c:121
#define SLEEP
Definition: clean_temp.c:36
int find_process(int pid)
Definition: clean_temp.c:173
#define BUF_MAX
Definition: clean_temp.c:33
void clean_dir(const char *pathname, uid_t uid, pid_t pid, time_t now, int max_age)
Definition: clean_temp.c:40
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
void G_temp_element(char *)
Populates element with a path string.
Definition: tempfile.c:147
char * G_file_name(char *, const char *, const char *, const char *)
Builds full path names to GIS data files.
Definition: file_name.c:61
const char * G_mapset(void)
Get current mapset name.
Definition: gis/mapset.c:33
void G_sleep(unsigned int)
Definition: sleep.c:11
int int G_strcasecmp(const char *, const char *)
String compare ignoring case (upper or lower)
Definition: strings.c:47
#define G_gisinit(pgm)
Definition: gis.h:72
#define GNAME_MAX
Definition: gis.h:191
Definition: lidar.h:85