GRASS GIS 8 Programmer's Manual 8.2.0(2022)-exported
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
39void 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) {
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
119int 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 */
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
171int 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}
#define NULL
Definition: ccmath.h:32
int main(int argc, char *argv[])
Definition: clean_temp.c:119
#define SLEEP
Definition: clean_temp.c:35
int find_process(int pid)
Definition: clean_temp.c:171
#define BUF_MAX
Definition: clean_temp.c:32
void clean_dir(const char *pathname, uid_t uid, pid_t pid, time_t now, int max_age)
Definition: clean_temp.c:39
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:61
void G_fatal_error(const char *msg,...)
Print a fatal error message to stderr.
Definition: gis/error.c:160
void G_warning(const char *msg,...)
Print a warning message to stderr.
Definition: gis/error.c:204
const char * G_mapset(void)
Get current mapset name.
Definition: mapset.c:33
void G_sleep(unsigned int seconds)
Definition: sleep.c:11
int G_snprintf(char *str, size_t size, const char *fmt,...)
snprintf() clone.
Definition: snprintf.c:43
int G_strcasecmp(const char *x, const char *y)
String compare ignoring case (upper or lower)
Definition: strings.c:47
Definition: lidar.h:87
void G_temp_element(char *element)
Populates element with a path string.
Definition: tempfile.c:102