<commit_before>/*
 * Wrapper for a socket descriptor with (optional) filter for input
 * and output.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef BENG_PROXY_FILTERED_SOCKET_HXX
#define BENG_PROXY_FILTERED_SOCKET_HXX

#include "buffered_socket.hxx"

#include <pthread.h>

struct fifo_buffer;
struct FilteredSocket;

struct SocketFilter {
    void (*init)(FilteredSocket &s, void *ctx);

    /**
     * Data has been read from the socket into the input buffer.  Call
     * filtered_socket_internal_consumed() each time you consume data
     * from the given buffer.
     */
    BufferedResult (*data)(const void *buffer, size_t size, void *ctx);

    bool (*is_empty)(void *ctx);

    bool (*is_full)(void *ctx);

    size_t (*available)(void *ctx);

    void (*consumed)(size_t nbytes, void *ctx);

    /**
     * The client asks to read more data.  The filter shall call
     * filtered_socket_internal_data() again.
     */
    bool (*read)(bool expect_more, void *ctx);

    /**
     * The client asks to write data to the socket.  The filter
     * processes it, and may then call
     * filtered_socket_internal_write().
     */
    ssize_t (*write)(const void *data, size_t length, void *ctx);

    /**
     * The client is willing to read, but does not expect it yet.  The
     * filter processes the call, and may then call
     * filtered_socket_internal_schedule_read().
     */
    void (*schedule_read)(bool expect_more, const struct timeval *timeout,
                          void *ctx);

    /**
     * The client wants to be called back as soon as writing becomes
     * possible.  The filter processes the call, and may then call
     * filtered_socket_internal_schedule_write().
     */
    void (*schedule_write)(void *ctx);

    /**
     * The client is not anymore interested in writing.  The filter
     * processes the call, and may then call
     * filtered_socket_internal_unschedule_write().
     */
    void (*unschedule_write)(void *ctx);

    /**
     * The underlying socket is ready for writing.  The filter may try
     * calling filtered_socket_internal_write() again.
     *
     * This method must not destroy the socket.  If an error occurs,
     * it shall return false.
     */
    bool (*internal_write)(void *ctx);

    /**
     * Called after the socket has been closed/abandoned (either by
     * the peer or locally).  The filter shall update its internal
     * state, but not do any invasive actions.
     */
    void (*closed)(void *ctx);

    bool (*remaining)(size_t remaining, void *ctx);

    /**
     * The buffered_socket has run empty after the socket has been
     * closed.  The filter may call filtered_socket_invoke_end() as
     * soon as all its buffers have been consumed.
     */
    void (*end)(void *ctx);

    void (*close)(void *ctx);
};

class SocketFilterFactory {
public:
    virtual void *CreateFilter(GError **error_r) = 0;
};

/**
 * A wrapper for #buffered_socket that can filter input and output.
 */
struct FilteredSocket {
    BufferedSocket base;

#ifndef NDEBUG
    bool ended;
#endif

    /**
     * The actual filter.  If this is nullptr, then this object behaves
     * just like #buffered_socket.
     */
    const SocketFilter *filter;
    void *filter_ctx;

    const BufferedSocketHandler *handler;
    void *handler_ctx;

    /**
     * Is there still data in the filter's output?  Once this turns
     * from "false" to "true", the #buffered_socket_handler method
     * drained() will be invoked.
     */
    bool drained;

    void Init(struct pool &pool,
              int fd, FdType fd_type,
              const struct timeval *read_timeout,
              const struct timeval *write_timeout,
              const SocketFilter *filter, void *filter_ctx,
              const BufferedSocketHandler &handler, void *handler_ctx);

    void Reinit(const struct timeval *read_timeout,
                const struct timeval *write_timeout,
                const BufferedSocketHandler &handler, void *handler_ctx);

    /**
     * Move the socket from another #BufferedSocket instance.  This
     * disables scheduled events, moves the input buffer and the
     * filter to this instance and installs a new handler.
     */
    void Init(struct pool &pool,
              FilteredSocket &&src,
              const struct timeval *read_timeout,
              const struct timeval *write_timeout,
              const BufferedSocketHandler &handler, void *handler_ctx);

    bool HasFilter() const {
        return filter != nullptr;
    }

    FdType GetType() const {
        return filter == nullptr
            ? base.GetType()
            /* can't do splice() with a filter */
            : FdType::FD_NONE;
    }

    void Shutdown() {
        base.Shutdown();
    }

    /**
     * Close the physical socket, but do not destroy the input buffer.  To
     * do the latter, call filtered_socket_destroy().
     */
    void Close() {
        if (filter != nullptr && filter->closed != nullptr)
            filter->closed(filter_ctx);

#ifndef NDEBUG
        /* work around bogus assertion failure */
        if (filter != nullptr && base.HasEnded())
            return;
#endif

        base.Close();
    }

    /**
     * Just like Close(), but do not actually close the
     * socket.  The caller is responsible for closing the socket (or
     * scheduling it for reuse).
     */
    void Abandon() {
        if (filter != nullptr && filter->closed != nullptr)
            filter->closed(filter_ctx);

#ifndef NDEBUG
        /* work around bogus assertion failure */
        if (filter != nullptr && base.HasEnded())
            return;
#endif

        base.Abandon();
    }

    /**
     * Destroy the object.  Prior to that, the socket must be removed
     * by calling either filtered_socket_close() or
     * filtered_socket_abandon().
     */
    void Destroy();

    /**
     * Returns the socket descriptor and calls Abandon().  Returns -1
     * if the input buffer is not empty.
     */
    int AsFD() {
        return filter != nullptr
            ? -1
            : base.AsFD();
    }

    /**
     * Is the socket still connected?  This does not actually check
     * whether the socket is connected, just whether it is known to be
     * closed.
     */
    bool IsConnected() const {
#ifndef NDEBUG
        /* work around bogus assertion failure */
        if (filter != nullptr && base.HasEnded())
            return false;
#endif

        return base.IsConnected();
    }

    /**
     * Is the object still usable?  The socket may be closed already, but
     * the input buffer may still have data.
     */
    bool IsValid() const {
        return base.IsValid();
    }

    /**
     * Accessor for #drained.
     */
    bool IsDrained() const {
        assert(IsValid());

        return drained;
    }

    /**
     * Is the input buffer empty?
     */
    gcc_pure
    bool IsEmpty() const;

    /**
     * Is the input buffer full?
     */
    gcc_pure
    bool IsFull() const;

    /**
     * Returns the number of bytes in the input buffer.
     */
    gcc_pure
    size_t GetAvailable() const;

    /**
     * Mark the specified number of bytes of the input buffer as
     * "consumed".  Call this in the data() method.  Note that this
     * method does not invalidate the buffer passed to data().  It may
     * be called repeatedly.
     */
    void Consumed(size_t nbytes);

    /**
     * Returns the istream_direct mask for splicing data into this socket.
     */
    FdTypeMask GetDirectMask() const {
        return filter != nullptr
            ? FdType::FD_NONE
            : base.GetDirectMask();
    }

    /**
     * The caller wants to read more data from the socket.  There are
     * four possible outcomes: a call to filtered_socket_handler.read,
     * a call to filtered_socket_handler.direct, a call to
     * filtered_socket_handler.error or (if there is no data available
     * yet) an event gets scheduled and the function returns
     * immediately.
     */
    bool Read(bool expect_more);

    void SetCork(bool cork) {
        base.SetCork(cork);
    }

    ssize_t Write(const void *data, size_t length);

    ssize_t WriteFrom(int fd, FdType fd_type, size_t length) {
        assert(filter == nullptr);

        return base.WriteFrom(fd, fd_type, length);
    }

    gcc_pure
    bool IsReadyForWriting() const {
        assert(filter == nullptr);

        return base.IsReadyForWriting();
    }

    void ScheduleReadTimeout(bool expect_more, const struct timeval *timeout) {
        if (filter != nullptr && filter->schedule_read != nullptr)
            filter->schedule_read(expect_more, timeout, filter_ctx);
        else
            base.ScheduleReadTimeout(expect_more, timeout);
    }

    /**
     * Schedules reading on the socket with timeout disabled, to indicate
     * that you are willing to read, but do not expect it yet.  No direct
     * action is taken.  Use this to enable reading when you are still
     * sending the request.  When you are finished sending the request,
     * you should call filtered_socket_read() to enable the read timeout.
     */
    void ScheduleReadNoTimeout(bool expect_more) {
        ScheduleReadTimeout(expect_more, nullptr);
    }

    void ScheduleWrite() {
        if (filter != nullptr && filter->schedule_write != nullptr)
            filter->schedule_write(filter_ctx);
        else
            base.ScheduleWrite();
    }

    void UnscheduleWrite() {
        if (filter != nullptr && filter->unschedule_write != nullptr)
            filter->unschedule_write(filter_ctx);
        else
            base.UnscheduleWrite();
    }

    gcc_pure
    bool InternalIsEmpty() const {
        assert(filter != nullptr);

        return base.IsEmpty();
    }

    gcc_pure
    bool InternalIsFull() const {
        assert(filter != nullptr);

        return base.IsFull();
    }

    gcc_pure
    size_t InternalGetAvailable() const {
        assert(filter != nullptr);

        return base.GetAvailable();
    }

    void InternalConsumed(size_t nbytes)
    {
        assert(filter != nullptr);

        base.Consumed(nbytes);
    }

    bool InternalRead(bool expect_more) {
        assert(filter != nullptr);

        return base.Read(expect_more);
    }

    ssize_t InternalWrite(const void *data, size_t length) {
        assert(filter != nullptr);

        return base.Write(data, length);
    }

    /**
     * A #SocketFilter must call this function whenever it adds data to
     * its output buffer (only if it implements such a buffer).
     */
    void InternalUndrained() {
        assert(filter != nullptr);
        assert(IsConnected());

        drained = false;
    }

    /**
     * A #SocketFilter must call this function whenever its output buffer
     * drains (only if it implements such a buffer).
     */
    bool InternalDrained();

    void InternalScheduleRead(bool expect_more,
                              const struct timeval *timeout) {
        assert(filter != nullptr);

        base.ScheduleReadTimeout(expect_more, timeout);
    }

    void InternalScheduleWrite() {
        assert(filter != nullptr);

        base.ScheduleWrite();
    }

    void InternalUnscheduleWrite() {
        assert(filter != nullptr);

        base.UnscheduleWrite();
    }

    BufferedResult InvokeData(const void *data, size_t size) {
        assert(filter != nullptr);

        return handler->data(data, size, handler_ctx);
    }

    bool InvokeClosed() {
        assert(filter != nullptr);

        return handler->closed(handler_ctx);
    }

    bool InvokeRemaining(size_t remaining) {
        assert(filter != nullptr);

        return handler->remaining == nullptr ||
            handler->remaining(remaining, handler_ctx);
    }

    void InvokeEnd() {
        assert(filter != nullptr);
        assert(!ended);
        assert(base.HasEnded());

#ifndef NDEBUG
        ended = true;
#endif

        if (handler->end != nullptr)
            handler->end(handler_ctx);
    }

    bool InvokeWrite() {
        assert(filter != nullptr);

        return handler->write(handler_ctx);
    }

    bool InvokeTimeout() {
        assert(filter != nullptr);

        return handler->timeout(handler_ctx);
    }

    void InvokeError(GError *error) {
        assert(filter != nullptr);

        handler->error(error, handler_ctx);
    }
};

