mirror of https://github.com/MidnightCommander/mc
337 lines
6.5 KiB
C
337 lines
6.5 KiB
C
/* 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 <signal.h>
|
|
|
|
#ifdef HAVE_SYS_TYPES_H
|
|
# include <sys/types.h>
|
|
#endif
|
|
#ifdef HAVE_SYS_WAIT_H
|
|
# include <sys/wait.h>
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
|
|
#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 <windows.h>
|
|
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
|