@@ -234,6 +234,64 @@ SEXP processx_set_stderr_to_file(SEXP file) {
234234SEXP processx_base64_encode (SEXP array );
235235SEXP processx_base64_decode (SEXP array );
236236
237+
238+ #ifndef _WIN32
239+
240+ #include <string.h>
241+ #include <signal.h>
242+
243+ const char * rimraf_tmpdir_cmd = NULL ;
244+
245+ void term_handler (int n ) {
246+ R_system (rimraf_tmpdir_cmd );
247+
248+ // We don't run finalization handlers because running R code from a
249+ // signal handler is not safe. To properly clean up a process, we'd
250+ // need R to handle SIGTERM and clean up at check-interrupt
251+ // time. We do run `atexit()` handlers though.
252+ exit (EXIT_FAILURE );
253+ }
254+
255+ void install_term_handler (void ) {
256+ if (getenv ("PROCESSX_NO_R_SIGTERM_CLEANUP" )) {
257+ return ;
258+ }
259+
260+ const char * tmp_dir = getenv ("R_SESSION_TMPDIR" );
261+
262+ // Should not happen but just in case
263+ if (!tmp_dir ) {
264+ return ;
265+ }
266+
267+ // Only install the handler if the tempdir doesn't have special
268+ // characters because we clean it through a `rm -rf` call in a
269+ // subprocess to avoid calling async-signal-unsafe functions like
270+ // `R_unlink(). Also it's faster with some filesystems, see notes in
271+ // the `R_CleanTempDir()` implementation.
272+ char * special = "'\\`$\"\n" ;
273+
274+ for (int i = 0 ; special [i ] != '\0' ; ++ i ) {
275+ if (strchr (tmp_dir , special [i ])) {
276+ return ;
277+ }
278+ }
279+
280+ // To make the handler as simple as we can we ignore the possibility
281+ // of the temp directory changing during the session, and create the
282+ // command string upfront. It is protected via the symbol table.
283+ SEXP rimraf_tmpdir_sym = R_ParseEvalString ("as.symbol(paste0('rm -rf ', tempdir()))" ,
284+ R_BaseNamespace );
285+ rimraf_tmpdir_cmd = CHAR (PRINTNAME (rimraf_tmpdir_sym ));
286+
287+ struct sigaction sig = {{ 0 }};
288+ sig .sa_handler = term_handler ;
289+ sigaction (SIGTERM , & sig , NULL );
290+ }
291+
292+ #endif // not _WIN32
293+
294+
237295static const R_CallMethodDef callMethods [] = {
238296 { "processx_base64_encode" , (DL_FUNC ) & processx_base64_encode , 1 },
239297 { "processx_base64_decode" , (DL_FUNC ) & processx_base64_decode , 1 },
@@ -250,4 +308,8 @@ void R_init_client(DllInfo *dll) {
250308 R_registerRoutines (dll , NULL , callMethods , NULL , NULL );
251309 R_useDynamicSymbols (dll , FALSE);
252310 R_forceSymbols (dll , TRUE);
311+
312+ #ifndef _WIN32
313+ install_term_handler ();
314+ #endif
253315}
0 commit comments