#endif
<commit_msg>filtered_socket: work around assertion failure in BufferedSocket::TryRead2()<commit_after>/*
 * Wrapper for a socket descriptor with (optional) filter for input
 * and output.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef BENG_PROXY_FILTERED_SOCKET_HXX
#define BENG_PROXY_FILTERED_SOCKET_HXX

#include "buffered_socket.hxx"

#include <pthread.h>

struct fifo_buffer;
struct FilteredSocket;

struct SocketFilter {
    void (*init)(FilteredSocket &s, void *ctx);

    /**
     * Data has been read from the socket into the input buffer.  Call
     * filtered_socket_internal_consumed() each time you consume data
     * from the given buffer.
     */
    BufferedResult (*data)(const void *buffer, size_t size, void *ctx);

    bool (*is_empty)(void *ctx);

    bool (*is_full)(void *ctx);

    size_t (*available)(void *ctx);

    void (*consumed)(size_t nbytes, void *ctx);

    /**
     * The client asks to read more data.  The filter shall call
     * filtered_socket_internal_data() again.
     */
    bool (*read)(bool expect_more, void *ctx);

    /**
     * The client asks to write data to the socket.  The filter
     * processes it, and may then call
     * filtered_socket_internal_write().
     */
    ssize_t (*write)(const void *data, size_t length, void *ctx);

    /**
     * The client is willing to read, but does not expect it yet.  The
     * filter processes the call, and may then call
     * filtered_socket_internal_schedule_read().
     */
    void (*schedule_read)(bool expect_more, const struct timeval *timeout,
                          void *ctx);

    /**
     * The client wants to be called back as soon as writing becomes
     * possible.  The filter processes the call, and may then call
     * filtered_socket_internal_schedule_write().
     */
    void (*schedule_write)(void *ctx);

    /**
     * The client is not anymore interested in writing.  The filter
     * processes the call, and may then call
     * filtered_socket_internal_unschedule_write().
     */
    void (*unschedule_write)(void *ctx);

    /**
     * The underlying socket is ready for writing.  The filter may try
     * calling filtered_socket_internal_write() again.
     *
     * This method must not destroy the socket.  If an error occurs,
     * it shall return false.
     */
    bool (*internal_write)(void *ctx);

    /**
     * Called after the socket has been closed/abandoned (either by
     * the peer or locally).  The filter shall update its internal
     * state, but not do any invasive actions.
     */
    void (*closed)(void *ctx);

    bool (*remaining)(size_t remaining, void *ctx);

    /**
     * The buffered_socket has run empty after the socket has been
     * closed.  The filter may call filtered_socket_invoke_end() as
     * soon as all its buffers have been consumed.
     */
    void (*end)(void *ctx);

    void (*close)(void *ctx);
};

class SocketFilterFactory {
public:
    virtual void *CreateFilter(GError **error_r) = 0;
};

/**
 * A wrapper for #buffered_socket that can filter input and output.
 */
struct FilteredSocket {
    BufferedSocket base;

#ifndef NDEBUG
    bool ended;
#endif

    /**
     * The actual filter.  If this is nullptr, then this object behaves
     * just like #buffered_socket.
     */
    const SocketFilter *filter;
    void *filter_ctx;

    const BufferedSocketHandler *handler;
    void *handler_ctx;

    /**
     * Is there still data in the filter's output?  Once this turns
     * from "false" to "true", the #buffered_socket_handler method
     * drained() will be invoked.
     */
    bool drained;

    void Init(struct pool &pool,
              int fd, FdType fd_type,
              const struct timeval *read_timeout,
              const struct timeval *write_timeout,
              const SocketFilter *filter, void *filter_ctx,
              const BufferedSocketHandler &handler, void *handler_ctx);

    void Reinit(const struct timeval *read_timeout,
                const struct timeval *write_timeout,
                const BufferedSocketHandler &handler, void *handler_ctx);

    /**
     * Move the socket from another #BufferedSocket instance.  This
     * disables scheduled events, moves the input buffer and the
     * filter to this instance and installs a new handler.
     */
    void Init(struct pool &pool,
              FilteredSocket &&src,
              const struct timeval *read_timeout,
              const struct timeval *write_timeout,
              const BufferedSocketHandler &handler, void *handler_ctx);

    bool HasFilter() const {
        return filter != nullptr;
    }

    FdType GetType() const {
        return filter == nullptr
            ? base.GetType()
            /* can't do splice() with a filter */
            : FdType::FD_NONE;
    }

    void Shutdown() {
        base.Shutdown();
    }

    /**
     * Close the physical socket, but do not destroy the input buffer.  To
     * do the latter, call filtered_socket_destroy().
     */
    void Close() {
        if (filter != nullptr && filter->closed != nullptr)
            filter->closed(filter_ctx);

#ifndef NDEBUG
        /* work around bogus assertion failure */
        if (filter != nullptr && base.HasEnded())
            return;
#endif

        base.Close();
    }

    /**
     * Just like Close(), but do not actually close the
     * socket.  The caller is responsible for closing the socket (or
     * scheduling it for reuse).
     */
    void Abandon() {
        if (filter != nullptr && filter->closed != nullptr)
            filter->closed(filter_ctx);

#ifndef NDEBUG
        /* work around bogus assertion failure */
        if (filter != nullptr && base.HasEnded())
            return;
#endif

        base.Abandon();
    }

    /**
     * Destroy the object.  Prior to that, the socket must be removed
     * by calling either filtered_socket_close() or
     * filtered_socket_abandon().
     */
    void Destroy();

    /**
     * Returns the socket descriptor and calls Abandon().  Returns -1
     * if the input buffer is not empty.
     */
    int AsFD() {
        return filter != nullptr
            ? -1
            : base.AsFD();
    }

    /**
     * Is the socket still connected?  This does not actually check
     * whether the socket is connected, just whether it is known to be
     * closed.
     */
    bool IsConnected() const {
#ifndef NDEBUG
        /* work around bogus assertion failure */
        if (filter != nullptr && base.HasEnded())
            return false;
#endif

        return base.IsConnected();
    }

    /**
     * Is the object still usable?  The socket may be closed already, but
     * the input buffer may still have data.
     */
    bool IsValid() const {
        return base.IsValid();
    }

    /**
     * Accessor for #drained.
     */
    bool IsDrained() const {
        assert(IsValid());

        return drained;
    }

    /**
     * Is the input buffer empty?
     */
    gcc_pure
    bool IsEmpty() const;

    /**
     * Is the input buffer full?
     */
    gcc_pure
    bool IsFull() const;

    /**
     * Returns the number of bytes in the input buffer.
     */
    gcc_pure
    size_t GetAvailable() const;

    /**
     * Mark the specified number of bytes of the input buffer as
     * "consumed".  Call this in the data() method.  Note that this
     * method does not invalidate the buffer passed to data().  It may
     * be called repeatedly.
     */
    void Consumed(size_t nbytes);

    /**
     * Returns the istream_direct mask for splicing data into this socket.
     */
    FdTypeMask GetDirectMask() const {
        return filter != nullptr
            ? FdType::FD_NONE
            : base.GetDirectMask();
    }

    /**
     * The caller wants to read more data from the socket.  There are
     * four possible outcomes: a call to filtered_socket_handler.read,
     * a call to filtered_socket_handler.direct, a call to
     * filtered_socket_handler.error or (if there is no data available
     * yet) an event gets scheduled and the function returns
     * immediately.
     */
    bool Read(bool expect_more);

    void SetCork(bool cork) {
        base.SetCork(cork);
    }

    ssize_t Write(const void *data, size_t length);

    ssize_t WriteFrom(int fd, FdType fd_type, size_t length) {
        assert(filter == nullptr);

        return base.WriteFrom(fd, fd_type, length);
    }

    gcc_pure
    bool IsReadyForWriting() const {
        assert(filter == nullptr);

        return base.IsReadyForWriting();
    }

    void ScheduleReadTimeout(bool expect_more, const struct timeval *timeout) {
        if (filter != nullptr && filter->schedule_read != nullptr)
            filter->schedule_read(expect_more, timeout, filter_ctx);
        else
            base.ScheduleReadTimeout(expect_more, timeout);
    }

    /**
     * Schedules reading on the socket with timeout disabled, to indicate
     * that you are willing to read, but do not expect it yet.  No direct
     * action is taken.  Use this to enable reading when you are still
     * sending the request.  When you are finished sending the request,
     * you should call filtered_socket_read() to enable the read timeout.
     */
    void ScheduleReadNoTimeout(bool expect_more) {
        ScheduleReadTimeout(expect_more, nullptr);
    }

    void ScheduleWrite() {
        if (filter != nullptr && filter->schedule_write != nullptr)
            filter->schedule_write(filter_ctx);
        else
            base.ScheduleWrite();
    }

    void UnscheduleWrite() {
        if (filter != nullptr && filter->unschedule_write != nullptr)
            filter->unschedule_write(filter_ctx);
        else
            base.UnscheduleWrite();
    }

    gcc_pure
    bool InternalIsEmpty() const {
        assert(filter != nullptr);

        return base.IsEmpty();
    }

    gcc_pure
    bool InternalIsFull() const {
        assert(filter != nullptr);

        return base.IsFull();
    }

    gcc_pure
    size_t InternalGetAvailable() const {
        assert(filter != nullptr);

        return base.GetAvailable();
    }

    void InternalConsumed(size_t nbytes)
    {
        assert(filter != nullptr);

        base.Consumed(nbytes);
    }

    bool InternalRead(bool expect_more) {
        assert(filter != nullptr);

#ifndef NDEBUG
        if (!base.IsConnected() && base.GetAvailable() == 0)
            /* work around assertion failure in
               BufferedSocket::TryRead2() */
            return false;
#endif

        return base.Read(expect_more);
    }

    ssize_t InternalWrite(const void *data, size_t length) {
        assert(filter != nullptr);

        return base.Write(data, length);
    }

    /**
     * A #SocketFilter must call this function whenever it adds data to
     * its output buffer (only if it implements such a buffer).
     */
    void InternalUndrained() {
        assert(filter != nullptr);
        assert(IsConnected());

        drained = false;
    }

    /**
     * A #SocketFilter must call this function whenever its output buffer
     * drains (only if it implements such a buffer).
     */
    bool InternalDrained();

    void InternalScheduleRead(bool expect_more,
                              const struct timeval *timeout) {
        assert(filter != nullptr);

        base.ScheduleReadTimeout(expect_more, timeout);
    }

    void InternalScheduleWrite() {
        assert(filter != nullptr);

        base.ScheduleWrite();
    }

    void InternalUnscheduleWrite() {
        assert(filter != nullptr);

        base.UnscheduleWrite();
    }

    BufferedResult InvokeData(const void *data, size_t size) {
        assert(filter != nullptr);

        return handler->data(data, size, handler_ctx);
    }

    bool InvokeClosed() {
        assert(filter != nullptr);

        return handler->closed(handler_ctx);
    }

    bool InvokeRemaining(size_t remaining) {
        assert(filter != nullptr);

        return handler->remaining == nullptr ||
            handler->remaining(remaining, handler_ctx);
    }

    void InvokeEnd() {
        assert(filter != nullptr);
        assert(!ended);
        assert(base.HasEnded());

#ifndef NDEBUG
        ended = true;
#endif

        if (handler->end != nullptr)
            handler->end(handler_ctx);
    }

    bool InvokeWrite() {
        assert(filter != nullptr);

        return handler->write(handler_ctx);
    }

    bool InvokeTimeout() {
        assert(filter != nullptr);

        return handler->timeout(handler_ctx);
    }

    void InvokeError(GError *error) {
        assert(filter != nullptr);

        handler->error(error, handler_ctx);
    }
};

#endif
<|endoftext|>


<commit_before>//===---------------------------- cxa_guard.cpp ---------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "abort_message.h"
#include "config.h"

#if !LIBCXXABI_SINGLE_THREADED
#  include <pthread.h>
#endif
#include <stdint.h>

