parent
55b458f933
commit
0feab83bbe
|
@ -100,6 +100,9 @@ trb: trb.o librpm.la
|
|||
tthread: tthread.o librpm.la
|
||||
$(LINK) $(CFLAGS) $(DEFS) $(INCLUDES) -o $@ $< $(mylibs) @WITH_LIBELF_LIB@
|
||||
|
||||
tsystem: tsystem.o
|
||||
$(LINK) $(CFLAGS) $(DEFS) $(INCLUDES) -o $@ $< -L/lib/tls -lpthread
|
||||
|
||||
tplatform: tplatform.o librpm.la
|
||||
$(LINK) @LDFLAGS_STATIC@ $(CFLAGS) $(DEFS) $(INCLUDES) -o $@ $< $(mylibs)
|
||||
|
||||
|
|
|
@ -797,7 +797,7 @@ static rpmRC runScript(rpmpsm psm, Header h, const char * sln,
|
|||
psm->child = 0;
|
||||
psm->reaped = 0;
|
||||
psm->status = 0;
|
||||
psm->reaper = 0;
|
||||
psm->reaper = 1;
|
||||
|
||||
/* XXX FIXME: except for %verifyscript, rpmteNEVR can be used. */
|
||||
xx = headerNVR(h, &n, &v, &r);
|
||||
|
|
421
lib/tsystem.c
421
lib/tsystem.c
|
@ -18,12 +18,134 @@
|
|||
02111-1307 USA. */
|
||||
|
||||
#include <sched.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <sysdep.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/wait.h>
|
||||
#include <bits/libc-lock.h>
|
||||
#include <kernel-features.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define SHELL_PATH "/bin/sh" /* Path of the shell. */
|
||||
#define SHELL_NAME "sh" /* Name to give it. */
|
||||
|
||||
static struct sigaction intr;
|
||||
static struct sigaction quit;
|
||||
|
||||
static int syssa_refcnt;
|
||||
|
||||
static pthread_mutex_t syssa_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/* =============================================================== */
|
||||
|
||||
/* We need some help from the assembler to generate optimal code. We
|
||||
define some macros here which later will be used. */
|
||||
asm (".L__X'%ebx = 1\n\t"
|
||||
".L__X'%ecx = 2\n\t"
|
||||
".L__X'%edx = 2\n\t"
|
||||
".L__X'%eax = 3\n\t"
|
||||
".L__X'%esi = 3\n\t"
|
||||
".L__X'%edi = 3\n\t"
|
||||
".L__X'%ebp = 3\n\t"
|
||||
".L__X'%esp = 3\n\t"
|
||||
".macro bpushl name reg\n\t"
|
||||
".if 1 - \\name\n\t"
|
||||
".if 2 - \\name\n\t"
|
||||
"pushl %ebx\n\t"
|
||||
".else\n\t"
|
||||
"xchgl \\reg, %ebx\n\t"
|
||||
".endif\n\t"
|
||||
".endif\n\t"
|
||||
".endm\n\t"
|
||||
".macro bpopl name reg\n\t"
|
||||
".if 1 - \\name\n\t"
|
||||
".if 2 - \\name\n\t"
|
||||
"popl %ebx\n\t"
|
||||
".else\n\t"
|
||||
"xchgl \\reg, %ebx\n\t"
|
||||
".endif\n\t"
|
||||
".endif\n\t"
|
||||
".endm\n\t"
|
||||
".macro bmovl name reg\n\t"
|
||||
".if 1 - \\name\n\t"
|
||||
".if 2 - \\name\n\t"
|
||||
"movl \\reg, %ebx\n\t"
|
||||
".endif\n\t"
|
||||
".endif\n\t"
|
||||
".endm\n\t");
|
||||
|
||||
/* Define a macro which expands inline into the wrapper code for a system
|
||||
call. */
|
||||
#undef INLINE_SYSCALL
|
||||
#define INLINE_SYSCALL(name, nr, args...) \
|
||||
({ \
|
||||
unsigned int resultvar = INTERNAL_SYSCALL (name, , nr, args); \
|
||||
if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (resultvar, ), 0)) \
|
||||
{ \
|
||||
errno = (INTERNAL_SYSCALL_ERRNO (resultvar, )); \
|
||||
resultvar = 0xffffffff; \
|
||||
} \
|
||||
(int) resultvar; })
|
||||
|
||||
/* Define a macro which expands inline into the wrapper code for a system
|
||||
call. This use is for internal calls that do not need to handle errors
|
||||
normally. It will never touch errno. This returns just what the kernel
|
||||
gave back. */
|
||||
# define INTERNAL_SYSCALL(name, err, nr, args...) \
|
||||
({ \
|
||||
unsigned int resultvar; \
|
||||
asm volatile ( \
|
||||
LOADARGS_##nr \
|
||||
"movl %1, %%eax\n\t" \
|
||||
"int $0x80\n\t" \
|
||||
RESTOREARGS_##nr \
|
||||
: "=a" (resultvar) \
|
||||
: "i" (__NR_##name) ASMFMT_##nr(args) : "memory", "cc"); \
|
||||
(int) resultvar; })
|
||||
|
||||
#undef INTERNAL_SYSCALL_DECL
|
||||
#define INTERNAL_SYSCALL_DECL(err) do { } while (0)
|
||||
|
||||
#undef INTERNAL_SYSCALL_ERROR_P
|
||||
#define INTERNAL_SYSCALL_ERROR_P(val, err) \
|
||||
((unsigned int) (val) >= 0xfffff001u)
|
||||
|
||||
#undef INTERNAL_SYSCALL_ERRNO
|
||||
#define INTERNAL_SYSCALL_ERRNO(val, err) (-(val))
|
||||
|
||||
#define LOADARGS_0
|
||||
# define LOADARGS_1 \
|
||||
"bpushl .L__X'%k3, %k3\n\t" \
|
||||
"bmovl .L__X'%k3, %k3\n\t"
|
||||
#define LOADARGS_2 LOADARGS_1
|
||||
#define LOADARGS_3 LOADARGS_1
|
||||
#define LOADARGS_4 LOADARGS_1
|
||||
#define LOADARGS_5 LOADARGS_1
|
||||
|
||||
#define RESTOREARGS_0
|
||||
# define RESTOREARGS_1 \
|
||||
"bpopl .L__X'%k3, %k3\n\t"
|
||||
#define RESTOREARGS_2 RESTOREARGS_1
|
||||
#define RESTOREARGS_3 RESTOREARGS_1
|
||||
#define RESTOREARGS_4 RESTOREARGS_1
|
||||
#define RESTOREARGS_5 RESTOREARGS_1
|
||||
|
||||
#define ASMFMT_0()
|
||||
#define ASMFMT_1(arg1) \
|
||||
, "acdSD" (arg1)
|
||||
#define ASMFMT_2(arg1, arg2) \
|
||||
, "adSD" (arg1), "c" (arg2)
|
||||
#define ASMFMT_3(arg1, arg2, arg3) \
|
||||
, "aSD" (arg1), "c" (arg2), "d" (arg3)
|
||||
#define ASMFMT_4(arg1, arg2, arg3, arg4) \
|
||||
, "aD" (arg1), "c" (arg2), "d" (arg3), "S" (arg4)
|
||||
#define ASMFMT_5(arg1, arg2, arg3, arg4, arg5) \
|
||||
, "a" (arg1), "c" (arg2), "d" (arg3), "S" (arg4), "D" (arg5)
|
||||
|
||||
/* We have to and actually can handle cancelable system(). The big
|
||||
problem: we have to kill the child process if necessary. To do
|
||||
|
@ -33,250 +155,169 @@
|
|||
return. It might still be in the kernel when the cancellation
|
||||
request comes. Therefore we have to use the clone() calls ability
|
||||
to have the kernel write the PID into the user-level variable. */
|
||||
#ifdef __ASSUME_CLONE_THREAD_FLAGS
|
||||
# define FORK() \
|
||||
INLINE_SYSCALL (clone, 3, CLONE_PARENT_SETTID | SIGCHLD, 0, &pid)
|
||||
#endif
|
||||
|
||||
/* =============================================================== */
|
||||
|
||||
/* The cancellation handler. */
|
||||
static void
|
||||
cancel_handler (void *arg)
|
||||
{
|
||||
pid_t child = *(pid_t *) arg;
|
||||
pid_t result;
|
||||
int err;
|
||||
|
||||
INTERNAL_SYSCALL_DECL (err);
|
||||
INTERNAL_SYSCALL (kill, err, 2, child, SIGKILL);
|
||||
err = kill(child, SIGKILL);
|
||||
|
||||
TEMP_FAILURE_RETRY (__waitpid (child, NULL, 0));
|
||||
do {
|
||||
result = waitpid(child, NULL, 0);
|
||||
} while (result == (pid_t)-1 && errno == EINTR);
|
||||
|
||||
DO_LOCK ();
|
||||
|
||||
if (SUB_REF () == 0)
|
||||
{
|
||||
(void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
|
||||
(void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
|
||||
}
|
||||
|
||||
DO_UNLOCK ();
|
||||
pthread_mutex_lock(&syssa_lock);
|
||||
if (--syssa_refcnt == 0) {
|
||||
(void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
|
||||
(void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
|
||||
}
|
||||
pthread_mutex_unlock(&syssa_lock);
|
||||
}
|
||||
|
||||
#define CLEANUP_HANDLER \
|
||||
__libc_cleanup_region_start (1, cancel_handler, &pid)
|
||||
|
||||
#define CLEANUP_RESET \
|
||||
__libc_cleanup_region_end (0)
|
||||
|
||||
|
||||
/* Copyright (C) 1991-2000, 2002, 2003 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <bits/libc-lock.h>
|
||||
#include <sysdep-cancel.h>
|
||||
|
||||
|
||||
#ifndef HAVE_GNU_LD
|
||||
#define __environ environ
|
||||
#endif
|
||||
|
||||
#define SHELL_PATH "/bin/sh" /* Path of the shell. */
|
||||
#define SHELL_NAME "sh" /* Name to give it. */
|
||||
|
||||
|
||||
#ifdef _LIBC_REENTRANT
|
||||
static struct sigaction intr, quit;
|
||||
static int sa_refcntr;
|
||||
__libc_lock_define_initialized (static, lock);
|
||||
|
||||
# define DO_LOCK() __libc_lock_lock (lock)
|
||||
# define DO_UNLOCK() __libc_lock_unlock (lock)
|
||||
# define INIT_LOCK() ({ __libc_lock_init (lock); sa_refcntr = 0; })
|
||||
# define ADD_REF() sa_refcntr++
|
||||
# define SUB_REF() --sa_refcntr
|
||||
#else
|
||||
# define DO_LOCK()
|
||||
# define DO_UNLOCK()
|
||||
# define INIT_LOCK()
|
||||
# define ADD_REF() 0
|
||||
# define SUB_REF() 0
|
||||
#endif
|
||||
|
||||
|
||||
/* Execute LINE as a shell command, returning its status. */
|
||||
static int
|
||||
do_system (const char *line)
|
||||
{
|
||||
int status, save;
|
||||
int oldtype;
|
||||
int status;
|
||||
int save;
|
||||
pid_t pid;
|
||||
pid_t result;
|
||||
struct sigaction sa;
|
||||
#ifndef _LIBC_REENTRANT
|
||||
struct sigaction intr, quit;
|
||||
#endif
|
||||
sigset_t omask;
|
||||
|
||||
fprintf(stderr, "*** %s(%p) %s\n", __FUNCTION__, line, line);
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sa.sa_flags = 0;
|
||||
__sigemptyset (&sa.sa_mask);
|
||||
sigemptyset (&sa.sa_mask);
|
||||
|
||||
DO_LOCK ();
|
||||
if (ADD_REF () == 0)
|
||||
{
|
||||
if (__sigaction (SIGINT, &sa, &intr) < 0)
|
||||
{
|
||||
SUB_REF ();
|
||||
pthread_mutex_lock(&syssa_lock);
|
||||
if (syssa_refcnt++ == 0) {
|
||||
if (sigaction (SIGINT, &sa, &intr) < 0) {
|
||||
--syssa_refcnt;
|
||||
goto out;
|
||||
}
|
||||
if (__sigaction (SIGQUIT, &sa, &quit) < 0)
|
||||
{
|
||||
}
|
||||
if (sigaction (SIGQUIT, &sa, &quit) < 0) {
|
||||
save = errno;
|
||||
SUB_REF ();
|
||||
--syssa_refcnt;
|
||||
goto out_restore_sigint;
|
||||
}
|
||||
}
|
||||
DO_UNLOCK ();
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&syssa_lock);
|
||||
|
||||
/* We reuse the bitmap in the 'sa' structure. */
|
||||
__sigaddset (&sa.sa_mask, SIGCHLD);
|
||||
sigaddset (&sa.sa_mask, SIGCHLD);
|
||||
save = errno;
|
||||
if (__sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0)
|
||||
{
|
||||
#ifndef _LIBC
|
||||
if (errno == ENOSYS)
|
||||
__set_errno (save);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
DO_LOCK ();
|
||||
if (SUB_REF () == 0)
|
||||
if (sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0) {
|
||||
pthread_mutex_lock(&syssa_lock);
|
||||
if (--syssa_refcnt == 0)
|
||||
{
|
||||
save = errno;
|
||||
(void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
|
||||
(void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
|
||||
out_restore_sigint:
|
||||
(void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
|
||||
__set_errno (save);
|
||||
(void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
|
||||
errno = save;
|
||||
}
|
||||
out:
|
||||
DO_UNLOCK ();
|
||||
pthread_mutex_unlock(&syssa_lock);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CLEANUP_HANDLER
|
||||
CLEANUP_HANDLER;
|
||||
#endif
|
||||
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
|
||||
pthread_cleanup_push(cancel_handler, &pid);
|
||||
|
||||
/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
|
||||
pid_t *tid, struct user_desc *tls); */
|
||||
/* INLINE_SYSCALL (clone, 3, CLONE_PARENT_SETTID | SIGCHLD, 0, &pid) */
|
||||
|
||||
/* pid = clone(sub, NULL, (CLONE_PARENT_SETTID | SIGCHLD), line,
|
||||
&pid???, &tls???); */
|
||||
|
||||
#ifdef FORK
|
||||
pid = FORK ();
|
||||
#else
|
||||
pid = __fork ();
|
||||
#endif
|
||||
if (pid == (pid_t) 0)
|
||||
{
|
||||
/* Child side. */
|
||||
const char *new_argv[4];
|
||||
new_argv[0] = SHELL_NAME;
|
||||
new_argv[1] = "-c";
|
||||
new_argv[2] = line;
|
||||
new_argv[3] = NULL;
|
||||
if (pid == (pid_t) 0) {
|
||||
/* Child side. */
|
||||
const char *new_argv[4];
|
||||
new_argv[0] = SHELL_NAME;
|
||||
new_argv[1] = "-c";
|
||||
new_argv[2] = line;
|
||||
new_argv[3] = NULL;
|
||||
|
||||
/* Restore the signals. */
|
||||
(void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
|
||||
(void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
|
||||
(void) __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
|
||||
INIT_LOCK ();
|
||||
/* Restore the signals. */
|
||||
(void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
|
||||
(void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
|
||||
(void) sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
|
||||
|
||||
/* Exec the shell. */
|
||||
(void) __execve (SHELL_PATH, (char *const *) new_argv, __environ);
|
||||
_exit (127);
|
||||
}
|
||||
else if (pid < (pid_t) 0)
|
||||
{ pthread_mutex_init (&syssa_lock, NULL); syssa_refcnt = 0; }
|
||||
|
||||
/* Exec the shell. */
|
||||
(void) execve (SHELL_PATH, (char *const *) new_argv, __environ);
|
||||
_exit (127);
|
||||
} else if (pid < (pid_t) 0) {
|
||||
/* The fork failed. */
|
||||
status = -1;
|
||||
else
|
||||
} else {
|
||||
/* Parent side. */
|
||||
{
|
||||
#ifdef NO_WAITPID
|
||||
pid_t child;
|
||||
do
|
||||
{
|
||||
child = __wait (&status);
|
||||
if (child <= -1 && errno != EINTR)
|
||||
{
|
||||
status = -1;
|
||||
break;
|
||||
}
|
||||
/* Note that pid cannot be <= -1 and therefore the loop continues
|
||||
when __wait returned with EINTR. */
|
||||
}
|
||||
while (child != pid);
|
||||
#else
|
||||
if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) != pid)
|
||||
status = -1;
|
||||
#endif
|
||||
}
|
||||
do {
|
||||
result = waitpid(pid, &status, 0);
|
||||
} while (result == (pid_t)-1 && errno == EINTR);
|
||||
if (result != pid)
|
||||
status = -1;
|
||||
}
|
||||
|
||||
#ifdef CLEANUP_HANDLER
|
||||
CLEANUP_RESET;
|
||||
#endif
|
||||
pthread_cleanup_pop(0);
|
||||
pthread_setcanceltype (oldtype, &oldtype);
|
||||
|
||||
save = errno;
|
||||
DO_LOCK ();
|
||||
if ((SUB_REF () == 0
|
||||
&& (__sigaction (SIGINT, &intr, (struct sigaction *) NULL)
|
||||
| __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0)
|
||||
|| __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0)
|
||||
{
|
||||
#ifndef _LIBC
|
||||
/* glibc cannot be used on systems without waitpid. */
|
||||
if (errno == ENOSYS)
|
||||
__set_errno (save);
|
||||
else
|
||||
#endif
|
||||
pthread_mutex_lock(&syssa_lock);
|
||||
if ((--syssa_refcnt == 0
|
||||
&& (sigaction (SIGINT, &intr, (struct sigaction *) NULL)
|
||||
| sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0)
|
||||
|| sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0)
|
||||
{
|
||||
status = -1;
|
||||
}
|
||||
DO_UNLOCK ();
|
||||
}
|
||||
pthread_mutex_unlock(&syssa_lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int
|
||||
__libc_system (const char *line)
|
||||
static int
|
||||
system (const char * line)
|
||||
{
|
||||
|
||||
fprintf(stderr, "*** %s(%p) %s\n", __FUNCTION__, line, line);
|
||||
if (line == NULL)
|
||||
/* Check that we have a command processor available. It might
|
||||
not be available after a chroot(), for example. */
|
||||
return do_system ("exit 0") == 0;
|
||||
|
||||
if (SINGLE_THREAD_P)
|
||||
return do_system (line);
|
||||
|
||||
int oldtype = LIBC_CANCEL_ASYNC ();
|
||||
|
||||
int result = do_system (line);
|
||||
|
||||
LIBC_CANCEL_RESET (oldtype);
|
||||
|
||||
return result;
|
||||
return do_system (line);
|
||||
}
|
||||
weak_alias (__libc_system, system)
|
||||
|
||||
static void *
|
||||
other_thread(void *dat)
|
||||
{
|
||||
const char * s = (const char *)dat;
|
||||
fprintf(stderr, "*** %s(%p)\n", __FUNCTION__, dat);
|
||||
return ((void *) system(s));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
pthread_t pth;
|
||||
|
||||
pthread_create(&pth, NULL, other_thread, "/bin/pwd" );
|
||||
|
||||
pthread_join(pth, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue