diff options
Diffstat (limited to 'makewrappers')
-rwxr-xr-x | makewrappers | 429 |
1 files changed, 429 insertions, 0 deletions
diff --git a/makewrappers b/makewrappers new file mode 100755 index 0000000..11ef407 --- /dev/null +++ b/makewrappers @@ -0,0 +1,429 @@ +#!/bin/sh +# +# makewrappers, script to auto-generate wrapper functions +# +# Copyright (c) 2008-2010 Wind River Systems, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the Lesser GNU General Public License version 2.1 as +# published by the Free Software Foundation. +# +# This program 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 Lesser GNU General Public License for more details. +# +# You should have received a copy of the Lesser GNU General Public License +# version 2.1 along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +case $# in +0) echo >&2 "Usage: makewrappers file [...]" + exit 1 + ;; +esac + +# save old versions +test -f "pseudo_wrappers.c" && mv pseudo_wrappers.c pseudo_wrappers.c.old +test -f "pseudo_wrappers.h" && mv pseudo_wrappers.h pseudo_wrappers.h.old + +# create files +exec 5>pseudo_wrappers.c +exec 6>pseudo_wrappers.h +exec 7>pseudo_wrapper_table.c + +# "cat >&N <<EOF" populates the file on &N with the here-document. + +# pseudo_wrappers.c has to have all the hunks used by the wrapper functions, +# including guts/*.c. +cat >&5 <<EOF +`cat guts/COPYRIGHT` +/* wrapper functions. generated automatically. */ + +/* This file is generated and should not be modified. See the makewrappers + * script if you want to modify this. */ + +#include <stdlib.h> +#include <limits.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <pthread.h> + +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <dlfcn.h> + +#include "pseudo.h" +#include "pseudo_wrappers.h" +#include "pseudo_ipc.h" +#include "pseudo_client.h" + +static void pseudo_enosys(const char *); +static int pseudo_populate_wrappers(void); +static volatile int antimagic = 0; +static pthread_mutex_t pseudo_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_t pseudo_mutex_holder; +static int pseudo_mutex_recursion = 0; + +int +pseudo_getlock() { + if (pthread_equal(pseudo_mutex_holder, pthread_self())) { + ++pseudo_mutex_recursion; + return 0; + } else { + if (pthread_mutex_lock(&pseudo_mutex) == 0) { + pseudo_mutex_recursion = 1; + pseudo_mutex_holder = pthread_self(); + return 0; + } else { + return -1; + } + } +} + +void +pseudo_droplock() { + if (--pseudo_mutex_recursion == 0) { + pseudo_mutex_holder = 0; + pthread_mutex_unlock(&pseudo_mutex); + } +} + +void +pseudo_antimagic() { + ++antimagic; +} + +void +pseudo_magic() { + if (antimagic > 0) + --antimagic; +} + +EOF + +cat >&6 <<EOF +`cat guts/COPYRIGHT` +EOF + +# the wrapper function table is also #included, it is a separate file so it +# can be written as we go, but still be a single table. +cat >&7 <<EOF +`cat guts/COPYRIGHT` +/* The table of wrapper functions to populate */ + +/* This file is generated and should not be modified. See the makewrappers + * script if you want to modify this. */ +static struct { + char *name; /* the name */ + int (**real)(void); /* the underlying syscall */ + int (*dummy)(void); /* the always-fails form */ + int (*wrapper)(void); /* the wrapper from guts/name.c */ +} pseudo_functions[] = { +EOF + +printf >&2 'Reading signatures...\n' +for file in "$@" +do + # read lines containing wrappable functions, write wrapper + # declarations, definitions, and so on. + printf >&2 '[%s]' "$file" + while read signature + do + # skip comments + case $signature in + \#*) continue;; + esac + # obtain return type, name, and arguments + args=`expr "$signature" : '.*(\(.*\));'` + return_and_name=`expr "$signature" : '\(.*\)('` + name=`expr "$return_and_name" : '.*[^a-zA-Z0-9_]\([a-zA-Z0-9_]*\)$'` + type=`expr "$return_and_name" : '\(.*[^ ]\) *'"$name"'$'` + printf >&2 ' %s' "$name" + argnames='' + save_IFS=$IFS + IFS=, + set -- $args + IFS=$save_ifs + args='' + optional_arg=false + for arg + do + # strip whitespace + arg=${arg# } + arg=${arg% } + + # handle optional arguments, like the third arg + # to open() + case $arg in + ...*) + optional_arg=true + args="$args${args:+, }..." + arg=`expr "$arg" : '\.\.\.{\(.*\)}'` + argname=`expr "$arg" : '.*[^a-zA-Z0-9_]\([a-zA-Z0-9_]*\)$'` + argnames="$argnames${argnames:+, }$argname" + + # we need this to extract and pass the argument + optional_decl=$arg + optional_prev=$prev_argname + optional_name=$argname + optional_type=`expr "$arg" : '\(.*[^ ]\) *'"$argname"'$'` + ;; + *) + argname=`expr "$arg" : '.*[^a-zA-Z0-9_]\([a-zA-Z0-9_]*\)$'` + args="$args${args:+, }$arg" + argnames="$argnames${argnames:+, }$argname" + prev_argname=$argname + ;; + esac + done + + # determine default return value. + case $type in + int) + default_value=-1;; + uid_t|gid_t) + default_value=0;; + 'FILE *') + default_value=NULL;; + *) echo >&2 "Unknown type '$type'." ; exit 1 ;; + esac + # create the wrappers + # first the dummy, and the function pointer: + cat >&5 <<EOF +static $type +dummy_$name($args) { + pseudo_enosys("$name"); + errno = ENOSYS; + return $default_value; +} + +static $type (*real_$name)($args) = dummy_$name; + +EOF + # then the wrapper signature and args: + if $optional_arg; then + cat >&5 <<EOF +$type +$name($args) { + $optional_decl; + va_list ap; + va_start(ap, $optional_prev); + $optional_name = va_arg(ap, $optional_type); + va_end(ap); + +EOF + else + cat >&5 <<EOF +$type +$name($args) { +EOF + fi + # and now the body of the wrapper: + cat >&5 <<EOF + if (pseudo_getlock()) { + errno = EBUSY; + return $default_value; + } + if (pseudo_populate_wrappers()) { + $type rc = $default_value; + int save_errno; + if (antimagic > 0) { + if (real_$name) { + rc = (*real_$name)($argnames); + } else { + rc = dummy_$name($argnames); + } + } else { + rc = wrap_$name($argnames); + } + save_errno = errno; + pseudo_droplock(); + errno = save_errno; + return rc; + } else { + pseudo_droplock(); + return dummy_$name($argnames); + } +} + +EOF + # and now the signature part for the actual implementation: + # and the guts include file. + + # the wrapper function is actually declared in + # pseudo_wrapper.c, with guts implemented in a separate + # file with comments indicating the signature. + guts="guts/$name.c" + + # the actual wrapper function, including argument setup + if $optional_arg; then + cat >&5 << EOF +static $type +wrap_$name($args) { + $type rc = $default_value; + $optional_decl; + + va_list ap; + va_start(ap, $optional_prev); + $optional_name = va_arg(ap, $optional_type); + va_end(ap); + +#include "$guts" + + return rc; +} +EOF + else + cat >&5 << EOF +static $type +wrap_$name($args) { + $type rc = $default_value; + +#include "$guts" + + return rc; +} +EOF + fi + + # if the guts file didn't already exist, create a default. + if test ! -f "$guts"; then + if $optional_arg; then + cat > "$guts" <<EOF +/* + * static $type + * wrap_$name($args$optional_decl) { + * $type rc = $default_value; + */ + + rc = real_$name($argnames); + +/* return rc; + * } + */ +EOF + else + cat > "$guts" <<EOF +/* + * static $type + * wrap_$name($args) { + * $type rc = $default_value; + */ + + rc = real_$name($argnames); + +/* return rc; + * } + */ +EOF + fi + fi + # prototypes for pseudo_wrappers.h + cat >&6 <<EOF +/* $type $name($args); */ +static $type dummy_$name($args); +static $type wrap_$name($args); +static $type (*real_$name)($args); + +EOF + + # and entries in the Big Table + cat >&7 <<EOF + { /* $type $name($args); */ + "$name", + (int (**)(void)) &real_$name, + (int (*)(void)) dummy_$name, + (int (*)(void)) wrap_$name + }, +EOF + done < $file +done +printf >&2 '.\n' + +# sentinel values +cat >&7 <<EOF + { NULL, NULL, NULL, NULL }, +}; +EOF + +# and now the actual populate_wrappers function. +cat >&5 <<EOF +#include "pseudo_wrapper_table.c" + +extern char *program_invocation_short_name; + +static void +pseudo_enosys(const char *func) { + pseudo_diag("pseudo: ENOSYS for '%s'.\n", func ? func : "<nil>"); + if (getenv("PSEUDO_ENOSYS_ABORT")) + abort(); +} + +static int +pseudo_populate_wrappers(void) { + int i; + char *debug; + static int done = 0; + char *pseudo_path = 0; + + if (done) + return done; + pseudo_getlock(); + pseudo_antimagic(); + for (i = 0; pseudo_functions[i].name; ++i) { + if (*pseudo_functions[i].real == pseudo_functions[i].dummy) { + int (*f)(void); + char *e; + dlerror(); + f = dlsym(RTLD_NEXT, pseudo_functions[i].name); + if ((e = dlerror()) != NULL) { + /* leave it pointed to dummy */ + pseudo_diag("No wrapper for %s: %s\n", pseudo_functions[i].name, e); + } else { + if (f) + *pseudo_functions[i].real = f; + } + } + } + done = 1; + debug = getenv("PSEUDO_DEBUG"); + if (debug) { + int level = atoi(debug); + for (i = 0; i < level; ++i) { + pseudo_debug_verbose(); + } + } + /* must happen after wrappers are set up, because it can call + * getcwd(), which needs wrappers, but must happen here so that + * any attempt to use a path in a wrapper function will have a + * value for cwd. + */ + pseudo_client_reset(); + pseudo_path = pseudo_prefix_path(NULL); + if (pseudo_dir_fd == -1) { + if (pseudo_path) { + pseudo_dir_fd = open(pseudo_path, O_RDONLY); + pseudo_dir_fd = pseudo_fd(pseudo_dir_fd, MOVE_FD); + free(pseudo_path); + } else { + pseudo_diag("No prefix available to to find server.\n"); + exit(1); + } + if (pseudo_dir_fd == -1) { + pseudo_diag("Can't open prefix path (%s) for server.\n", + strerror(errno)); + exit(1); + } + } + pseudo_debug(2, "(%s) set up wrappers\n", program_invocation_short_name); + pseudo_magic(); + pseudo_droplock(); + return done; +} +EOF |