/*
    This implementation must be careful to not call code external to this file
    which will turn around and try to call __cxa_guard_acquire reentrantly.
    For this reason, the headers of this file are as restricted as possible.
    Previous implementations of this code for __APPLE__ have used
    pthread_mutex_lock and the abort_message utility without problem.  This
    implementation also uses pthread_cond_wait which has tested to not be a
    problem.
*/

namespace __cxxabiv1
{

namespace
{

#if __arm__

// A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must
// be statically initialized to 0.
typedef uint32_t guard_type;

// Test the lowest bit.
inline bool is_initialized(guard_type* guard_object) {
    return (*guard_object) & 1;
}

inline void set_initialized(guard_type* guard_object) {
    *guard_object |= 1;
}

#else

typedef uint64_t guard_type;

bool is_initialized(guard_type* guard_object) {
    char* initialized = (char*)guard_object;
    return *initialized;
}

void set_initialized(guard_type* guard_object) {
    char* initialized = (char*)guard_object;
    *initialized = 1;
}

#endif

#if !LIBCXXABI_SINGLE_THREADED
pthread_mutex_t guard_mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  guard_cv  = PTHREAD_COND_INITIALIZER;
#endif

#if defined(__APPLE__) && !defined(__arm__)

typedef uint32_t lock_type;

#if __LITTLE_ENDIAN__

inline
lock_type
get_lock(uint64_t x)
{
    return static_cast<lock_type>(x >> 32);
}

inline
void
set_lock(uint64_t& x, lock_type y)
{
    x = static_cast<uint64_t>(y) << 32;
}

#else  // __LITTLE_ENDIAN__

inline
lock_type
get_lock(uint64_t x)
{
    return static_cast<lock_type>(x);
}

inline
void
set_lock(uint64_t& x, lock_type y)
{
    x = y;
}

#endif  // __LITTLE_ENDIAN__

#else  // !__APPLE__ || __arm__

typedef bool lock_type;

inline
lock_type
get_lock(uint64_t x)
{
    union
    {
        uint64_t guard;
        uint8_t lock[2];
    } f = {x};
    return f.lock[1] != 0;
}

inline
void
set_lock(uint64_t& x, lock_type y)
{
    union
    {
        uint64_t guard;
        uint8_t lock[2];
    } f = {0};
    f.lock[1] = y;
    x = f.guard;
}

inline
lock_type
get_lock(uint32_t x)
{
    union
    {
        uint32_t guard;
        uint8_t lock[2];
    } f = {x};
    return f.lock[1] != 0;
}

inline
void
set_lock(uint32_t& x, lock_type y)
{
    union
    {
        uint32_t guard;
        uint8_t lock[2];
    } f = {0};
    f.lock[1] = y;
    x = f.guard;
}

#endif  // __APPLE__

}  // unnamed namespace

extern "C"
{

#if LIBCXXABI_SINGLE_THREADED
int __cxa_guard_acquire(guard_type* guard_object)
{
    return !is_initialized(guard_object);
}

void __cxa_guard_release(guard_type* guard_object)
{
    *guard_object = 0;
    set_initialized(guard_object);
}

void __cxa_guard_abort(guard_type* guard_object)
{
    *guard_object = 0;
}

#else // !LIBCXXABI_SINGLE_THREADED

int __cxa_guard_acquire(guard_type* guard_object)
{
    if (pthread_mutex_lock(&guard_mut))
        abort_message("__cxa_guard_acquire failed to acquire mutex");
    int result = *initialized == 0;
    if (result)
    {
#if defined(__APPLE__) && !defined(__arm__)
        const lock_type id = pthread_mach_thread_np(pthread_self());
        lock_type lock = get_lock(*guard_object);
        if (lock)
        {
            // if this thread set lock for this same guard_object, abort
            if (lock == id)
                abort_message("__cxa_guard_acquire detected deadlock");
            do
            {
                if (pthread_cond_wait(&guard_cv, &guard_mut))
                    abort_message("__cxa_guard_acquire condition variable wait failed");
                lock = get_lock(*guard_object);
            } while (lock);
            result = !is_initialized(guard_object);
            if (result)
                set_lock(*guard_object, id);
        }
        else
            set_lock(*guard_object, id);
#else  // !__APPLE__ || __arm__
        while (get_lock(*guard_object))
            if (pthread_cond_wait(&guard_cv, &guard_mut))
                abort_message("__cxa_guard_acquire condition variable wait failed");
        result = *initialized == 0;
        if (result)
            set_lock(*guard_object, true);
#endif  // !__APPLE__ || __arm__
    }
    if (pthread_mutex_unlock(&guard_mut))
        abort_message("__cxa_guard_acquire failed to release mutex");
    return result;
}

void __cxa_guard_release(guard_type* guard_object)
{
    if (pthread_mutex_lock(&guard_mut))
        abort_message("__cxa_guard_release failed to acquire mutex");
    *guard_object = 0;
    set_initialized(guard_object);
    if (pthread_mutex_unlock(&guard_mut))
        abort_message("__cxa_guard_release failed to release mutex");
    if (pthread_cond_broadcast(&guard_cv))
        abort_message("__cxa_guard_release failed to broadcast condition variable");
}

void __cxa_guard_abort(guard_type* guard_object)
{
    if (pthread_mutex_lock(&guard_mut))
        abort_message("__cxa_guard_abort failed to acquire mutex");
    *guard_object = 0;
    if (pthread_mutex_unlock(&guard_mut))
        abort_message("__cxa_guard_abort failed to release mutex");
    if (pthread_cond_broadcast(&guard_cv))
        abort_message("__cxa_guard_abort failed to broadcast condition variable");
}

#endif // !LIBCXXABI_SINGLE_THREADED

}  // extern "C"

}  // __cxxabiv1
<commit_msg>Fix broken build from r208135<commit_after>//===---------------------------- cxa_guard.cpp ---------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "abort_message.h"
#include "config.h"

#if !LIBCXXABI_SINGLE_THREADED
#  include <pthread.h>
#endif
#include <stdint.h>

/*
    This implementation must be careful to not call code external to this file
    which will turn around and try to call __cxa_guard_acquire reentrantly.
    For this reason, the headers of this file are as restricted as possible.
    Previous implementations of this code for __APPLE__ have used
    pthread_mutex_lock and the abort_message utility without problem.  This
    implementation also uses pthread_cond_wait which has tested to not be a
    problem.
*/

namespace __cxxabiv1
{

namespace
{

#if __arm__

// A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must
// be statically initialized to 0.
typedef uint32_t guard_type;

// Test the lowest bit.
inline bool is_initialized(guard_type* guard_object) {
    return (*guard_object) & 1;
}

inline void set_initialized(guard_type* guard_object) {
    *guard_object |= 1;
}

#else

typedef uint64_t guard_type;

bool is_initialized(guard_type* guard_object) {
    char* initialized = (char*)guard_object;
    return *initialized;
}

void set_initialized(guard_type* guard_object) {
    char* initialized = (char*)guard_object;
    *initialized = 1;
}

#endif

#if !LIBCXXABI_SINGLE_THREADED
pthread_mutex_t guard_mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  guard_cv  = PTHREAD_COND_INITIALIZER;
#endif

#if defined(__APPLE__) && !defined(__arm__)

typedef uint32_t lock_type;

#if __LITTLE_ENDIAN__

inline
lock_type
get_lock(uint64_t x)
{
    return static_cast<lock_type>(x >> 32);
}

inline
void
set_lock(uint64_t& x, lock_type y)
{
    x = static_cast<uint64_t>(y) << 32;
}

#else  // __LITTLE_ENDIAN__

inline
lock_type
get_lock(uint64_t x)
{
    return static_cast<lock_type>(x);
}

inline
void
set_lock(uint64_t& x, lock_type y)
{
    x = y;
}

#endif  // __LITTLE_ENDIAN__

#else  // !__APPLE__ || __arm__

typedef bool lock_type;

inline
lock_type
get_lock(uint64_t x)
{
    union
    {
        uint64_t guard;
        uint8_t lock[2];
    } f = {x};
    return f.lock[1] != 0;
}

inline
void
set_lock(uint64_t& x, lock_type y)
{
    union
    {
        uint64_t guard;
        uint8_t lock[2];
    } f = {0};
    f.lock[1] = y;
    x = f.guard;
}

inline
lock_type
get_lock(uint32_t x)
{
    union
    {
        uint32_t guard;
        uint8_t lock[2];
    } f = {x};
    return f.lock[1] != 0;
}

inline
void
set_lock(uint32_t& x, lock_type y)
{
    union
    {
        uint32_t guard;
        uint8_t lock[2];
    } f = {0};
    f.lock[1] = y;
    x = f.guard;
}

#endif  // __APPLE__

}  // unnamed namespace

extern "C"
{

#if LIBCXXABI_SINGLE_THREADED
int __cxa_guard_acquire(guard_type* guard_object)
{
    return !is_initialized(guard_object);
}

void __cxa_guard_release(guard_type* guard_object)
{
    *guard_object = 0;
    set_initialized(guard_object);
}

void __cxa_guard_abort(guard_type* guard_object)
{
    *guard_object = 0;
}

#else // !LIBCXXABI_SINGLE_THREADED

int __cxa_guard_acquire(guard_type* guard_object)
{
    char* initialized = (char*)guard_object;
    if (pthread_mutex_lock(&guard_mut))
        abort_message("__cxa_guard_acquire failed to acquire mutex");
    int result = *initialized == 0;
    if (result)
    {
#if defined(__APPLE__) && !defined(__arm__)
        const lock_type id = pthread_mach_thread_np(pthread_self());
        lock_type lock = get_lock(*guard_object);
        if (lock)
        {
            // if this thread set lock for this same guard_object, abort
            if (lock == id)
                abort_message("__cxa_guard_acquire detected deadlock");
            do
            {
                if (pthread_cond_wait(&guard_cv, &guard_mut))
                    abort_message("__cxa_guard_acquire condition variable wait failed");
                lock = get_lock(*guard_object);
            } while (lock);
            result = !is_initialized(guard_object);
            if (result)
                set_lock(*guard_object, id);
        }
        else
            set_lock(*guard_object, id);
#else  // !__APPLE__ || __arm__
        while (get_lock(*guard_object))
            if (pthread_cond_wait(&guard_cv, &guard_mut))
                abort_message("__cxa_guard_acquire condition variable wait failed");
        result = *initialized == 0;
        if (result)
            set_lock(*guard_object, true);
#endif  // !__APPLE__ || __arm__
    }
    if (pthread_mutex_unlock(&guard_mut))
        abort_message("__cxa_guard_acquire failed to release mutex");
    return result;
}

void __cxa_guard_release(guard_type* guard_object)
{
    if (pthread_mutex_lock(&guard_mut))
        abort_message("__cxa_guard_release failed to acquire mutex");
    *guard_object = 0;
    set_initialized(guard_object);
    if (pthread_mutex_unlock(&guard_mut))
        abort_message("__cxa_guard_release failed to release mutex");
    if (pthread_cond_broadcast(&guard_cv))
        abort_message("__cxa_guard_release failed to broadcast condition variable");
}

void __cxa_guard_abort(guard_type* guard_object)
{
    if (pthread_mutex_lock(&guard_mut))
        abort_message("__cxa_guard_abort failed to acquire mutex");
    *guard_object = 0;
    if (pthread_mutex_unlock(&guard_mut))
        abort_message("__cxa_guard_abort failed to release mutex");
    if (pthread_cond_broadcast(&guard_cv))
        abort_message("__cxa_guard_abort failed to broadcast condition variable");
}

#endif // !LIBCXXABI_SINGLE_THREADED

}  // extern "C"

}  // __cxxabiv1
<|endoftext|>


