CVS patchset: 6692
CVS date: 2003/03/15 21:51:11
This commit is contained in:
jbj 2003-03-15 21:51:11 +00:00
parent 55b458f933
commit 0feab83bbe
3 changed files with 235 additions and 191 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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;
}