15#define QDEBUG(...) Ase::debug ("AtQuit", __VA_ARGS__)
27 while ((entry =
readdir (dir)) !=
nullptr) {
28 char fullpath[
PATH_MAX + 1] = { 0, };
31 if (
stat (fullpath, &sb) == -1 || !S_ISREG (sb.st_mode))
33 FILE *file =
fopen (fullpath,
"r");
35 const int BUFFER_SIZE = 8192;
36 char buffer[BUFFER_SIZE + 1] = { 0, };
37 fread (buffer, BUFFER_SIZE, 1, file);
39 const char *tag =
"@@TEMPFILE_PID=";
40 char *tagp =
strstr (buffer, tag);
44 char procpath[
PATH_MAX + 1] = { 0, };
46 if (
access (procpath, F_OK) != 0) {
47 if (
unlink (fullpath) == 0)
49 diag (
"AtQuit: %s: remove \"%s\": %s", __func__, fullpath,
strerror (
errno));
66 atquit_add (atquit_handler);
70 atquit_del (atquit_handler);
72 delete atquit_handler;
90 while (tentries.
size()) {
96 diag (
"AtQuit: %s: remove \"%s\": %s", __func__, tentry,
strerror (
errno));
109 g_pending_removals.add (filename);
116 g_pending_removals.del (filename);
125 this->kill_all (SIGTERM);
127 atquit_add (atquit_handler);
131 atquit_del (atquit_handler);
132 (*atquit_handler) ();
133 delete atquit_handler;
151 while (pids.
size()) {
154 diag (
"AtQuit: %s: pid=%d signal=%d", __func__, pid, sig);
168 g_kill_pids.add (pid);
175 g_kill_pids.del (pid);
183 for (
const auto &arg : argv)
184 argvptr.push_back (arg.c_str());
185 argvptr.push_back (
nullptr);
186 const char **child_argv = &argvptr[0];
190 return {
errno,
"fork" };
197 int max_fd =
sysconf (_SC_OPEN_MAX);
200 for (
int i = 3; i < max_fd; i++)
203 const char *
const home =
getenv (
"HOME");
204 if (home &&
chdir (home) < 0) {
205 ereason = {
errno,
"chdir" };
209 ereason = {
errno,
"unsetenv" };
214 if (
sigprocmask (SIG_SETMASK, &empty_mask,
nullptr) < 0) {
215 ereason = {
errno,
"sigprocmask" };
219 if (pdeathsig > 0 && prctl (PR_SET_PDEATHSIG, SIGKILL) < 0) {
220 ereason = {
errno,
"prctl(PR_SET_PDEATHSIG)" };
223 execvp (child_argv[0],
const_cast<char *
const *
> (child_argv));
225 ereason = {
errno,
"execvp" };
227 fprintf (
stderr,
"%s[pid=%d]: fork to exec %s: %s: %s\n", program_invocation_short_name, pid,
228 child_argv[0], ereason.what.
c_str(),
strerror (ereason.error));
237 middlename +=
"XXXXXX";
263 atquit_handlers.atquit_funcs.
push_back (func);
276AtquitHandlers::call_hooks()
279 while (atquit_funcs.
size())
293atquit_terminate (
int exitcode,
int pgroup)
295 atquit_triggered_ =
true;
296 atquit_handlers.call_hooks();
299 sa.sa_handler = SIG_DFL;
303 diag (
"AtQuit: killing process group: pid=%d signal=%d", pgroup, SIGTERM);
304 kill (-pgroup, SIGTERM);
313 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)