<commit_before>/*******************************************************************************
 *
 * X testing environment - Google Test environment feat. dummy x server
 *
 * Copyright (C) 2011, 2012 Canonical Ltd.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 ******************************************************************************/

#include "xorg/gtest/xorg-gtest_test.h"

#include <stdexcept>

#include <X11/Xlib.h>

struct xorg::testing::Test::Private {
  ::Display* display;
};

xorg::testing::Test::Test() : d_(new Private) {
  d_->display = NULL;
}

xorg::testing::Test::~Test() {}

void xorg::testing::Test::SetUp() {
  d_->display = XOpenDisplay(NULL);
  if (!d_->display)
    throw std::runtime_error("Failed to open connection to display");
}

void xorg::testing::Test::TearDown() {
  XCloseDisplay(d_->display);
  d_->display = NULL;
}

::Display* xorg::testing::Test::Display() const {
  return d_->display;
}
<commit_msg>XCloseDisplay(3) cannot handle NULL<commit_after>/*******************************************************************************
 *
 * X testing environment - Google Test environment feat. dummy x server
 *
 * Copyright (C) 2011, 2012 Canonical Ltd.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 ******************************************************************************/

#include "xorg/gtest/xorg-gtest_test.h"

#include <stdexcept>

#include <X11/Xlib.h>

struct xorg::testing::Test::Private {
  ::Display* display;
};

xorg::testing::Test::Test() : d_(new Private) {
  d_->display = NULL;
}

xorg::testing::Test::~Test() {}

void xorg::testing::Test::SetUp() {
  d_->display = XOpenDisplay(NULL);
  if (!d_->display)
    throw std::runtime_error("Failed to open connection to display");
}

void xorg::testing::Test::TearDown() {
  if (d_->display)
    XCloseDisplay(d_->display);
  d_->display = NULL;
}

