1
1
s-lang/modules/fork-module.c

315 строки
7.2 KiB
C

/* -*- mode: C; mode: fold; -*- */
/*
Copyright (C) 2009-2017,2018 John E. Davis
This file is part of the S-Lang Library.
The S-Lang Library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The S-Lang Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA.
*/
#include "config.h"
#include <stdio.h>
#include <errno.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#include <unistd.h>
#include <string.h>
#include <slang.h>
/* WCONTINUED is not defined on Hurd, in waitflags.h. */
#ifndef WCONTINUED
# define WCONTINUED 0 /* Debian patch used 8, but 0 is safer */
#endif
SLANG_MODULE(fork);
static int fork_intrinsic (void)
{
int ret = fork ();
if (ret == -1)
(void) SLerrno_set_errno (errno);
return ret;
}
typedef struct
{
int pid;
int exited;
int exit_status;
int signal;
int coredump;
int stopped;
int continued;
}
Waitpid_Type;
static SLang_CStruct_Field_Type Waitpid_Struct [] =
{
MAKE_CSTRUCT_FIELD(Waitpid_Type, pid, "pid", SLANG_INT_TYPE, 0),
MAKE_CSTRUCT_FIELD(Waitpid_Type, exited, "exited", SLANG_INT_TYPE, 0),
MAKE_CSTRUCT_FIELD(Waitpid_Type, exit_status, "exit_status", SLANG_INT_TYPE, 0),
MAKE_CSTRUCT_FIELD(Waitpid_Type, signal, "signal", SLANG_INT_TYPE, 0),
MAKE_CSTRUCT_FIELD(Waitpid_Type, coredump, "coredump", SLANG_INT_TYPE, 0),
MAKE_CSTRUCT_FIELD(Waitpid_Type, stopped, "stopped", SLANG_INT_TYPE, 0),
MAKE_CSTRUCT_FIELD(Waitpid_Type, continued, "continued", SLANG_INT_TYPE, 0),
SLANG_END_CSTRUCT_TABLE
};
static void waitpid_intrinsic (int *pid, int *options)
{
int status, ret;
Waitpid_Type s;
while (-1 == (ret = waitpid ((pid_t)*pid, &status, *options)))
{
if (errno == EINTR)
{
if (-1 != SLang_handle_interrupt ())
continue;
}
(void) SLerrno_set_errno (errno);
(void) SLang_push_null ();
return;
}
memset ((char *)&s, 0, sizeof(Waitpid_Type));
if (WIFEXITED(status))
{
s.exited = 1;
s.exit_status = WEXITSTATUS(status);
}
if (WIFSIGNALED(status))
{
s.signal = WTERMSIG(status);
#ifdef WCOREDUMP
s.coredump = WCOREDUMP(status) != 0;
#endif
}
if (WIFSTOPPED(status))
s.stopped = WSTOPSIG(status);
#ifdef WIFCONTINUED
s.continued = WIFCONTINUED(status);
#endif
s.pid = ret;
(void) SLang_push_cstruct ((VOID_STAR)&s, Waitpid_Struct);
}
static char **pop_argv (SLang_Array_Type **atp)
{
SLang_Array_Type *at;
char **argv;
SLuindex_Type i, num, argc;
char **strp;
*atp = NULL;
if (-1 == SLang_pop_array_of_type (&at, SLANG_STRING_TYPE))
return NULL;
num = at->num_elements;
if (NULL == (argv = (char **)SLmalloc ((num+1)*sizeof(char *))))
{
SLang_free_array (at);
return NULL;
}
strp = (char **)at->data;
argc = 0;
for (i = 0; i < num; i++)
{
if (strp[i] != NULL)
argv[argc++] = strp[i];
}
argv[argc] = NULL;
*atp = at;
return argv;
}
#define CALL_EXECV 1
#define CALL_EXECVP 2
#define CALL_EXECVE 3
static int call_what (int what, char *path, char **argv, char **envp)
{
while (1)
{
int ret;
switch (what)
{
case CALL_EXECV:
ret = execv (path, argv);
break;
case CALL_EXECVP:
ret = execvp (path, argv);
break;
case CALL_EXECVE:
ret = execve (path, argv, envp);
break;
}
if (ret == 0)
return 0; /* should never happen */
SLerrno_set_errno (errno);
if (errno == EINTR)
{
if (-1 != SLang_handle_interrupt ())
continue;
}
break;
}
return -1;
}
static int exec_what (int what, int has_envp)
{
SLang_Array_Type *at_argv = NULL;
SLang_Array_Type *at_envp = NULL;
char **argv = NULL, **envp = NULL;
char *path = NULL;
int status = -1;
if (has_envp)
{
if (NULL == (envp = pop_argv (&at_envp)))
goto free_and_return;
}
if (NULL == (argv = pop_argv (&at_argv)))
goto free_and_return;
if (-1 == SLang_pop_slstring (&path))
goto free_and_return;
status = call_what (what, path, argv, envp);
free_and_return:
if (path != NULL) SLang_free_slstring (path);
if (argv != NULL) SLfree ((char *)argv);
if (at_argv != NULL) SLang_free_array (at_argv);
if (envp != NULL) SLfree ((char *)envp);
if (at_envp != NULL) SLang_free_array (at_envp);
return status;
}
static int execv_intrin (void)
{
if (SLang_Num_Function_Args != 2)
SLang_verror (SL_Usage_Error, "Usage: ret = execv(path, argv[]);");
return exec_what (CALL_EXECV, 0);
}
static int execvp_intrin (void)
{
if (SLang_Num_Function_Args != 2)
SLang_verror (SL_Usage_Error, "Usage: ret = execvp(path, argv[]);");
return exec_what (CALL_EXECVP, 0);
}
static int execve_intrin (void)
{
if (SLang_Num_Function_Args != 3)
SLang_verror (SL_Usage_Error, "Usage: ret = execve(path, argv[], env[]);");
return exec_what (CALL_EXECVE, 1);
}
static void _exit_intrin (int *s)
{
(void) fflush (stdout);
(void) fflush (stderr);
_exit (*s);
}
static void pipe_intrin (void)
{
int fds[2];
SLFile_FD_Type *f0;
SLFile_FD_Type *f1;
while (-1 == pipe (fds))
{
if (errno == EINTR)
{
if (-1 != SLang_handle_interrupt ())
continue;
}
SLerrno_set_errno (errno);
SLang_verror (SL_OS_Error, "pipe failed: %s", SLerrno_strerror(errno));
return;
}
f0 = SLfile_create_fd ("*pipe*", fds[0]);
f1 = SLfile_create_fd ("*pipe*", fds[1]);
if ((NULL != f0) && (NULL != f1))
{
/* Ignore errors and allow the free_fd routines to clean up */
(void) SLfile_push_fd (f0);
(void) SLfile_push_fd (f1);
}
SLfile_free_fd (f1);
SLfile_free_fd (f0);
}
static SLang_IConstant_Type Module_IConstants [] =
{
MAKE_ICONSTANT("WNOHANG", WNOHANG),
MAKE_ICONSTANT("WUNTRACED", WUNTRACED),
MAKE_ICONSTANT("WCONTINUED", WCONTINUED),
SLANG_END_ICONST_TABLE
};
static SLang_Intrin_Fun_Type Module_Intrinsics [] =
{
MAKE_INTRINSIC_0("fork", fork_intrinsic, SLANG_INT_TYPE),
MAKE_INTRINSIC_2("waitpid", waitpid_intrinsic, SLANG_VOID_TYPE, SLANG_INT_TYPE, SLANG_INT_TYPE),
MAKE_INTRINSIC_0("execv", execv_intrin, SLANG_INT_TYPE),
MAKE_INTRINSIC_0("execvp", execvp_intrin, SLANG_INT_TYPE),
MAKE_INTRINSIC_0("execve", execve_intrin, SLANG_INT_TYPE),
MAKE_INTRINSIC_0("pipe", pipe_intrin, SLANG_VOID_TYPE),
MAKE_INTRINSIC_1("_exit", _exit_intrin, SLANG_VOID_TYPE, SLANG_INT_TYPE),
SLANG_END_INTRIN_FUN_TABLE
};
int init_fork_module_ns (char *ns_name)
{
SLang_NameSpace_Type *ns = SLns_create_namespace (ns_name);
if (ns == NULL)
return -1;
if ((-1 == SLns_add_intrin_fun_table (ns, Module_Intrinsics, NULL))
|| (-1 == SLns_add_iconstant_table (ns, Module_IConstants, NULL)))
return -1;
return 0;
}
/* This function is optional */
void deinit_fork_module (void)
{
}