Logo Search packages:      
Sourcecode: hexec version File versions  Download package

hexec.c

/***************************************************************************
 *   Copyright (C) 2008 by Alexander Block                                 *
 *   ablock@blocksoftware.net                                              *
 *                                                                         *
 *   This program 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.                                   *
 *                                                                         *
 *   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         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "config.h"

#include "hexec.h"
#include "parser.h"
#include "common/error.h"
#include "common/args.h"
#include "common/shm.h"
#include "common/buf.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <stdbool.h>

#include <sys/wait.h>
#include <sys/mman.h>
#include <pthread.h>

void print_version()
{
    fprintf(stderr, "%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
}

void print_copyright()
{
    print_version();
    fprintf(stderr, "Copyright 2008 (c) by Alexander Block\n");
}

void print_usage(const char* msg, bool do_exit)
{
    if(msg)
        fprintf(stderr, "%s\n", msg);
    fprintf(stderr, "Usage: hexec <expr> cmd [args...]\n");
    fprintf(stderr, "Use 'man hexec' to get a detailed documentation\n");
    if(do_exit)
        exit(EXIT_FAILURE);
}

static void append_env(const char* var, const char* value)
{
    char* orig_value = getenv(var);
    if(!orig_value)
    {
        setenv(var, value, 1);
    }
    else
    {
        char* new_value = malloc(strlen(orig_value) + strlen(value) + 2);
        strcpy(new_value, orig_value);
        strcat(new_value, " ");
        strcat(new_value, value);
        setenv(var, new_value, 1);
        free(new_value);
    }
}

bool parse_opt(int argc, char** argv, int* cur_arg, char* name, bool needs_value, char** value)
{
    if(*cur_arg >= argc)
        return false;
    size_t arg_len = strlen(argv[*cur_arg]);
    size_t name_len = strlen(name);

    if(!strncmp(argv[*cur_arg], name, name_len))
    {
        if(needs_value)
        {
            if(arg_len > name_len)
            {
                *value = argv[*cur_arg] + name_len;
                *cur_arg += 1;
                return true;
            }
            else
            {
                if(*cur_arg + 1 >= argc)
                {
                    print_usage("missing value for argument", true);
                }
                
                *value = argv[*cur_arg + 1];
                *cur_arg += 2;
                return true;
            }
        }
        else
        {
            if(arg_len != name_len)
                return false;
            *cur_arg += 1;
            return true;
        }
    }
    return false;
}

void make_shm_name(char* name)
{
    sprintf(name, "/hexec-shm-%d", getpid());
}

void sig_handler(int signum)
{
    char shm_name[128];
    make_shm_name(shm_name);
    hexec_log("Received interrupt. Removing shm object '%s'\n", shm_name);
    shm_unlink(shm_name);
    exit(EXIT_FAILURE);
}

int main(int argc, char** argv)
{
    int err;
    char shm_name[128];
    char* log_out = NULL;
    struct hexec_buf buf;
    struct hexec_shm shm;
    struct hexec_parser parser;
    struct args_t args;
    int cur_arg = 1;

    /* init interrupt signal. We need to avoid shared
       memory leaks when the hexec main process is 
       cancelled. */
    struct sigaction act;
    memset(&act, 0, sizeof(act));
    act.sa_handler = sig_handler;
    sigaction(SIGINT, &act, NULL);

    if (argc == 1)
    {
        print_copyright();
        print_usage("\nno arguments given\n", true);
    }

    hexec_open_log_fd("/dev/stderr");
    
    while(true)
    {
        char* value;
        if(parse_opt(argc, argv, &cur_arg, "-h", false, &value) ||
           parse_opt(argc, argv, &cur_arg, "--help", false, &value))
        {
            print_copyright();
            fprintf(stderr, "\n");
            print_usage(NULL, true);
        }
        else if(parse_opt(argc, argv, &cur_arg, "-v", false, &value) ||
                parse_opt(argc, argv, &cur_arg, "--version", false, &value))
        {
            print_version();
            exit(0);
        }
        else if(parse_opt(argc, argv, &cur_arg, "-lo", true, &value) ||
                parse_opt(argc, argv, &cur_arg, "--log-out", true, &value))
        {
            log_out = value;
        }
        else
            break;
    }
    int first_expr_arg = cur_arg;

    /* init parser */
    hexec_args_from_array(&args, argv);
    hexec_buf_create(&buf);
    hexec_parser_init(&parser, &buf, &args, first_expr_arg);

    if(hexec_parser_parse(&parser))
        print_usage("parsing of expression failed\n", true);
    if(parser.result == -1)
        print_usage("missing expression\n", true);

    if(parser.cur_arg >= argc)
        print_usage("missing command\n", true);

    make_shm_name(shm_name);
    hexec_log("shm_name: %s\n", shm_name);

    /* create the shared memory object and copy the 
       the expression into the shm buffer */
    err = hexec_shm_create(&shm, shm_name, &buf);
    if(err)
        hexec_fatal("failed to create shared memory object\n");

    /* now fork the current process and exec into the 
       original command inside the child process. We
       need to do this to keep control over our shared
       memory object */
    int pid = fork();
    if(pid == -1)
        hexec_fatal("failed to fork process\n");
    if(pid == 0)
    {
        /* set LD_PRELOAD so that our hooking library 
           is called. Also set HEXEC_EXPR_SHM to the 
           name of the shared memory object, so that
           the hook library can use it.*/
        append_env("LD_PRELOAD", HEXEC_LIBHOOK);
        setenv("HEXEC_EXPR_SHM", shm_name, 1);
        if(log_out)
        {
            hexec_open_log_fd(log_out);
        }
        char tmp[16];
        sprintf(tmp, "%d", log_out_fd);
        setenv("HEXEC_LOG_FD", tmp, 1);
        
        //hexec_log("%s\n", args.argv[parser.cur_arg]);
        int err = execvp(args.argv[parser.cur_arg], args.argv + parser.cur_arg);
        hexec_error("failed to call command\n");
        exit(errno);
    }

    int status;
    if (waitpid(pid, &status, 0) != pid) 
    {
        hexec_shm_close(&shm);
        hexec_fatal("waitpid failed\n");
    }

    hexec_shm_close(&shm);

    if (WEXITSTATUS(status) == 0 && WIFSIGNALED(status)) 
    {
        return -1;
    }
    else
    {
        return WEXITSTATUS(status);
    }
}


Generated by  Doxygen 1.6.0   Back to index