::Display* xorg::testing::Test::Display() const {
  return d_->display;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: sunversion.hxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 19:31:59 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This 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 this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#if !defined INCLUDED_JVMACCESS_SUNVERSION_HXX
#define INCLUDED_JVMACCESS_SUNVERSION_HXX

#include "rtl/ustring.hxx"

namespace jfw_plugin {
// Define OSL_DEBUG_LEVEL >= 2 to run a test when this lib is loaded

/* SunVersion is used to compare java versions based on a string, as taken
   from the registry. The strings look like "1.3", "1.3.1", "1.3.1_02" etc.
   Versions such as "1.4.1_01a" are allowed although this is not specified.
   1.4.1_01 < 1.4.1_01a < 1.4.1_01b < 1.4.1_02
   Pre - release versions, such as 1.4.1-ea, 1.4.1-beta, 1.4.1-rc are recognized,
   but are treated as minor to release versions:
   1.4.0 > 1.4.2-beta
   Pre releases relate this way
   1.4.1-ea < 1.4.1-beta < 1.4.1-rc1

   This class supports also a FreeBSD Java. This is currently necessary because
   it also has the vendor string "Sun Microsystems Inc.".

   An object acts as holder for the version string. That string may be present
   even if the version could not be parsed. Then the version may not be compatible
   to a SUN Java version.

   An invalid object, that is, operator bool returns false, will always be
   the lower version in a comparison. If two invalid objects are compared
   then they are considered equal.

   To test if the version is ok, that is this object can be compared to others,
   use the bool conversion operator.
 */
class SunVersion
{
protected:

    enum PreRelease
    {
        Rel_NONE,
        Rel_EA,
        Rel_EA1,
        Rel_EA2,
        Rel_EA3,
        Rel_BETA,
        Rel_BETA1,
        Rel_BETA2,
        Rel_BETA3,
        Rel_RC,
        Rel_RC1,
        Rel_RC2,
        Rel_RC3
#if defined(FREEBSD)
    ,
        Rel_FreeBSD
#endif
    };

    //contains major,minor,micro,update
    int m_arVersionParts[4];
    // The update can be followed by a char, e.g. 1.4.1_01a
    char m_nUpdateSpecial;

    PreRelease m_preRelease;
public:
    SunVersion();
    SunVersion(const char * szVer);
    SunVersion(const rtl::OUString& usVer);
    ~SunVersion();

    /**
       Pre-release versions are taken into account.
       1.5.0-beta > 1.5.0-ea > 1.4.2
     */
    bool operator > (const SunVersion& ver) const;
    bool operator < (const SunVersion& ver) const;
    bool operator == (const SunVersion& ver) const;

    /** Test if the version is compatible tu SUN's versioning scheme
     */
    operator bool ();

    /** Will always contain a value if the object has been constructed with
        a version string.
     */
    rtl::OUString usVersion;

protected:
    bool init(const char * szVer);

    bool m_bValid;

    /* Determines if a string constitutes a pre release. For example, if
       "ea" is passed then Rel_EA is returned. If the string is no pre release
       then Rel_NONE is returned.
    */
    PreRelease getPreRelease(const char *szRel);
};

}

#endif // INCLUDED_JVMACCESS_SUNVERSION_HXX
<commit_msg>INTEGRATION: CWS changefileheader (1.7.126); FILE MERGED 2008/03/31 07:24:50 rt 1.7.126.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: sunversion.hxx,v $
 * $Revision: 1.8 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#if !defined INCLUDED_JVMACCESS_SUNVERSION_HXX
#define INCLUDED_JVMACCESS_SUNVERSION_HXX

#include "rtl/ustring.hxx"

namespace jfw_plugin {
// Define OSL_DEBUG_LEVEL >= 2 to run a test when this lib is loaded

/* SunVersion is used to compare java versions based on a string, as taken
   from the registry. The strings look like "1.3", "1.3.1", "1.3.1_02" etc.
   Versions such as "1.4.1_01a" are allowed although this is not specified.
   1.4.1_01 < 1.4.1_01a < 1.4.1_01b < 1.4.1_02
   Pre - release versions, such as 1.4.1-ea, 1.4.1-beta, 1.4.1-rc are recognized,
   but are treated as minor to release versions:
   1.4.0 > 1.4.2-beta
   Pre releases relate this way
   1.4.1-ea < 1.4.1-beta < 1.4.1-rc1

   This class supports also a FreeBSD Java. This is currently necessary because
   it also has the vendor string "Sun Microsystems Inc.".

   An object acts as holder for the version string. That string may be present
   even if the version could not be parsed. Then the version may not be compatible
   to a SUN Java version.

   An invalid object, that is, operator bool returns false, will always be
   the lower version in a comparison. If two invalid objects are compared
   then they are considered equal.

   To test if the version is ok, that is this object can be compared to others,
   use the bool conversion operator.
 */
class SunVersion
{
protected:

    enum PreRelease
    {
        Rel_NONE,
        Rel_EA,
        Rel_EA1,
        Rel_EA2,
        Rel_EA3,
        Rel_BETA,
        Rel_BETA1,
        Rel_BETA2,
        Rel_BETA3,
        Rel_RC,
        Rel_RC1,
        Rel_RC2,
        Rel_RC3
#if defined(FREEBSD)
    ,
        Rel_FreeBSD
#endif
    };

    //contains major,minor,micro,update
    int m_arVersionParts[4];
    // The update can be followed by a char, e.g. 1.4.1_01a
    char m_nUpdateSpecial;

    PreRelease m_preRelease;
public:
    SunVersion();
    SunVersion(const char * szVer);
    SunVersion(const rtl::OUString& usVer);
    ~SunVersion();

    /**
       Pre-release versions are taken into account.
       1.5.0-beta > 1.5.0-ea > 1.4.2
     */
    bool operator > (const SunVersion& ver) const;
    bool operator < (const SunVersion& ver) const;
    bool operator == (const SunVersion& ver) const;

    /** Test if the version is compatible tu SUN's versioning scheme
     */
    operator bool ();

    /** Will always contain a value if the object has been constructed with
        a version string.
     */
    rtl::OUString usVersion;

protected:
    bool init(const char * szVer);

    bool m_bValid;

    /* Determines if a string constitutes a pre release. For example, if
       "ea" is passed then Rel_EA is returned. If the string is no pre release
       then Rel_NONE is returned.
    */
    PreRelease getPreRelease(const char *szRel);
};

}

#endif // INCLUDED_JVMACCESS_SUNVERSION_HXX
<|endoftext|>


<commit_before>/*
    Kopete , The KDE Instant Messenger
    Copyright (c) 2001-2002 by Duncan Mac-Vicar Prett <duncan@kde.org>

    Viva Chile Mierda!
    Started at Wed Dec 26 03:12:10 CLST 2001, Santiago de Chile

    Kopete    (c) 2002-2003 by the Kopete developers  <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * 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.                                   *
    *                                                                       *
    *************************************************************************
*/

#include <kcmdlineargs.h>
#include <kaboutdata.h>
#include "kopeteapplication.h"

#include <dcopclient.h>
#include "kopeteiface.h"
#include "kimifaceimpl.h"

#define KOPETE_VERSION "0.8.922 (CVS >= 20040717)"

static const char description[] =
	I18N_NOOP( "Kopete, the KDE Instant Messenger" );

static KCmdLineOptions options[] =
{
	{ "noplugins",              I18N_NOOP( "Do not load plugins. This option overrides all other options." ), 0 },
	{ "noconnect",              I18N_NOOP( "Disable auto-connection" ), 0 },
	{ "autoconnect <accounts>", I18N_NOOP( "Auto-connect the specified accounts. Use a comma-separated list\n"
		"to auto-connect multiple accounts." ), 0 },
	{ "disable <plugins>",      I18N_NOOP( "Do not load the specified plugin. Use a comma-separated list\n"
		"to disable multiple plugins." ), 0 },
	{ "load-plugins <plugins>", I18N_NOOP( "Load only the specified plugins. Use a comma-separated list\n"
		"to load multiple plugins. This option has no effect when\n"
		"--noplugins is set and overrides all other plugin related\n"
		"command line options." ), 0 },
//	{ "url <url>",              I18N_NOOP( "Load the given Kopete URL" ), 0 },
//	{ "!+[plugin]",            I18N_NOOP( "Load specified plugins" ), 0 },
	{ "!+[URL]",                 I18N_NOOP("URLs to pass to kopete / emoticon themes to install"), 0},
	KCmdLineLastOption
};

int main( int argc, char *argv[] )
{
	KAboutData aboutData( "kopete", I18N_NOOP("Kopete"),
		KOPETE_VERSION, description, KAboutData::License_GPL,
		I18N_NOOP("(c) 2001-2004, Duncan Mac-Vicar Prett\n(c) 2002-2004, Kopete Development Team"), "kopete-devel@kde.org", "http://kopete.kde.org");

	aboutData.addAuthor ( "Duncan Mac-Vicar Prett", I18N_NOOP("Original author, Developer"), "duncan@kde.org", "http://www.mac-vicar.org/~duncan" );
	aboutData.addAuthor ( "Stefan Gehn", I18N_NOOP("Developer, Oscar plugin"), "metz@gehn.net", "http://metz.gehn.net" );
	aboutData.addAuthor ( "Till Gerken", I18N_NOOP("Developer, Jabber plugin maintainer"), "till@tantalo.net");
	aboutData.addAuthor ( "Olivier Goffart", I18N_NOOP("Developer, MSN plugin maintainer"), "ogoffart@tiscalinet.be");
	aboutData.addAuthor ( "Andy Goossens", I18N_NOOP("Developer"), "andygoossens@telenet.be" );
	aboutData.addAuthor ( "Chris Howells", I18N_NOOP("Developer, Connection status plugin author"), "howells@kde.org", "http://chrishowells.co.uk");
	aboutData.addAuthor ( "Grzegorz Jaskiewicz", I18N_NOOP("Developer, Gadu plugin maintainer"), "gj@pointblue.com.pl" );
	aboutData.addAuthor ( "Jason Keirstead", I18N_NOOP("Developer, IRC maintainer"), "jason@keirstead.org", "http://www.keirstead.org");
	aboutData.addAuthor ( "Martijn Klingens", I18N_NOOP("Developer"), "klingens@kde.org" );
	aboutData.addAuthor ( "Matt Rogers", I18N_NOOP("Developer, Yahoo plugin and Oscar plugin maintainer"), "mattrogers@sbcglobal.net" );
	aboutData.addAuthor ( "Zack Rusin", I18N_NOOP("Developer, original Gadu plugin author"), "zack@kde.org" );
	aboutData.addAuthor ( "Richard Smith", I18N_NOOP("Developer, UI maintainer"), "kde@metafoo.co.uk" );
	aboutData.addAuthor ( "Will Stephenson", I18N_NOOP("Developer, icons, various plugins"), "lists@stevello.free-online.co.uk" );
	aboutData.addAuthor ( "Gav Wood", I18N_NOOP("Developer, WinPopup plugin maintainer"), "gjw102@york.ac.uk" );

	aboutData.addCredit ( "Luciash d' Being", I18N_NOOP("Kopete's icon author") );
	aboutData.addCredit ( "Steve Cable", I18N_NOOP("Sounds") );
	aboutData.addCredit ( "Justin Karneges", I18N_NOOP("Iris Jabber Backend Library") );
	aboutData.addCredit ( "Tom Linsky", I18N_NOOP("OscarSocket author"), "twl6@po.cwru.edu" );
	aboutData.addCredit ( "Olaf Lueg", I18N_NOOP("Kmerlin MSN code") );

	aboutData.addCredit ( "Nick Betcher", I18N_NOOP("Former developer, project co-founder"), "nbetcher@kde.org");
	aboutData.addCredit ( "Ryan Cumming", I18N_NOOP("Former developer"), "ryan@kde.org" );
	aboutData.addCredit ( "Andres Krapf", I18N_NOOP("Former developer"), "dae@chez.com" );
	aboutData.addCredit ( "Carsten Pfeiffer", I18N_NOOP("Misc bugfixes and enhancements"), "pfeiffer@kde.org" );
	aboutData.addCredit ( "Richard Stellingwerff", I18N_NOOP("Former developer"), "remenic@linuxfromscratch.org");
	aboutData.addCredit ( "Daniel Stone", I18N_NOOP("Former developer, Jabber plugin author"), "daniel@fooishbar.org", "http://fooishbar.org");
	aboutData.addCredit ( "Chris TenHarmsel", I18N_NOOP("Former developer, Oscar plugin"), "tenharmsel@users.sourceforge.net");
	aboutData.addCredit ( "Hendrik vom Lehn", I18N_NOOP("Former developer"), "hennevl@hennevl.de", "http://www.hennevl.de");

	aboutData.setTranslator( I18N_NOOP("_: NAME OF TRANSLATORS\nYour names"),
		I18N_NOOP("_: EMAIL OF TRANSLATORS\nYour emails") );

	KCmdLineArgs::init( argc, argv, &aboutData );
	KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
	KUniqueApplication::addCmdLineOptions();

	KopeteApplication kopete;
	new KIMIfaceImpl();
	kapp->dcopClient()->registerAs( "kopete", false );
	kapp->dcopClient()->setDefaultObject( (new KopeteIface())->objId() ); // Has to be called before exec

	kopete.exec();
}
// vim: set noet ts=4 sts=4 sw=4:
<commit_msg>Update version number.<commit_after>/*
    Kopete , The KDE Instant Messenger
    Copyright (c) 2001-2002 by Duncan Mac-Vicar Prett <duncan@kde.org>

    Viva Chile Mierda!
    Started at Wed Dec 26 03:12:10 CLST 2001, Santiago de Chile

    Kopete    (c) 2002-2003 by the Kopete developers  <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * 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.                                   *
    *                                                                       *
    *************************************************************************
*/

#include <kcmdlineargs.h>
#include <kaboutdata.h>
#include "kopeteapplication.h"

#include <dcopclient.h>
#include "kopeteiface.h"
#include "kimifaceimpl.h"

#define KOPETE_VERSION "0.9.0"

static const char description[] =
	I18N_NOOP( "Kopete, the KDE Instant Messenger" );

static KCmdLineOptions options[] =
{
	{ "noplugins",              I18N_NOOP( "Do not load plugins. This option overrides all other options." ), 0 },
	{ "noconnect",              I18N_NOOP( "Disable auto-connection" ), 0 },
	{ "autoconnect <accounts>", I18N_NOOP( "Auto-connect the specified accounts. Use a comma-separated list\n"
		"to auto-connect multiple accounts." ), 0 },
	{ "disable <plugins>",      I18N_NOOP( "Do not load the specified plugin. Use a comma-separated list\n"
		"to disable multiple plugins." ), 0 },
	{ "load-plugins <plugins>", I18N_NOOP( "Load only the specified plugins. Use a comma-separated list\n"
		"to load multiple plugins. This option has no effect when\n"
		"--noplugins is set and overrides all other plugin related\n"
		"command line options." ), 0 },
//	{ "url <url>",              I18N_NOOP( "Load the given Kopete URL" ), 0 },
//	{ "!+[plugin]",            I18N_NOOP( "Load specified plugins" ), 0 },
	{ "!+[URL]",                 I18N_NOOP("URLs to pass to kopete / emoticon themes to install"), 0},
	KCmdLineLastOption
};

int main( int argc, char *argv[] )
{
	KAboutData aboutData( "kopete", I18N_NOOP("Kopete"),
		KOPETE_VERSION, description, KAboutData::License_GPL,
		I18N_NOOP("(c) 2001-2004, Duncan Mac-Vicar Prett\n(c) 2002-2004, Kopete Development Team"), "kopete-devel@kde.org", "http://kopete.kde.org");

	aboutData.addAuthor ( "Duncan Mac-Vicar Prett", I18N_NOOP("Original author, Developer"), "duncan@kde.org", "http://www.mac-vicar.org/~duncan" );
	aboutData.addAuthor ( "Stefan Gehn", I18N_NOOP("Developer, Oscar plugin"), "metz@gehn.net", "http://metz.gehn.net" );
	aboutData.addAuthor ( "Till Gerken", I18N_NOOP("Developer, Jabber plugin maintainer"), "till@tantalo.net");
	aboutData.addAuthor ( "Olivier Goffart", I18N_NOOP("Developer, MSN plugin maintainer"), "ogoffart@tiscalinet.be");
	aboutData.addAuthor ( "Andy Goossens", I18N_NOOP("Developer"), "andygoossens@telenet.be" );
	aboutData.addAuthor ( "Chris Howells", I18N_NOOP("Developer, Connection status plugin author"), "howells@kde.org", "http://chrishowells.co.uk");
	aboutData.addAuthor ( "Grzegorz Jaskiewicz", I18N_NOOP("Developer, Gadu plugin maintainer"), "gj@pointblue.com.pl" );
	aboutData.addAuthor ( "Jason Keirstead", I18N_NOOP("Developer, IRC maintainer"), "jason@keirstead.org", "http://www.keirstead.org");
	aboutData.addAuthor ( "Martijn Klingens", I18N_NOOP("Developer"), "klingens@kde.org" );
	aboutData.addAuthor ( "Matt Rogers", I18N_NOOP("Developer, Yahoo plugin and Oscar plugin maintainer"), "mattrogers@sbcglobal.net" );
	aboutData.addAuthor ( "Zack Rusin", I18N_NOOP("Developer, original Gadu plugin author"), "zack@kde.org" );
	aboutData.addAuthor ( "Richard Smith", I18N_NOOP("Developer, UI maintainer"), "kde@metafoo.co.uk" );
	aboutData.addAuthor ( "Will Stephenson", I18N_NOOP("Developer, icons, various plugins"), "lists@stevello.free-online.co.uk" );
	aboutData.addAuthor ( "Gav Wood", I18N_NOOP("Developer, WinPopup plugin maintainer"), "gjw102@york.ac.uk" );

	aboutData.addCredit ( "Luciash d' Being", I18N_NOOP("Kopete's icon author") );
	aboutData.addCredit ( "Steve Cable", I18N_NOOP("Sounds") );
	aboutData.addCredit ( "Justin Karneges", I18N_NOOP("Iris Jabber Backend Library") );
	aboutData.addCredit ( "Tom Linsky", I18N_NOOP("OscarSocket author"), "twl6@po.cwru.edu" );
	aboutData.addCredit ( "Olaf Lueg", I18N_NOOP("Kmerlin MSN code") );

	aboutData.addCredit ( "Nick Betcher", I18N_NOOP("Former developer, project co-founder"), "nbetcher@kde.org");
	aboutData.addCredit ( "Ryan Cumming", I18N_NOOP("Former developer"), "ryan@kde.org" );
	aboutData.addCredit ( "Andres Krapf", I18N_NOOP("Former developer"), "dae@chez.com" );
	aboutData.addCredit ( "Carsten Pfeiffer", I18N_NOOP("Misc bugfixes and enhancements"), "pfeiffer@kde.org" );
	aboutData.addCredit ( "Richard Stellingwerff", I18N_NOOP("Former developer"), "remenic@linuxfromscratch.org");
	aboutData.addCredit ( "Daniel Stone", I18N_NOOP("Former developer, Jabber plugin author"), "daniel@fooishbar.org", "http://fooishbar.org");
	aboutData.addCredit ( "Chris TenHarmsel", I18N_NOOP("Former developer, Oscar plugin"), "tenharmsel@users.sourceforge.net");
	aboutData.addCredit ( "Hendrik vom Lehn", I18N_NOOP("Former developer"), "hennevl@hennevl.de", "http://www.hennevl.de");

	aboutData.setTranslator( I18N_NOOP("_: NAME OF TRANSLATORS\nYour names"),
		I18N_NOOP("_: EMAIL OF TRANSLATORS\nYour emails") );

	KCmdLineArgs::init( argc, argv, &aboutData );
	KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
	KUniqueApplication::addCmdLineOptions();

	KopeteApplication kopete;
	new KIMIfaceImpl();
	kapp->dcopClient()->registerAs( "kopete", false );
	kapp->dcopClient()->setDefaultObject( (new KopeteIface())->objId() ); // Has to be called before exec

	kopete.exec();
}
// vim: set noet ts=4 sts=4 sw=4:
<|endoftext|>


<commit_before>#include <cstdlib>

#include <iostream>

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/expressions/formatters/date_time.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/attributes/current_thread_id.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>

#include <boost/filesystem.hpp>
#include <boost/asio.hpp>

namespace logging = boost::log;
namespace expr = boost::log::expressions;
namespace fs = boost::filesystem;

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif //HAVE_CONFIG_H

#include "configure.hpp"
#include "remcon.hpp"
#include "daemon.hpp"

Daemon::Daemon(DaemonConfigure const& config)
{
	if(config.version_requested())
	{
		std::cout << "Distributed Filesystem (c) Tom Johnson 2014\n"
			<< "Project v" << VERSION
			<< " Daemon v0.0\n";
		state_ = exit;
	}
	else
	{
		// Double-fork to avoid zombification on parent exit
		if(config.daemonise())
			double_fork();

		//Setup our logs
		init_log(config.log_path(), config.output_loudness(), config.log_level());

		boost::asio::io_service io;

		RemoteControl remcon(io, config.socket());
	}
}

int Daemon::exit_code() const
{
	return static_cast<int>(state_);
}

void Daemon::double_fork() const
{
	pid_t pid1, pid2;
	int status;

	if(pid1 = fork()) // parent process
		std::exit(0);
	else if (!pid1) // child process
	{
		int sid = setsid();
		if(pid2 = fork()) // second parent
			std::exit(0);
		else if(!pid2)
		{
			// Change current directory
			chdir("/");

			// Reset our umask:
			umask(0);

			// Close stdin, stdout and stderr:
			close(0);
			close(1);
			close(2);
		}
		else
			BOOST_LOG_TRIVIAL(warning) << "Second fork of daemonise failed. Continuing...";
	}
	else
		BOOST_LOG_TRIVIAL(warning) << "First fork of daemonise failed. Continuing...";
}

void Daemon::init_log(fs::path const& log_path, DaemonConfigure::loudness stderr_level, logging::trivial::severity_level level) const
{
	//Add attributes

	//Add LineID, TimeStamp, ProcessID and ThreadID.
	logging::add_common_attributes();

	//Formatter
	auto formatter = expr::stream
		<< "[" << expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%dT%H:%M:%S%q")
		<< "] {" << expr::attr<logging::attributes::current_thread_id::value_type>("ThreadID")
		<< "} (" << logging::trivial::severity
		<< "): " << expr::message;

	if(stderr_level != DaemonConfigure::daemon)
	{
		logging::trivial::severity_level stderr_severity;
		switch(stderr_level)
		{
		case DaemonConfigure::quiet:
			stderr_severity = logging::trivial::fatal;
			break;

		case DaemonConfigure::verbose:
			stderr_severity = logging::trivial::info;
			break;

		case DaemonConfigure::normal:
		default:
			stderr_severity = logging::trivial::warning;
		}

		logging::add_console_log(std::cerr, logging::keywords::format = formatter)->set_filter(logging::trivial::severity >= stderr_severity);
	}

	logging::add_file_log(logging::keywords::file_name = log_path.string(),
			logging::keywords::open_mode = std::ios::app,
			logging::keywords::format = formatter)
		->set_filter(logging::trivial::severity >= level);

	BOOST_LOG_TRIVIAL(info) << "Log start.";
	BOOST_LOG_TRIVIAL(info) << "Logging to " << log_path;
}
<commit_msg>Fixed some compile warnings in daemon.cppFixed some compile warnings in daemon.cppFixed some compile warnings in daemon.cppFixed some compile warnings in daemon.cppFixed some compile warnings in daemon.cppFixed some compile warnings in daemon.cppFixed some compile warnings in daemon.cppFixed some compile warnings in daemon.cppFixed some compile warnings in daemon.cpp<commit_after>#include <cstdlib>

#include <iostream>

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/expressions/formatters/date_time.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/attributes/current_thread_id.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>

#include <boost/filesystem.hpp>
#include <boost/asio.hpp>

namespace logging = boost::log;
namespace expr = boost::log::expressions;
namespace fs = boost::filesystem;

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif //HAVE_CONFIG_H

#include "configure.hpp"
#include "remcon.hpp"
#include "daemon.hpp"

Daemon::Daemon(DaemonConfigure const& config)
{
	if(config.version_requested())
	{
		std::cout << "Distributed Filesystem (c) Tom Johnson 2014\n"
			<< "Project v" << VERSION
			<< " Daemon v0.0\n";
		state_ = exit;
	}
	else
	{
		// Double-fork to avoid zombification on parent exit
		if(config.daemonise())
			double_fork();

		//Setup our logs
		init_log(config.log_path(), config.output_loudness(), config.log_level());

		boost::asio::io_service io;

		RemoteControl remcon(io, config.socket());
	}
}

int Daemon::exit_code() const
{
	return static_cast<int>(state_);
}

void Daemon::double_fork() const
{
	pid_t pid1, pid2;

	if((pid1 = fork())) // parent process
		std::exit(0);
	else if (!pid1) // child process
	{
		setsid();
		if((pid2 = fork())) // second parent
			std::exit(0);
		else if(!pid2)
		{
			// Change current directory
			chdir("/");

			// Reset our umask:
			umask(0);

			// Close stdin, stdout and stderr:
			close(0);
			close(1);
			close(2);
		}
		else
			BOOST_LOG_TRIVIAL(warning) << "Second fork of daemonise failed. Continuing...";
	}
	else
		BOOST_LOG_TRIVIAL(warning) << "First fork of daemonise failed. Continuing...";
}

void Daemon::init_log(fs::path const& log_path, DaemonConfigure::loudness stderr_level, logging::trivial::severity_level level) const
{
	//Add attributes

	//Add LineID, TimeStamp, ProcessID and ThreadID.
	logging::add_common_attributes();

	//Formatter
	auto formatter = expr::stream
		<< "[" << expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%dT%H:%M:%S%q")
		<< "] {" << expr::attr<logging::attributes::current_thread_id::value_type>("ThreadID")
		<< "} (" << logging::trivial::severity
		<< "): " << expr::message;

	if(stderr_level != DaemonConfigure::daemon)
	{
		logging::trivial::severity_level stderr_severity;
		switch(stderr_level)
		{
		case DaemonConfigure::quiet:
			stderr_severity = logging::trivial::fatal;
			break;

		case DaemonConfigure::verbose:
			stderr_severity = logging::trivial::info;
			break;

		case DaemonConfigure::normal:
		default:
			stderr_severity = logging::trivial::warning;
		}

		logging::add_console_log(std::cerr, logging::keywords::format = formatter)->set_filter(logging::trivial::severity >= stderr_severity);
	}

	logging::add_file_log(logging::keywords::file_name = log_path.string(),
			logging::keywords::open_mode = std::ios::app,
			logging::keywords::format = formatter)
		->set_filter(logging::trivial::severity >= level);

	BOOST_LOG_TRIVIAL(info) << "Log start.";
	BOOST_LOG_TRIVIAL(info) << "Logging to " << log_path;
}
<|endoftext|>


<commit_before>/**************************************************************************
 *
 * Copyright 2011 Jose Fonseca
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **************************************************************************/

/*
 * Main program to start and inject a DLL into a process via a remote thread.
 *
 * For background see:
 * - http://en.wikipedia.org/wiki/DLL_injection#Approaches_on_Microsoft_Windows
 * - http://www.codeproject.com/KB/threads/completeinject.aspx
 * - http://www.codeproject.com/KB/threads/winspy.aspx
 * - http://www.codeproject.com/KB/DLL/DLL_Injection_tutorial.aspx
 * - http://www.codeproject.com/KB/threads/APIHooking.aspx
 *
 * Other slightly different techniques:
 * - http://www.fr33project.org/pages/projects/phook.htm
 * - http://www.hbgary.com/loading-a-dll-without-calling-loadlibrary
 * - http://securityxploded.com/ntcreatethreadex.php
 */

#include <string>
#include <stdio.h>
#include <assert.h>

#include <windows.h>
#include <psapi.h>
#include <dwmapi.h>
#include <tlhelp32.h>

#ifndef ERROR_ELEVATION_REQUIRED
#define ERROR_ELEVATION_REQUIRED 740
#endif

#include "os_version.hpp"
#include "devcon.hpp"
#include "inject.h"

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
#endif

static void
debugPrintf(const char *format, ...)
{
    va_list ap;
    va_start(ap, format);
    vfprintf(stderr, format, ap);
    va_end(ap);
}

/**
 * Determine whether an argument should be quoted.
 */
static bool
needsQuote(const char *arg)
{
    char c;
    while (true) {
        c = *arg++;
        if (c == '\0') {
            break;
        }
        if (c == ' ' || c == '\t' || c == '\"') {
            return true;
        }
        if (c == '\\') {
            c = *arg++;
            if (c == '\0') {
                break;
            }
            if (c == '"') {
                return true;
            }
        }
    }
    return false;
}

static void
quoteArg(std::string &s, const char *arg)
{
    char c;
    unsigned backslashes = 0;

    s.push_back('"');
    while (true) {
        c = *arg++;
        if (c == '\0') {
            break;
        } else if (c == '"') {
            while (backslashes) {
                s.push_back('\\');
                --backslashes;
            }
            s.push_back('\\');
        } else {
            if (c == '\\') {
                ++backslashes;
            } else {
                backslashes = 0;
            }
        }
        s.push_back(c);
    }
    s.push_back('"');
}

// http://msdn.microsoft.com/en-gb/library/windows/desktop/ms686335.aspx
static void
restartService(const char *lpServiceName)
{
    SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    assert(hSCManager);
    if (!hSCManager) {
        return;
    }

    SC_HANDLE hService = OpenServiceA(hSCManager, lpServiceName, SC_MANAGER_ALL_ACCESS);
    assert(hService);
    if (!hService) {
        return;
    }

    SERVICE_STATUS_PROCESS ssp;
    DWORD cbBytesNeeded;
    QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE) &ssp, sizeof ssp, &cbBytesNeeded);

    BOOL bRet;
    if (ssp.dwCurrentState == SERVICE_RUNNING) {
        bRet = ControlService(hService, SERVICE_CONTROL_STOP, (LPSERVICE_STATUS) &ssp);
        assert(bRet);
        while (ssp.dwCurrentState != SERVICE_STOPPED) {
            Sleep(ssp.dwWaitHint);
            QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE) &ssp, sizeof ssp, &cbBytesNeeded);
        }
        bRet = StartService(hService, 0, NULL);
        assert(bRet);
    }

    CloseServiceHandle(hService);
    CloseServiceHandle(hSCManager);
}

