14#define QDEBUG(...) Ase::debug ("AtQuit", __VA_ARGS__)
26 while ((entry =
readdir (dir)) !=
nullptr) {
27 char fullpath[
PATH_MAX + 1] = { 0, };
30 if (
stat (fullpath, &sb) == -1 || !S_ISREG (sb.st_mode))
32 FILE *file =
fopen (fullpath,
"r");
34 const int BUFFER_SIZE = 8192;
35 char buffer[BUFFER_SIZE + 1] = { 0, };
36 fread (buffer, BUFFER_SIZE, 1, file);
38 const char *tag =
"@@TEMPFILE_PID=";
39 char *tagp =
strstr (buffer, tag);
43 char procpath[
PATH_MAX + 1] = { 0, };
45 if (
access (procpath, F_OK) != 0) {
46 if (
unlink (fullpath) == 0)
65 atquit_add (atquit_handler);
69 atquit_del (atquit_handler);
71 delete atquit_handler;
89 while (tentries.
size()) {
108 g_pending_removals.add (filename);
115 g_pending_removals.del (filename);
124 this->kill_all (SIGTERM);
126 atquit_add (atquit_handler);
130 atquit_del (atquit_handler);
131 (*atquit_handler) ();
132 delete atquit_handler;
150 while (pids.
size()) {
153 log (
"AtQuit: %s: pid=%d signal=%d", __func__, pid, sig);
167 g_kill_pids.add (pid);
174 g_kill_pids.del (pid);
182 for (
const auto &arg : argv)
183 argvptr.push_back (arg.c_str());
184 argvptr.push_back (
nullptr);
185 const char **child_argv = &argvptr[0];
189 return {
errno,
"fork" };
196 int max_fd =
sysconf (_SC_OPEN_MAX);
199 for (
int i = 3; i < max_fd; i++)
202 const char *
const home =
getenv (
"HOME");
203 if (home &&
chdir (home) < 0) {
204 ereason = {
errno,
"chdir" };
208 ereason = {
errno,
"unsetenv" };
213 if (
sigprocmask (SIG_SETMASK, &empty_mask,
nullptr) < 0) {
214 ereason = {
errno,
"sigprocmask" };
218 if (pdeathsig > 0 && prctl (PR_SET_PDEATHSIG, SIGKILL) < 0) {
219 ereason = {
errno,
"prctl(PR_SET_PDEATHSIG)" };
222 execvp (child_argv[0],
const_cast<char *
const *
> (child_argv));
224 ereason = {
errno,
"execvp" };
226 fprintf (
stderr,
"%s[pid=%d]: fork to exec %s: %s: %s\n", program_invocation_short_name, pid,
227 child_argv[0], ereason.what.
c_str(),
strerror (ereason.error));
236 middlename +=
"XXXXXX";
262 atquit_handlers.atquit_funcs.
push_back (func);
275AtquitHandlers::call_hooks()
278 while (atquit_funcs.
size())
292atquit_terminate (
int exitcode,
int pgroup)
294 atquit_triggered_ =
true;
295 atquit_handlers.call_hooks();
298 sa.sa_handler = SIG_DFL;
302 log (
"AtQuit: killing process group: pid=%d signal=%d", pgroup, SIGTERM);
303 kill (-pgroup, SIGTERM);
312 return atquit_triggered_;
size_t erase_first(C &container, const std::function< bool(typename C::value_type const &value)> &pred)
Erase first element for which pred() is true in vector or list.
The Anklang C++ API namespace.
std::string string_format(const char *format, const Args &...args) __attribute__((__format__(__printf__
Format a string similar to sprintf(3) with support for std::string and std::ostringstream convertible...
void atquit_add_removal(const std::string &filename)
Remove filename (or directory) when the program terminates.
ErrorReason spawn_process(const std::vector< std::string > &argv, pid_t *child_pid, int pdeathsig)
Span a child process after cleaning up the environment.
void atquit_del_killl_pid(int pid)
Undo a previous atquit_add_killl_pid() call.
void atquit_del_removal(const std::string &filename)
Undo a previous atquit_add_removal() call.
void cleanup_orphaned_tempfiles(const std::string &directory)
Delete all files that contain @TEMPFILE_PID=d@ without a running pid_t d.
void atquit_add_killl_pid(int pid)
Kill pid when the program terminates.
std::string create_tempfile_dir(const std::string &basename)
Create temporary directory under /tmp, scheduled for removal atquit.
Cleanup list of child processes still running at exit.
Cleanup list of temporary files/dirs to be removed at exit.
T temp_directory_path(T... args)