/* Copyright (c) 1998, 1999, 2001, 2002 John E. Davis * This file is part of the S-Lang library. * * You may distribute under the terms of either the GNU General Public * License or the Perl Artistic License. */ #include "slinclud.h" #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_WAIT_H # include #endif #include #include "slang.h" #include "_slang.h" /* Do not trust these environments */ #if defined(__CYGWIN32__) || defined(__MINGW32__) || defined(AMIGA) # ifdef SLANG_POSIX_SIGNALS # undef SLANG_POSIX_SIGNALS # endif #endif /* This function will cause system calls to be restarted after signal if possible */ SLSig_Fun_Type *SLsignal (int sig, SLSig_Fun_Type *f) { #if defined(SLANG_POSIX_SIGNALS) struct sigaction old_sa, new_sa; # ifdef SIGALRM /* We want system calls to be interrupted by SIGALRM. */ if (sig == SIGALRM) return SLsignal_intr (sig, f); # endif sigemptyset (&new_sa.sa_mask); new_sa.sa_handler = f; new_sa.sa_flags = 0; # ifdef SA_RESTART new_sa.sa_flags |= SA_RESTART; # endif if (-1 == sigaction (sig, &new_sa, &old_sa)) return (SLSig_Fun_Type *) SIG_ERR; return old_sa.sa_handler; #else /* Not POSIX. */ return signal (sig, f); #endif } /* This function will NOT cause system calls to be restarted after * signal if possible */ SLSig_Fun_Type *SLsignal_intr (int sig, SLSig_Fun_Type *f) { #ifdef SLANG_POSIX_SIGNALS struct sigaction old_sa, new_sa; sigemptyset (&new_sa.sa_mask); new_sa.sa_handler = f; new_sa.sa_flags = 0; # ifdef SA_INTERRUPT new_sa.sa_flags |= SA_INTERRUPT; # endif if (-1 == sigaction (sig, &new_sa, &old_sa)) return (SLSig_Fun_Type *) SIG_ERR; return old_sa.sa_handler; #else /* Not POSIX. */ return signal (sig, f); #endif } /* We are primarily interested in blocking signals that would cause the * application to reset the tty. These include suspend signals and * possibly interrupt signals. */ #ifdef SLANG_POSIX_SIGNALS static sigset_t Old_Signal_Mask; #endif static volatile unsigned int Blocked_Depth; int SLsig_block_signals (void) { #ifdef SLANG_POSIX_SIGNALS sigset_t new_mask; #endif Blocked_Depth++; if (Blocked_Depth != 1) { return 0; } #ifdef SLANG_POSIX_SIGNALS sigemptyset (&new_mask); # ifdef SIGQUIT sigaddset (&new_mask, SIGQUIT); # endif # ifdef SIGTSTP sigaddset (&new_mask, SIGTSTP); # endif # ifdef SIGINT sigaddset (&new_mask, SIGINT); # endif # ifdef SIGTTIN sigaddset (&new_mask, SIGTTIN); # endif # ifdef SIGTTOU sigaddset (&new_mask, SIGTTOU); # endif # ifdef SIGWINCH sigaddset (&new_mask, SIGWINCH); # endif (void) sigprocmask (SIG_BLOCK, &new_mask, &Old_Signal_Mask); return 0; #else /* Not implemented. */ return -1; #endif } int SLsig_unblock_signals (void) { if (Blocked_Depth == 0) return -1; Blocked_Depth--; if (Blocked_Depth != 0) return 0; #ifdef SLANG_POSIX_SIGNALS (void) sigprocmask (SIG_SETMASK, &Old_Signal_Mask, NULL); return 0; #else return -1; #endif } #ifdef MSWINDOWS int SLsystem (char *cmd) { SLang_verror (SL_NOT_IMPLEMENTED, "system not implemented"); return -1; } #else int SLsystem (char *cmd) { #ifdef SLANG_POSIX_SIGNALS pid_t pid; int status; struct sigaction ignore; # ifdef SIGINT struct sigaction save_intr; # endif # ifdef SIGQUIT struct sigaction save_quit; # endif # ifdef SIGCHLD sigset_t child_mask, save_mask; # endif if (cmd == NULL) return 1; ignore.sa_handler = SIG_IGN; sigemptyset (&ignore.sa_mask); ignore.sa_flags = 0; # ifdef SIGINT if (-1 == sigaction (SIGINT, &ignore, &save_intr)) return -1; # endif # ifdef SIGQUIT if (-1 == sigaction (SIGQUIT, &ignore, &save_quit)) { (void) sigaction (SIGINT, &save_intr, NULL); return -1; } # endif # ifdef SIGCHLD sigemptyset (&child_mask); sigaddset (&child_mask, SIGCHLD); if (-1 == sigprocmask (SIG_BLOCK, &child_mask, &save_mask)) { # ifdef SIGINT (void) sigaction (SIGINT, &save_intr, NULL); # endif # ifdef SIGQUIT (void) sigaction (SIGQUIT, &save_quit, NULL); # endif return -1; } # endif pid = fork(); if (pid == -1) status = -1; else if (pid == 0) { /* Child */ # ifdef SIGINT (void) sigaction (SIGINT, &save_intr, NULL); # endif # ifdef SIGQUIT (void) sigaction (SIGQUIT, &save_quit, NULL); # endif # ifdef SIGCHLD (void) sigprocmask (SIG_SETMASK, &save_mask, NULL); # endif execl ("/bin/sh", "sh", "-c", cmd, NULL); _exit (127); } else { /* parent */ while (-1 == waitpid (pid, &status, 0)) { # ifdef EINTR if (errno == EINTR) continue; # endif # ifdef ERESTARTSYS if (errno == ERESTARTSYS) continue; # endif status = -1; break; } } # ifdef SIGINT if (-1 == sigaction (SIGINT, &save_intr, NULL)) status = -1; # endif # ifdef SIGQUIT if (-1 == sigaction (SIGQUIT, &save_quit, NULL)) status = -1; # endif # ifdef SIGCHLD if (-1 == sigprocmask (SIG_SETMASK, &save_mask, NULL)) status = -1; # endif return status; #else /* No POSIX Signals */ # ifdef SIGINT void (*sint)(int); # endif # ifdef SIGQUIT void (*squit)(int); # endif int status; # ifdef SIGQUIT squit = SLsignal (SIGQUIT, SIG_IGN); # endif # ifdef SIGINT sint = SLsignal (SIGINT, SIG_IGN); # endif status = system (cmd); # ifdef SIGINT SLsignal (SIGINT, sint); # endif # ifdef SIGQUIT SLsignal (SIGQUIT, squit); # endif return status; #endif /* POSIX_SIGNALS */ } #endif #if 0 #include static int msw_system (char *cmd) { STARTUPINFO startup_info; PROCESS_INFORMATION process_info; int status; if (cmd == NULL) return -1; memset ((char *) &startup_info, 0, sizeof (STARTUPINFO)); startup_info.cb = sizeof(STARTUPINFO); startup_info.dwFlags = STARTF_USESHOWWINDOW; startup_info.wShowWindow = SW_SHOWDEFAULT; if (FALSE == CreateProcess (NULL, cmd, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE, NULL, NULL, &startup_info, &process_info)) { SLang_verror (0, "%s: CreateProcess failed.", cmd); return -1; } status = -1; if (0xFFFFFFFFUL != WaitForSingleObject (process_info.hProcess, INFINITE)) { DWORD exit_code; if (TRUE == GetExitCodeProcess (process_info.hProcess, &exit_code)) status = (int) exit_code; } CloseHandle (process_info.hThread); CloseHandle (process_info.hProcess); return status; } #endif