// Force DWM process to recreate all its Direct3D objects.
static void
restartDwmComposition(HANDLE hProcess)
{
    HRESULT hr;

    HMODULE hModule = LoadLibraryA("dwmapi");
    assert(hModule);
    if (!hModule) {
        return;
    }

    typedef HRESULT (WINAPI *PFNDWMISCOMPOSITIONENABLED)(BOOL *pfEnabled);
    PFNDWMISCOMPOSITIONENABLED pfnDwmIsCompositionEnabled = (PFNDWMISCOMPOSITIONENABLED)GetProcAddress(hModule, "DwmIsCompositionEnabled");
    assert(pfnDwmIsCompositionEnabled);
    if (!pfnDwmIsCompositionEnabled) {
        return;
    }

    typedef HRESULT (WINAPI *PFNDWMENABLECOMPOSITION)(UINT uCompositionAction);
    PFNDWMENABLECOMPOSITION pfnDwmEnableComposition = (PFNDWMENABLECOMPOSITION)GetProcAddress(hModule, "DwmEnableComposition");
    assert(pfnDwmEnableComposition);
    if (!pfnDwmEnableComposition) {
        return;
    }

    BOOL bIsWindows8OrGreater = IsWindows8OrGreater();
    if (bIsWindows8OrGreater) {
        // Windows 8 ignores DwmEnableComposition(DWM_EC_DISABLECOMPOSITION).
        // It is however possible to force DWM to restart by restarting the
        // display device via the devcon utility
        devconRestart(DEVCON_CLASS_DISPLAY);
    } else {

        BOOL fEnabled = FALSE;
        hr = pfnDwmIsCompositionEnabled(&fEnabled);
        if (FAILED(hr) || !fEnabled) {
            return;
        }

        fprintf(stderr, "info: restarting DWM composition\n");

        hr = pfnDwmEnableComposition(DWM_EC_DISABLECOMPOSITION);
        assert(SUCCEEDED(hr));
        if (FAILED(hr)) {
            return;
        }

        Sleep(1000/30);

        hr = pfnDwmEnableComposition(DWM_EC_ENABLECOMPOSITION);
        assert(SUCCEEDED(hr));
        (void)hr;
    }

    fprintf(stderr, "Press any key when finished tracing\n");
    getchar();

    DWORD dwExitCode;
    if (GetExitCodeProcess(hProcess, &dwExitCode) &&
        dwExitCode != STILL_ACTIVE) {
        // DWM process has already terminated
        return;
    }

    fprintf(stderr, "info: restarting DWM process\n");
    if (bIsWindows8OrGreater) {
        // From Windows 8 onwards DWM no longer runs as a service.  We just
        // kill it and winlogon parent process will respawn it.
        if (!TerminateProcess(hProcess, 0)) {
            logLastError("failed to terminate DWM process");
        }
    } else {
        hr = pfnDwmEnableComposition(DWM_EC_DISABLECOMPOSITION);
        assert(SUCCEEDED(hr));

        restartService("uxsms");
    }
}

