From 0feab83bbe7f1d8a76e66cbfbe33f9459086cf93 Mon Sep 17 00:00:00 2001 From: jbj Date: Sat, 15 Mar 2003 21:51:11 +0000 Subject: [PATCH] Sanity. CVS patchset: 6692 CVS date: 2003/03/15 21:51:11 --- lib/Makefile.am | 3 + lib/psm.c | 2 +- lib/tsystem.c | 419 +++++++++++++++++++++++++++++++------------------------- 3 files changed, 234 insertions(+), 190 deletions(-) diff --git a/lib/Makefile.am b/lib/Makefile.am index d38aab2..bea82b1 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -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) diff --git a/lib/psm.c b/lib/psm.c index 72ecb67..ba19f7b 100644 --- a/lib/psm.c +++ b/lib/psm.c @@ -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); diff --git a/lib/tsystem.c b/lib/tsystem.c index 14b0636..dffa220 100644 --- a/lib/tsystem.c +++ b/lib/tsystem.c @@ -18,12 +18,134 @@ 02111-1307 USA. */ #include +#include + #include -#include #include +#include #include -#include -#include + +#include +#include +#include +#include +#include + +#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); - - TEMP_FAILURE_RETRY (__waitpid (child, NULL, 0)); + err = kill(child, SIGKILL); - DO_LOCK (); - - if (SUB_REF () == 0) - { - (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); - (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); - } + do { + result = waitpid(child, NULL, 0); + } while (result == (pid_t)-1 && errno == EINTR); - 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 -#include -#include -#include -#include -#include -#include -#include -#include - - -#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); - - DO_LOCK (); - if (ADD_REF () == 0) - { - if (__sigaction (SIGINT, &sa, &intr) < 0) - { - SUB_REF (); + sigemptyset (&sa.sa_mask); + + 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; - - /* 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 (); - - /* Exec the shell. */ - (void) __execve (SHELL_PATH, (char *const *) new_argv, __environ); - _exit (127); - } - else if (pid < (pid_t) 0) + 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); + + { 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); + return do_system (line); +} + +static void * +other_thread(void *dat) +{ + const char * s = (const char *)dat; +fprintf(stderr, "*** %s(%p)\n", __FUNCTION__, dat); + return ((void *) system(s)); +} - int oldtype = LIBC_CANCEL_ASYNC (); +int main(int argc, char *argv[]) +{ + pthread_t pth; - int result = do_system (line); + pthread_create(&pth, NULL, other_thread, "/bin/pwd" ); - LIBC_CANCEL_RESET (oldtype); + pthread_join(pth, NULL); - return result; + return 0; } -weak_alias (__libc_system, system) + -- 2.7.4