BOOL
getProcessIdByName(const char *szProcessName, DWORD *pdwProcessID)
{
    BOOL bRet = FALSE;

    HANDLE hProcessSnap;
    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hProcessSnap != INVALID_HANDLE_VALUE) {
        PROCESSENTRY32 pe32;
        pe32.dwSize = sizeof pe32;
        if (Process32First(hProcessSnap, &pe32)) {
            do {
                if (stricmp(szProcessName, pe32.szExeFile) == 0) {
                    *pdwProcessID = pe32.th32ProcessID;
                    bRet = TRUE;
                    break;
                }
            } while (Process32Next(hProcessSnap, &pe32));
        }
        CloseHandle(hProcessSnap);
    }

    return bRet;
}

int
main(int argc, char *argv[])
{
    if (argc < 3) {
        fprintf(stderr,
                "usage:\n"
                "  inject <dllname.dll> <command> [args] ...\n"
                "  inject <dllname.dll> <process-id>\n"
                "  inject <dllname.dll> !<process-name>\n"
        );
        return 1;
    }

    BOOL bAttach = FALSE;
    DWORD dwProcessId = ~0;
    if (isdigit(argv[2][0])) {
        dwProcessId = atol(argv[2]);
        bAttach = TRUE;
    } else if (argv[2][0] == '!') {
        const char *szProcessName = &argv[2][1];
        if (!getProcessIdByName(szProcessName, &dwProcessId)) {
            fprintf(stderr, "error: failed to find process %s\n", szProcessName);
            return 1;
        }
        bAttach = TRUE;
        fprintf(stderr, "dwProcessId = %lu\n", dwProcessId);
    }

    HANDLE hSemaphore = NULL;
    const char *szDll = argv[1];
    if (!USE_SHARED_MEM) {
        SetEnvironmentVariableA("INJECT_DLL", szDll);
    } else {
        hSemaphore = CreateSemaphore(NULL, 1, 1, "inject_semaphore");
        if (hSemaphore == NULL) {
            fprintf(stderr, "error: failed to create semaphore\n");
            return 1;
        }

        DWORD dwWait = WaitForSingleObject(hSemaphore, 0);
        if (dwWait == WAIT_TIMEOUT) {
            fprintf(stderr, "info: waiting for another inject instance to finish\n");
            dwWait = WaitForSingleObject(hSemaphore, INFINITE);
        }
        if (dwWait != WAIT_OBJECT_0) {
            fprintf(stderr, "error: failed to enter semaphore gate\n");
            return 1;
        }

        SetSharedMem(szDll);
    }

    PROCESS_INFORMATION processInfo;
    HANDLE hProcess;
    if (bAttach) {
        BOOL bRet;
        HANDLE hToken   = NULL;
        bRet = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken);
        if (!bRet) {
            fprintf(stderr, "error: OpenProcessToken returned %u\n", (unsigned)bRet);
            return 1;
        }

        LUID Luid;
        bRet = LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Luid);
        if (!bRet) {
            fprintf(stderr, "error: LookupPrivilegeValue returned %u\n", (unsigned)bRet);
            return 1;
        }

        TOKEN_PRIVILEGES tp;
        tp.PrivilegeCount = 1;
        tp.Privileges[0].Luid = Luid;
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        bRet = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof tp, NULL, NULL);
        if (!bRet) {
            fprintf(stderr, "error: AdjustTokenPrivileges returned %u\n", (unsigned)bRet);
            return 1;
        }

        DWORD dwDesiredAccess =
            PROCESS_CREATE_THREAD |
            PROCESS_QUERY_INFORMATION |
            PROCESS_QUERY_LIMITED_INFORMATION |
            PROCESS_VM_OPERATION |
            PROCESS_VM_WRITE |
            PROCESS_VM_READ |
            PROCESS_TERMINATE;
        hProcess = OpenProcess(
            dwDesiredAccess,
            FALSE /* bInheritHandle */,
            dwProcessId);
        if (!hProcess) {
            logLastError("failed to open process");
            return 1;
        }
    } else {
        bAttach = FALSE;
        std::string commandLine;
        char sep = 0;
        for (int i = 2; i < argc; ++i) {
            const char *arg = argv[i];

            if (sep) {
                commandLine.push_back(sep);
            }

            if (needsQuote(arg)) {
                quoteArg(commandLine, arg);
            } else {
                commandLine.append(arg);
            }

            sep = ' ';
        }

        STARTUPINFO startupInfo;
        memset(&startupInfo, 0, sizeof startupInfo);
        startupInfo.cb = sizeof startupInfo;

        // Create the process in suspended state
        if (!CreateProcessA(
               NULL,
               const_cast<char *>(commandLine.c_str()), // only modified by CreateProcessW
               0, // process attributes
               0, // thread attributes
               TRUE, // inherit handles
               CREATE_SUSPENDED,
               NULL, // environment
               NULL, // current directory
               &startupInfo,
               &processInfo)) {
            DWORD dwLastError = GetLastError();
            fprintf(stderr, "error: failed to execute %s (%lu)\n",
                    commandLine.c_str(), dwLastError);
            if (dwLastError == ERROR_ELEVATION_REQUIRED) {
                fprintf(stderr, "error: target program requires elevated priviledges and must be started from an Administrator Command Prompt, or UAC must be disabled\n");
            }
            return 1;
        }

        hProcess = processInfo.hProcess;
    }

    /*
     * XXX: Mixed architecture don't quite work.  See also
     * http://www.corsix.org/content/dll-injection-and-wow64
     */
    {
        typedef BOOL (WINAPI *PFNISWOW64PROCESS)(HANDLE, PBOOL);
        PFNISWOW64PROCESS pfnIsWow64Process;
        pfnIsWow64Process = (PFNISWOW64PROCESS)
            GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process");
        if (pfnIsWow64Process) {
            BOOL isParentWow64 = FALSE;
            BOOL isChildWow64 = FALSE;
            if (pfnIsWow64Process(GetCurrentProcess(), &isParentWow64) &&
                pfnIsWow64Process(hProcess, &isChildWow64) &&
                isParentWow64 != isChildWow64) {
                fprintf(stderr, "error: binaries mismatch: you need to use the "
#ifdef _WIN64
                        "32-bits"
#else
                        "64-bits"
#endif
                        " apitrace binaries to trace this application\n");
                TerminateProcess(hProcess, 1);
                return 1;
            }
        }
    }

    const char *szDllName;
    szDllName = "injectee.dll";

    char szDllPath[MAX_PATH];
    GetModuleFileNameA(NULL, szDllPath, sizeof szDllPath);
    getDirName(szDllPath);
    strncat(szDllPath, szDllName, sizeof szDllPath - strlen(szDllPath) - 1);

#if 1
    if (!injectDll(hProcess, szDllPath)) {
        TerminateProcess(hProcess, 1);
        return 1;
    }
#endif

    DWORD exitCode;

    if (bAttach) {
        char szProcess[MAX_PATH];
        DWORD dwRet = GetModuleFileNameEx(hProcess, 0, szProcess, sizeof szProcess);
        assert(dwRet);

        if (stricmp(getBaseName(szProcess), "dwm.exe") == 0) {
            restartDwmComposition(hProcess);
        }

        exitCode = 0;
    } else {
        // Start main process thread
        ResumeThread(processInfo.hThread);

        // Wait for it to finish
        WaitForSingleObject(hProcess, INFINITE);

        if (pSharedMem && !pSharedMem->bReplaced) {
            fprintf(stderr, "warning: %s was never used: application probably does not use this API\n", szDll);
        }

        exitCode = ~0;
        GetExitCodeProcess(hProcess, &exitCode);

        CloseHandle(processInfo.hThread);
    }

    CloseHandle(hProcess);

    if (hSemaphore) {
        ReleaseSemaphore(hSemaphore, 1, NULL);
        CloseHandle(hSemaphore);
    }

    return (int)exitCode;
}
<commit_msg>inject: Attach to DWM with display device disabled.<commit_after>/**************************************************************************
 *
 * Copyright 2011 Jose Fonseca
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **************************************************************************/

/*
 * Main program to start and inject a DLL into a process via a remote thread.
 *
 * For background see:
 * - http://en.wikipedia.org/wiki/DLL_injection#Approaches_on_Microsoft_Windows
 * - http://www.codeproject.com/KB/threads/completeinject.aspx
 * - http://www.codeproject.com/KB/threads/winspy.aspx
 * - http://www.codeproject.com/KB/DLL/DLL_Injection_tutorial.aspx
 * - http://www.codeproject.com/KB/threads/APIHooking.aspx
 *
 * Other slightly different techniques:
 * - http://www.fr33project.org/pages/projects/phook.htm
 * - http://www.hbgary.com/loading-a-dll-without-calling-loadlibrary
 * - http://securityxploded.com/ntcreatethreadex.php
 */

#include <string>
#include <stdio.h>
#include <assert.h>

#include <windows.h>
#include <psapi.h>
#include <dwmapi.h>
#include <tlhelp32.h>

#ifndef ERROR_ELEVATION_REQUIRED
#define ERROR_ELEVATION_REQUIRED 740
#endif

#include "os_version.hpp"
#include "devcon.hpp"
#include "inject.h"

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
#endif

static void
debugPrintf(const char *format, ...)
{
    va_list ap;
    va_start(ap, format);
    vfprintf(stderr, format, ap);
    va_end(ap);
}

/**
 * Determine whether an argument should be quoted.
 */
static bool
needsQuote(const char *arg)
{
    char c;
    while (true) {
        c = *arg++;
        if (c == '\0') {
            break;
        }
        if (c == ' ' || c == '\t' || c == '\"') {
            return true;
        }
        if (c == '\\') {
            c = *arg++;
            if (c == '\0') {
                break;
            }
            if (c == '"') {
                return true;
            }
        }
    }
    return false;
}

static void
quoteArg(std::string &s, const char *arg)
{
    char c;
    unsigned backslashes = 0;

    s.push_back('"');
    while (true) {
        c = *arg++;
        if (c == '\0') {
            break;
        } else if (c == '"') {
            while (backslashes) {
                s.push_back('\\');
                --backslashes;
            }
            s.push_back('\\');
        } else {
            if (c == '\\') {
                ++backslashes;
            } else {
                backslashes = 0;
            }
        }
        s.push_back(c);
    }
    s.push_back('"');
}

// http://msdn.microsoft.com/en-gb/library/windows/desktop/ms686335.aspx
static void
restartService(const char *lpServiceName)
{
    SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    assert(hSCManager);
    if (!hSCManager) {
        return;
    }

    SC_HANDLE hService = OpenServiceA(hSCManager, lpServiceName, SC_MANAGER_ALL_ACCESS);
    assert(hService);
    if (!hService) {
        return;
    }

    SERVICE_STATUS_PROCESS ssp;
    DWORD cbBytesNeeded;
    QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE) &ssp, sizeof ssp, &cbBytesNeeded);

    BOOL bRet;
    if (ssp.dwCurrentState == SERVICE_RUNNING) {
        bRet = ControlService(hService, SERVICE_CONTROL_STOP, (LPSERVICE_STATUS) &ssp);
        assert(bRet);
        while (ssp.dwCurrentState != SERVICE_STOPPED) {
            Sleep(ssp.dwWaitHint);
            QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE) &ssp, sizeof ssp, &cbBytesNeeded);
        }
        bRet = StartService(hService, 0, NULL);
        assert(bRet);
    }

    CloseServiceHandle(hService);
    CloseServiceHandle(hSCManager);
}

// Force DWM process to recreate all its Direct3D objects.
static void
restartDwmComposition(HANDLE hProcess)
{
    HRESULT hr;

    HMODULE hModule = LoadLibraryA("dwmapi");
    assert(hModule);
    if (!hModule) {
        return;
    }

    typedef HRESULT (WINAPI *PFNDWMISCOMPOSITIONENABLED)(BOOL *pfEnabled);
    PFNDWMISCOMPOSITIONENABLED pfnDwmIsCompositionEnabled = (PFNDWMISCOMPOSITIONENABLED)GetProcAddress(hModule, "DwmIsCompositionEnabled");
    assert(pfnDwmIsCompositionEnabled);
    if (!pfnDwmIsCompositionEnabled) {
        return;
    }

    typedef HRESULT (WINAPI *PFNDWMENABLECOMPOSITION)(UINT uCompositionAction);
    PFNDWMENABLECOMPOSITION pfnDwmEnableComposition = (PFNDWMENABLECOMPOSITION)GetProcAddress(hModule, "DwmEnableComposition");
    assert(pfnDwmEnableComposition);
    if (!pfnDwmEnableComposition) {
        return;
    }

    BOOL bIsWindows8OrGreater = IsWindows8OrGreater();
    if (bIsWindows8OrGreater) {
        // Windows 8 ignores DwmEnableComposition(DWM_EC_DISABLECOMPOSITION).
        // It is however possible to force DWM to restart by restarting the
        // display device via the devcon utility
        devconEnable(DEVCON_CLASS_DISPLAY);
    } else {

        BOOL fEnabled = FALSE;
        hr = pfnDwmIsCompositionEnabled(&fEnabled);
        if (FAILED(hr) || !fEnabled) {
            return;
        }

        fprintf(stderr, "info: restarting DWM composition\n");

        hr = pfnDwmEnableComposition(DWM_EC_DISABLECOMPOSITION);
        assert(SUCCEEDED(hr));
        if (FAILED(hr)) {
            return;
        }

        Sleep(1000/30);

        hr = pfnDwmEnableComposition(DWM_EC_ENABLECOMPOSITION);
        assert(SUCCEEDED(hr));
        (void)hr;
    }

    fprintf(stderr, "Press any key when finished tracing\n");
    getchar();

    DWORD dwExitCode;
    if (GetExitCodeProcess(hProcess, &dwExitCode) &&
        dwExitCode != STILL_ACTIVE) {
        // DWM process has already terminated
        return;
    }

    fprintf(stderr, "info: restarting DWM process\n");
    if (bIsWindows8OrGreater) {
        // From Windows 8 onwards DWM no longer runs as a service.  We just
        // kill it and winlogon parent process will respawn it.
        if (!TerminateProcess(hProcess, 0)) {
            logLastError("failed to terminate DWM process");
        }
    } else {
        hr = pfnDwmEnableComposition(DWM_EC_DISABLECOMPOSITION);
        assert(SUCCEEDED(hr));

        restartService("uxsms");
    }
}

BOOL
getProcessIdByName(const char *szProcessName, DWORD *pdwProcessID)
{
    BOOL bRet = FALSE;

    HANDLE hProcessSnap;
    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hProcessSnap != INVALID_HANDLE_VALUE) {
        PROCESSENTRY32 pe32;
        pe32.dwSize = sizeof pe32;
        if (Process32First(hProcessSnap, &pe32)) {
            do {
                if (stricmp(szProcessName, pe32.szExeFile) == 0) {
                    *pdwProcessID = pe32.th32ProcessID;
                    bRet = TRUE;
                    break;
                }
            } while (Process32Next(hProcessSnap, &pe32));
        }
        CloseHandle(hProcessSnap);
    }

    return bRet;
}

int
main(int argc, char *argv[])
{
    if (argc < 3) {
        fprintf(stderr,
                "usage:\n"
                "  inject <dllname.dll> <command> [args] ...\n"
                "  inject <dllname.dll> <process-id>\n"
                "  inject <dllname.dll> !<process-name>\n"
        );
        return 1;
    }

    BOOL bAttach = FALSE;
    DWORD dwProcessId = ~0;
    if (isdigit(argv[2][0])) {
        dwProcessId = atol(argv[2]);
        bAttach = TRUE;
    } else if (argv[2][0] == '!') {
        const char *szProcessName = &argv[2][1];
        if (!getProcessIdByName(szProcessName, &dwProcessId)) {
            fprintf(stderr, "error: failed to find process %s\n", szProcessName);
            return 1;
        }
        bAttach = TRUE;
        fprintf(stderr, "dwProcessId = %lu\n", dwProcessId);
    }

    HANDLE hSemaphore = NULL;
    const char *szDll = argv[1];
    if (!USE_SHARED_MEM) {
        SetEnvironmentVariableA("INJECT_DLL", szDll);
    } else {
        hSemaphore = CreateSemaphore(NULL, 1, 1, "inject_semaphore");
        if (hSemaphore == NULL) {
            fprintf(stderr, "error: failed to create semaphore\n");
            return 1;
        }

        DWORD dwWait = WaitForSingleObject(hSemaphore, 0);
        if (dwWait == WAIT_TIMEOUT) {
            fprintf(stderr, "info: waiting for another inject instance to finish\n");
            dwWait = WaitForSingleObject(hSemaphore, INFINITE);
        }
        if (dwWait != WAIT_OBJECT_0) {
            fprintf(stderr, "error: failed to enter semaphore gate\n");
            return 1;
        }

        SetSharedMem(szDll);
    }

    BOOL bAttachDwm = FALSE;
    PROCESS_INFORMATION processInfo;
    HANDLE hProcess;
    if (bAttach) {
        BOOL bRet;
        HANDLE hToken   = NULL;
        bRet = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken);
        if (!bRet) {
            fprintf(stderr, "error: OpenProcessToken returned %u\n", (unsigned)bRet);
            return 1;
        }

        LUID Luid;
        bRet = LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Luid);
        if (!bRet) {
            fprintf(stderr, "error: LookupPrivilegeValue returned %u\n", (unsigned)bRet);
            return 1;
        }

        TOKEN_PRIVILEGES tp;
        tp.PrivilegeCount = 1;
        tp.Privileges[0].Luid = Luid;
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        bRet = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof tp, NULL, NULL);
        if (!bRet) {
            fprintf(stderr, "error: AdjustTokenPrivileges returned %u\n", (unsigned)bRet);
            return 1;
        }

        DWORD dwDesiredAccess =
            PROCESS_CREATE_THREAD |
            PROCESS_QUERY_INFORMATION |
            PROCESS_QUERY_LIMITED_INFORMATION |
            PROCESS_VM_OPERATION |
            PROCESS_VM_WRITE |
            PROCESS_VM_READ |
            PROCESS_TERMINATE;
        hProcess = OpenProcess(
            dwDesiredAccess,
            FALSE /* bInheritHandle */,
            dwProcessId);
        if (!hProcess) {
            logLastError("failed to open process");
            return 1;
        }

        char szProcess[MAX_PATH];
        DWORD dwRet = GetModuleFileNameEx(hProcess, 0, szProcess, sizeof szProcess);
        assert(dwRet);
        if (dwRet &&
            stricmp(getBaseName(szProcess), "dwm.exe") == 0) {
            bAttachDwm = TRUE;
        }
    } else {
        std::string commandLine;
        char sep = 0;
        for (int i = 2; i < argc; ++i) {
            const char *arg = argv[i];

            if (sep) {
                commandLine.push_back(sep);
            }

            if (needsQuote(arg)) {
                quoteArg(commandLine, arg);
            } else {
                commandLine.append(arg);
            }

            sep = ' ';
        }

        STARTUPINFO startupInfo;
        memset(&startupInfo, 0, sizeof startupInfo);
        startupInfo.cb = sizeof startupInfo;

        // Create the process in suspended state
        if (!CreateProcessA(
               NULL,
               const_cast<char *>(commandLine.c_str()), // only modified by CreateProcessW
               0, // process attributes
               0, // thread attributes
               TRUE, // inherit handles
               CREATE_SUSPENDED,
               NULL, // environment
               NULL, // current directory
               &startupInfo,
               &processInfo)) {
            DWORD dwLastError = GetLastError();
            fprintf(stderr, "error: failed to execute %s (%lu)\n",
                    commandLine.c_str(), dwLastError);
            if (dwLastError == ERROR_ELEVATION_REQUIRED) {
                fprintf(stderr, "error: target program requires elevated priviledges and must be started from an Administrator Command Prompt, or UAC must be disabled\n");
            }
            return 1;
        }

        hProcess = processInfo.hProcess;
    }

    /*
     * XXX: Mixed architecture don't quite work.  See also
     * http://www.corsix.org/content/dll-injection-and-wow64
     */
    {
        typedef BOOL (WINAPI *PFNISWOW64PROCESS)(HANDLE, PBOOL);
        PFNISWOW64PROCESS pfnIsWow64Process;
        pfnIsWow64Process = (PFNISWOW64PROCESS)
            GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process");
        if (pfnIsWow64Process) {
            BOOL isParentWow64 = FALSE;
            BOOL isChildWow64 = FALSE;
            if (pfnIsWow64Process(GetCurrentProcess(), &isParentWow64) &&
                pfnIsWow64Process(hProcess, &isChildWow64) &&
                isParentWow64 != isChildWow64) {
                fprintf(stderr, "error: binaries mismatch: you need to use the "
#ifdef _WIN64
                        "32-bits"
#else
                        "64-bits"
#endif
                        " apitrace binaries to trace this application\n");
                TerminateProcess(hProcess, 1);
                return 1;
            }
        }
    }

    if (bAttachDwm && IsWindows8OrGreater()) {
        // Switch to Microsoft Basic Display Driver before injecting, so that
        // we don't trace with it.
        devconDisable(DEVCON_CLASS_DISPLAY);
        Sleep(1000);
    }

    const char *szDllName;
    szDllName = "injectee.dll";

    char szDllPath[MAX_PATH];
    GetModuleFileNameA(NULL, szDllPath, sizeof szDllPath);
    getDirName(szDllPath);
    strncat(szDllPath, szDllName, sizeof szDllPath - strlen(szDllPath) - 1);

#if 1
    if (!injectDll(hProcess, szDllPath)) {
        TerminateProcess(hProcess, 1);
        return 1;
    }
#endif

    DWORD exitCode;

    if (bAttach) {
        if (bAttachDwm) {
            restartDwmComposition(hProcess);
        }

        exitCode = 0;
    } else {
        // Start main process thread
        ResumeThread(processInfo.hThread);

        // Wait for it to finish
        WaitForSingleObject(hProcess, INFINITE);

        if (pSharedMem && !pSharedMem->bReplaced) {
            fprintf(stderr, "warning: %s was never used: application probably does not use this API\n", szDll);
        }

        exitCode = ~0;
        GetExitCodeProcess(hProcess, &exitCode);

        CloseHandle(processInfo.hThread);
    }

    CloseHandle(hProcess);

    if (hSemaphore) {
        ReleaseSemaphore(hSemaphore, 1, NULL);
        CloseHandle(hSemaphore);
    }

    return (int)exitCode;
}
<|endoftext|>