<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "liblocationwrapper_p.h"

using namespace std;

QTM_BEGIN_NAMESPACE

Q_GLOBAL_STATIC(LiblocationWrapper, LocationEngine)

LiblocationWrapper *LiblocationWrapper::instance()
{
    return LocationEngine();
}

LiblocationWrapper::~LiblocationWrapper()
{
    if (locationDevice)
        g_object_unref(locationDevice);
    if (locationControl)
        g_object_unref(locationControl);
}

bool LiblocationWrapper::inited()
{
    int retval = false;
    if (!(locationState & LiblocationWrapper::Inited)) {
        g_type_init();

        locationControl = location_gpsd_control_get_default();

        if (locationControl) {
            g_object_set(G_OBJECT(locationControl),
                         "preferred-method", LOCATION_METHOD_USER_SELECTED,
                         "preferred-interval", LOCATION_INTERVAL_1S,
                         NULL);
            locationDevice =
                    (LocationGPSDevice*)g_object_new(LOCATION_TYPE_GPS_DEVICE,
                                                     NULL);

            if (locationDevice) {
                errorHandlerId =
                    g_signal_connect(G_OBJECT(locationControl), "error-verbose",
                                     G_CALLBACK(&locationError),
                                     static_cast<void*>(this));
                posChangedId =
                    g_signal_connect(G_OBJECT(locationDevice), "changed",
                                     G_CALLBACK(&locationChanged),
                                     static_cast<void*>(this));
                locationState = LiblocationWrapper::Inited;
                retval = true;
                startcounter = 0;
            }
        }
    } else {
        retval = true;
    }
    return retval;
}

void LiblocationWrapper::locationError(LocationGPSDevice *device,
                                       gint errorCode, gpointer data)
{
    Q_UNUSED(device);
    QString locationError;

    switch (errorCode) {
    case LOCATION_ERROR_USER_REJECTED_DIALOG:
        locationError = "User didn't enable requested methods";
        break;
    case LOCATION_ERROR_USER_REJECTED_SETTINGS:
        locationError = "User changed settings, which disabled location.";
        break;
    case LOCATION_ERROR_BT_GPS_NOT_AVAILABLE:
        locationError = "Problems with BT GPS";
        break;
    case LOCATION_ERROR_METHOD_NOT_ALLOWED_IN_OFFLINE_MODE:
        locationError = "Requested method is not allowed in offline mode";
        break;
    case LOCATION_ERROR_SYSTEM:
        locationError = "System error.";
        break;
    default:
        locationError = "Unknown error.";
    }

    qDebug() << "Location error:" << locationError;

    LiblocationWrapper *object;
    object = (LiblocationWrapper *)data;
    emit object->error();
}

void LiblocationWrapper::locationChanged(LocationGPSDevice *device,
                                                 gpointer data)
{
    QGeoPositionInfo posInfo;
    QGeoCoordinate coordinate;
    QGeoSatelliteInfo satInfo;
    int satellitesInUseCount = 0;
    LiblocationWrapper *object;

    if (!data || !device) {
        return;
    }

    object = (LiblocationWrapper *)data;

    if (device) {
        if (device->fix) {
            if (device->fix->fields & LOCATION_GPS_DEVICE_TIME_SET) {
                posInfo.setTimestamp(QDateTime::fromTime_t(device->fix->time));
            }

            if (device->fix->fields & LOCATION_GPS_DEVICE_LATLONG_SET) {
                coordinate.setLatitude(device->fix->latitude);
                coordinate.setLongitude(device->fix->longitude);
                posInfo.setAttribute(QGeoPositionInfo::HorizontalAccuracy,
                                     device->fix->eph * 100);
                                     device->fix->eph / 100.0);
                posInfo.setAttribute(QGeoPositionInfo::VerticalAccuracy,
                                     device->fix->epv);
            }

            if (device->fix->fields & LOCATION_GPS_DEVICE_ALTITUDE_SET) {
                coordinate.setAltitude(device->fix->altitude);
            }

            if (device->fix->fields & LOCATION_GPS_DEVICE_SPEED_SET) {
                posInfo.setAttribute(QGeoPositionInfo::GroundSpeed,
                                     device->fix->speed);
            }

            if (device->fix->fields & LOCATION_GPS_DEVICE_CLIMB_SET) {
                posInfo.setAttribute(QGeoPositionInfo::VerticalSpeed,
                                     device->fix->climb);
            }

            if (device->fix->fields & LOCATION_GPS_DEVICE_TRACK_SET) {
                posInfo.setAttribute(QGeoPositionInfo::Direction,
                                     device->fix->track);
            }
        }

        if (device->satellites_in_view) {
            QList<QGeoSatelliteInfo> satsInView;
            QList<QGeoSatelliteInfo> satsInUse;
            unsigned int i;
            for (i=0;i<device->satellites->len;i++) {
                LocationGPSDeviceSatellite *satData =
                    (LocationGPSDeviceSatellite *)g_ptr_array_index(device->satellites,
                                                                    i);
                satInfo.setSignalStrength(satData->signal_strength);
                satInfo.setPrnNumber(satData->prn);
                satInfo.setAttribute(QGeoSatelliteInfo::Elevation,
                                     satData->elevation);
                satInfo.setAttribute(QGeoSatelliteInfo::Azimuth,
                                     satData->azimuth);

                satsInView.append(satInfo);
                if (satData->in_use) {
                    satellitesInUseCount++;
                    satsInUse.append(satInfo);
                }
            }

            if (!satsInView.isEmpty())
                object->satellitesInViewUpdated(satsInView);

            if (!satsInUse.isEmpty())
                object->satellitesInUseUpdated(satsInUse);
        }
    }

    posInfo.setCoordinate(coordinate);

    if ((device->fix->fields & LOCATION_GPS_DEVICE_TIME_SET) &&
        ((device->fix->mode == LOCATION_GPS_DEVICE_MODE_3D) ||
         (device->fix->mode == LOCATION_GPS_DEVICE_MODE_2D))) {
        object->setLocation(posInfo, true);
    } else {
        object->setLocation(posInfo, false);
    }
}

void LiblocationWrapper::setLocation(const QGeoPositionInfo &update,
                                     bool locationValid)
{
    validLastSatUpdate = locationValid;
    lastSatUpdate = update;
}

QGeoPositionInfo LiblocationWrapper::position() {
    return lastSatUpdate;
}

bool LiblocationWrapper::fixIsValid()
{
    return validLastSatUpdate;
}

QGeoPositionInfo LiblocationWrapper::lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const
{
    QGeoPositionInfo posInfo;
    QGeoCoordinate coordinate;
    double time;
    double latitude;
    double longitude;
    double altitude;
    double speed;
    double track;
    double climb;

    GConfItem lastKnownPositionTime("/system/nokia/location/lastknown/time");
    GConfItem lastKnownPositionLatitude("/system/nokia/location/lastknown/latitude");
    GConfItem lastKnownPositionLongitude("/system/nokia/location/lastknown/longitude");
    GConfItem lastKnownPositionAltitude("/system/nokia/location/lastknown/altitude");
    GConfItem lastKnownPositionSpeed("/system/nokia/location/lastknown/speed");
    GConfItem lastKnownPositionTrack("/system/nokia/location/lastknown/track");
    GConfItem lastKnownPositionClimb("/system/nokia/location/lastknown/climb");

    if (validLastSatUpdate)
        return lastSatUpdate;

    if (!fromSatellitePositioningMethodsOnly)
        if (validLastUpdate)
            return lastUpdate;

    time = lastKnownPositionTime.value().toDouble();
    latitude = lastKnownPositionLatitude.value().toDouble();
    longitude = lastKnownPositionLongitude.value().toDouble();
    altitude = lastKnownPositionAltitude.value().toDouble();
    speed = lastKnownPositionSpeed.value().toDouble();
    track = lastKnownPositionTrack.value().toDouble();
    climb = lastKnownPositionClimb.value().toDouble();

    if (longitude && latitude) {
        coordinate.setLongitude(longitude);
        coordinate.setLatitude(latitude);
        if (altitude) {
            coordinate.setAltitude(altitude);
        }
        posInfo.setCoordinate(coordinate);
    }

    if (speed) {
        posInfo.setAttribute(QGeoPositionInfo::GroundSpeed, speed);
    }

    if (track) {
        posInfo.setAttribute(QGeoPositionInfo::Direction, track);
    }

    if (climb) {
        posInfo.setAttribute(QGeoPositionInfo::VerticalSpeed, climb);
    }

    // Only positions with time (3D) are provided.
    if (time) {
        posInfo.setTimestamp(QDateTime::fromTime_t(time));
        return posInfo;
    }

    return QGeoPositionInfo();
}

void LiblocationWrapper::satellitesInViewUpdated(const QList<QGeoSatelliteInfo> &satellites)
{
    satsInView = satellites;
}

void LiblocationWrapper::satellitesInUseUpdated(const QList<QGeoSatelliteInfo> &satellites)
{
    satsInUse = satellites;
}

QList<QGeoSatelliteInfo> LiblocationWrapper::satellitesInView()
{
    return satsInView;
}

QList<QGeoSatelliteInfo> LiblocationWrapper::satellitesInUse()
{
    return satsInUse;
}

void LiblocationWrapper::start() {
    startcounter++;

    if ((locationState & LiblocationWrapper::Inited) &&
        !(locationState & LiblocationWrapper::Started)) {
        if (!errorHandlerId) {
            errorHandlerId =
                g_signal_connect(G_OBJECT(locationControl), "error-verbose",
                                 G_CALLBACK(&locationError),
                                 static_cast<void*>(this));
        }

        if (!posChangedId) {
            posChangedId =
                g_signal_connect(G_OBJECT(locationDevice), "changed",
                                 G_CALLBACK(&locationChanged),
                                 static_cast<void*>(this));
        }

        location_gpsd_control_start(locationControl);

        locationState |= LiblocationWrapper::Started;
        locationState &= ~LiblocationWrapper::Stopped;
    }
}

void LiblocationWrapper::stop() {
    startcounter--;

    if (startcounter > 0)
        return;

    if ((locationState & (LiblocationWrapper::Started |
                          LiblocationWrapper::Inited)) &&
        !(locationState & LiblocationWrapper::Stopped)) {
        if (errorHandlerId)
            g_signal_handler_disconnect(G_OBJECT(locationControl),
                                        errorHandlerId);
        if (posChangedId)
            g_signal_handler_disconnect(G_OBJECT(locationDevice),
                                        posChangedId);
        errorHandlerId = 0;
        posChangedId = 0;
        startcounter = 0;
        location_gpsd_control_stop(locationControl);

        locationState &= ~LiblocationWrapper::Started;
        locationState |= LiblocationWrapper::Stopped;
    }
}

bool LiblocationWrapper::isActive() {
    if (locationState & LiblocationWrapper::Started)
        return true;
    else
        return false;
}

#include "moc_liblocationwrapper_p.cpp"
QTM_END_NAMESPACE

<commit_msg>Attempt fo fix failed merge.<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "liblocationwrapper_p.h"

using namespace std;

QTM_BEGIN_NAMESPACE

Q_GLOBAL_STATIC(LiblocationWrapper, LocationEngine)

LiblocationWrapper *LiblocationWrapper::instance()
{
    return LocationEngine();
}

LiblocationWrapper::~LiblocationWrapper()
{
    if (locationDevice)
        g_object_unref(locationDevice);
    if (locationControl)
        g_object_unref(locationControl);
}

bool LiblocationWrapper::inited()
{
    int retval = false;
    if (!(locationState & LiblocationWrapper::Inited)) {
        g_type_init();

        locationControl = location_gpsd_control_get_default();

        if (locationControl) {
            g_object_set(G_OBJECT(locationControl),
                         "preferred-method", LOCATION_METHOD_USER_SELECTED,
                         "preferred-interval", LOCATION_INTERVAL_1S,
                         NULL);
            locationDevice =
                    (LocationGPSDevice*)g_object_new(LOCATION_TYPE_GPS_DEVICE,
                                                     NULL);

            if (locationDevice) {
                errorHandlerId =
                    g_signal_connect(G_OBJECT(locationControl), "error-verbose",
                                     G_CALLBACK(&locationError),
                                     static_cast<void*>(this));
                posChangedId =
                    g_signal_connect(G_OBJECT(locationDevice), "changed",
                                     G_CALLBACK(&locationChanged),
                                     static_cast<void*>(this));
                locationState = LiblocationWrapper::Inited;
                retval = true;
                startcounter = 0;
            }
        }
    } else {
        retval = true;
    }
    return retval;
}

void LiblocationWrapper::locationError(LocationGPSDevice *device,
                                       gint errorCode, gpointer data)
{
    Q_UNUSED(device);
    QString locationError;

    switch (errorCode) {
    case LOCATION_ERROR_USER_REJECTED_DIALOG:
        locationError = "User didn't enable requested methods";
        break;
    case LOCATION_ERROR_USER_REJECTED_SETTINGS:
        locationError = "User changed settings, which disabled location.";
        break;
    case LOCATION_ERROR_BT_GPS_NOT_AVAILABLE:
        locationError = "Problems with BT GPS";
        break;
    case LOCATION_ERROR_METHOD_NOT_ALLOWED_IN_OFFLINE_MODE:
        locationError = "Requested method is not allowed in offline mode";
        break;
    case LOCATION_ERROR_SYSTEM:
        locationError = "System error.";
        break;
    default:
        locationError = "Unknown error.";
    }

    qDebug() << "Location error:" << locationError;

    LiblocationWrapper *object;
    object = (LiblocationWrapper *)data;
    emit object->error();
}

void LiblocationWrapper::locationChanged(LocationGPSDevice *device,
                                                 gpointer data)
{
    QGeoPositionInfo posInfo;
    QGeoCoordinate coordinate;
    QGeoSatelliteInfo satInfo;
    int satellitesInUseCount = 0;
    LiblocationWrapper *object;

    if (!data || !device) {
        return;
    }

    object = (LiblocationWrapper *)data;

    if (device) {
        if (device->fix) {
            if (device->fix->fields & LOCATION_GPS_DEVICE_TIME_SET) {
                posInfo.setTimestamp(QDateTime::fromTime_t(device->fix->time));
            }

            if (device->fix->fields & LOCATION_GPS_DEVICE_LATLONG_SET) {
                coordinate.setLatitude(device->fix->latitude);
                coordinate.setLongitude(device->fix->longitude);
                posInfo.setAttribute(QGeoPositionInfo::HorizontalAccuracy,
                                     device->fix->eph / 100.0);
                posInfo.setAttribute(QGeoPositionInfo::VerticalAccuracy,
                                     device->fix->epv);
            }

            if (device->fix->fields & LOCATION_GPS_DEVICE_ALTITUDE_SET) {
                coordinate.setAltitude(device->fix->altitude);
            }

            if (device->fix->fields & LOCATION_GPS_DEVICE_SPEED_SET) {
                posInfo.setAttribute(QGeoPositionInfo::GroundSpeed,
                                     device->fix->speed);
            }

            if (device->fix->fields & LOCATION_GPS_DEVICE_CLIMB_SET) {
                posInfo.setAttribute(QGeoPositionInfo::VerticalSpeed,
                                     device->fix->climb);
            }

            if (device->fix->fields & LOCATION_GPS_DEVICE_TRACK_SET) {
                posInfo.setAttribute(QGeoPositionInfo::Direction,
                                     device->fix->track);
            }
        }

        if (device->satellites_in_view) {
            QList<QGeoSatelliteInfo> satsInView;
            QList<QGeoSatelliteInfo> satsInUse;
            unsigned int i;
            for (i=0;i<device->satellites->len;i++) {
                LocationGPSDeviceSatellite *satData =
                    (LocationGPSDeviceSatellite *)g_ptr_array_index(device->satellites,
                                                                    i);
                satInfo.setSignalStrength(satData->signal_strength);
                satInfo.setPrnNumber(satData->prn);
                satInfo.setAttribute(QGeoSatelliteInfo::Elevation,
                                     satData->elevation);
                satInfo.setAttribute(QGeoSatelliteInfo::Azimuth,
                                     satData->azimuth);

                satsInView.append(satInfo);
                if (satData->in_use) {
                    satellitesInUseCount++;
                    satsInUse.append(satInfo);
                }
            }

            if (!satsInView.isEmpty())
                object->satellitesInViewUpdated(satsInView);

            if (!satsInUse.isEmpty())
                object->satellitesInUseUpdated(satsInUse);
        }
    }

    posInfo.setCoordinate(coordinate);

    if ((device->fix->fields & LOCATION_GPS_DEVICE_TIME_SET) &&
        ((device->fix->mode == LOCATION_GPS_DEVICE_MODE_3D) ||
         (device->fix->mode == LOCATION_GPS_DEVICE_MODE_2D))) {
        object->setLocation(posInfo, true);
    } else {
        object->setLocation(posInfo, false);
    }
}

void LiblocationWrapper::setLocation(const QGeoPositionInfo &update,
                                     bool locationValid)
{
    validLastSatUpdate = locationValid;
    lastSatUpdate = update;
}

QGeoPositionInfo LiblocationWrapper::position() {
    return lastSatUpdate;
}

bool LiblocationWrapper::fixIsValid()
{
    return validLastSatUpdate;
}

QGeoPositionInfo LiblocationWrapper::lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const
{
    QGeoPositionInfo posInfo;
    QGeoCoordinate coordinate;
    double time;
    double latitude;
    double longitude;
    double altitude;
    double speed;
    double track;
    double climb;

    GConfItem lastKnownPositionTime("/system/nokia/location/lastknown/time");
    GConfItem lastKnownPositionLatitude("/system/nokia/location/lastknown/latitude");
    GConfItem lastKnownPositionLongitude("/system/nokia/location/lastknown/longitude");
    GConfItem lastKnownPositionAltitude("/system/nokia/location/lastknown/altitude");
    GConfItem lastKnownPositionSpeed("/system/nokia/location/lastknown/speed");
    GConfItem lastKnownPositionTrack("/system/nokia/location/lastknown/track");
    GConfItem lastKnownPositionClimb("/system/nokia/location/lastknown/climb");

    if (validLastSatUpdate)
        return lastSatUpdate;

    if (!fromSatellitePositioningMethodsOnly)
        if (validLastUpdate)
            return lastUpdate;

    time = lastKnownPositionTime.value().toDouble();
    latitude = lastKnownPositionLatitude.value().toDouble();
    longitude = lastKnownPositionLongitude.value().toDouble();
    altitude = lastKnownPositionAltitude.value().toDouble();
    speed = lastKnownPositionSpeed.value().toDouble();
    track = lastKnownPositionTrack.value().toDouble();
    climb = lastKnownPositionClimb.value().toDouble();

    if (longitude && latitude) {
        coordinate.setLongitude(longitude);
        coordinate.setLatitude(latitude);
        if (altitude) {
            coordinate.setAltitude(altitude);
        }
        posInfo.setCoordinate(coordinate);
    }

    if (speed) {
        posInfo.setAttribute(QGeoPositionInfo::GroundSpeed, speed);
    }

    if (track) {
        posInfo.setAttribute(QGeoPositionInfo::Direction, track);
    }

    if (climb) {
        posInfo.setAttribute(QGeoPositionInfo::VerticalSpeed, climb);
    }

    // Only positions with time (3D) are provided.
    if (time) {
        posInfo.setTimestamp(QDateTime::fromTime_t(time));
        return posInfo;
    }

    return QGeoPositionInfo();
}

void LiblocationWrapper::satellitesInViewUpdated(const QList<QGeoSatelliteInfo> &satellites)
{
    satsInView = satellites;
}

void LiblocationWrapper::satellitesInUseUpdated(const QList<QGeoSatelliteInfo> &satellites)
{
    satsInUse = satellites;
}

QList<QGeoSatelliteInfo> LiblocationWrapper::satellitesInView()
{
    return satsInView;
}

QList<QGeoSatelliteInfo> LiblocationWrapper::satellitesInUse()
{
    return satsInUse;
}

void LiblocationWrapper::start() {
    startcounter++;

    if ((locationState & LiblocationWrapper::Inited) &&
        !(locationState & LiblocationWrapper::Started)) {
        if (!errorHandlerId) {
            errorHandlerId =
                g_signal_connect(G_OBJECT(locationControl), "error-verbose",
                                 G_CALLBACK(&locationError),
                                 static_cast<void*>(this));
        }

        if (!posChangedId) {
            posChangedId =
                g_signal_connect(G_OBJECT(locationDevice), "changed",
                                 G_CALLBACK(&locationChanged),
                                 static_cast<void*>(this));
        }

        location_gpsd_control_start(locationControl);

        locationState |= LiblocationWrapper::Started;
        locationState &= ~LiblocationWrapper::Stopped;
    }
}

void LiblocationWrapper::stop() {
    startcounter--;

    if (startcounter > 0)
        return;

    if ((locationState & (LiblocationWrapper::Started |
                          LiblocationWrapper::Inited)) &&
        !(locationState & LiblocationWrapper::Stopped)) {
        if (errorHandlerId)
            g_signal_handler_disconnect(G_OBJECT(locationControl),
                                        errorHandlerId);
        if (posChangedId)
            g_signal_handler_disconnect(G_OBJECT(locationDevice),
                                        posChangedId);
        errorHandlerId = 0;
        posChangedId = 0;
        startcounter = 0;
        location_gpsd_control_stop(locationControl);

        locationState &= ~LiblocationWrapper::Started;
        locationState |= LiblocationWrapper::Stopped;
    }
}

bool LiblocationWrapper::isActive() {
    if (locationState & LiblocationWrapper::Started)
        return true;
    else
        return false;
}

#include "moc_liblocationwrapper_p.cpp"
QTM_END_NAMESPACE

<|endoftext|>


<commit_before>// Copyright (c) 2015, Karsten Heinze <karsten.heinze@sidenotes.de>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef SESAME_VERSION_HPP
#define SESAME_VERSION_HPP

#include <cstdint>

namespace sesame {

const uint32_t VERSION_MAJOR = 0;
const uint32_t VERSION_MINOR = 1;
const uint32_t VERSION_BUGFIX = 2;

namespace
{
   static const String getVersionString()
   {
      StringStream s;
      s << "Sesame ";
      s << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_BUGFIX;
      s << " - Copyright (c), 2015 Karsten Heinze";

      return s.str();
   }
}

static const String VERSION_STRING( getVersionString() );

}

#endif
<commit_msg>adjusted version<commit_after>// Copyright (c) 2015, Karsten Heinze <karsten.heinze@sidenotes.de>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef SESAME_VERSION_HPP
#define SESAME_VERSION_HPP

#include <cstdint>

namespace sesame {

const uint32_t VERSION_MAJOR = 0;
const uint32_t VERSION_MINOR = 1;
const uint32_t VERSION_BUGFIX = 3;

namespace
{
   static const String getVersionString()
   {
      StringStream s;
      s << "Sesame ";
      s << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_BUGFIX;
      s << " - Copyright (c), 2015 Karsten Heinze";

      return s.str();
   }
}

static const String VERSION_STRING( getVersionString() );

}

#endif
<|endoftext|>


<commit_before>/**
 * @copyright
 * ====================================================================
 * Copyright (c) 2003 CollabNet.  All rights reserved.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.  The terms
 * are also available at http://subversion.tigris.org/license-1.html.
 * If newer versions of this license are posted there, you may use a
 * newer version instead, at your option.
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://subversion.tigris.org/.
 * ====================================================================
 * @endcopyright
 *
 * @file Revision.cpp
 * @brief Implementation of the class Revision
 */

#include "Revision.h"
#include "org_tigris_subversion_javahl_Revision_Kind.h"
#include "JNIUtil.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
const svn_opt_revision_kind Revision::START = svn_opt_revision_unspecified;
const svn_opt_revision_kind Revision::HEAD = svn_opt_revision_head;

Revision::Revision (const svn_opt_revision_kind kind)
{
	m_revision.kind = kind;
	m_revision.value.number = 0;
}

Revision::Revision(jobject jthis, bool headIfUnspecified, bool oneIfUnspecified)
{
	if(jthis == NULL)
	{
		m_revision.kind = svn_opt_revision_unspecified;
		m_revision.value.number = 0;
	}
	else
	{
		JNIEnv *env = JNIUtil::getEnv();
		static jfieldID fid = 0;
		if(fid == 0)
		{
			jclass clazz = env->FindClass(JAVA_PACKAGE"/Revision");
			if(JNIUtil::isJavaExceptionThrown())
			{
				return;
			}
			fid = env->GetFieldID(clazz, "revKind", "I");
			if(JNIUtil::isJavaExceptionThrown())
			{
				return;
			}
			env->DeleteLocalRef(clazz);
			if(JNIUtil::isJavaExceptionThrown())
			{
				return;
			}
		}
		jint jKind = env->GetIntField(jthis, fid);
		if(JNIUtil::isJavaExceptionThrown())
		{
			return;
		}
		m_revision.value.number = 0;

		switch(jKind)
		{
		case org_tigris_subversion_javahl_Revision_Kind_unspecified:
			m_revision.kind = svn_opt_revision_unspecified;
			break;
		case org_tigris_subversion_javahl_Revision_Kind_number:
			m_revision.kind = svn_opt_revision_number;
			{
				static jfieldID fidNum = 0;
				if(fidNum == 0)
				{
					jclass clazz = env->FindClass(JAVA_PACKAGE"/Revision$Number");
					if(JNIUtil::isJavaExceptionThrown())
					{
						return;
					}
					fidNum = env->GetFieldID(clazz, "revNumber", "J");
					if(JNIUtil::isJavaExceptionThrown())
					{
						return;
					}
					env->DeleteLocalRef(clazz);
					if(JNIUtil::isJavaExceptionThrown())
					{
						return;
					}
				}
				jlong jNumber = env->GetLongField(jthis, fidNum);
				m_revision.value.number = jNumber;
			}
			break;
		case org_tigris_subversion_javahl_Revision_Kind_date:
			m_revision.kind = svn_opt_revision_date;
			{
				static jfieldID fidDate = 0;
				if(fidDate == 0)
				{
					jclass clazz = env->FindClass(JAVA_PACKAGE"/Revision$DateSpec");
					if(JNIUtil::isJavaExceptionThrown())
					{
						return;
					}
					fidDate = env->GetFieldID(clazz, "revDate", "Ljava/util/Date;");
					if(JNIUtil::isJavaExceptionThrown())
					{
						return;
					}
					env->DeleteLocalRef(clazz);
					if(JNIUtil::isJavaExceptionThrown())
					{
						return;
					}
				}
				jobject jDate = env->GetObjectField(jthis, fidDate);
				if(JNIUtil::isJavaExceptionThrown())
				{
					return;
				}

				static jmethodID mid = 0;
				if(mid == 0)
				{
					jclass clazz = env->FindClass("java/util/Date");
					if(JNIUtil::isJavaExceptionThrown())
					{
						return;
					}
					fid = env->GetFieldID(clazz, "getTime", "()J");
					if(JNIUtil::isJavaExceptionThrown())
					{
						return;
					}
					env->DeleteLocalRef(clazz);
					if(JNIUtil::isJavaExceptionThrown())
					{
						return;
					}
				}
				jlong jMillSec = env->CallLongMethod(jDate, mid);
				if(JNIUtil::isJavaExceptionThrown())
				{
					return;
				}
				env->DeleteLocalRef(jDate);
				if(JNIUtil::isJavaExceptionThrown())
				{
					return;
				}
				m_revision.value.date = jMillSec * 1000;
			}
			break;
		case org_tigris_subversion_javahl_Revision_Kind_committed:
			m_revision.kind = svn_opt_revision_committed;
			break;
		case org_tigris_subversion_javahl_Revision_Kind_previous:
			m_revision.kind = svn_opt_revision_previous;
			break;
		case org_tigris_subversion_javahl_Revision_Kind_base:
			m_revision.kind = svn_opt_revision_base;
			break;
		case org_tigris_subversion_javahl_Revision_Kind_working:
			m_revision.kind = svn_opt_revision_working;
			break;
		case org_tigris_subversion_javahl_Revision_Kind_head:
			m_revision.kind = svn_opt_revision_head;
			break;
		}
	}
	if(headIfUnspecified && m_revision.kind == svn_opt_revision_unspecified)
		m_revision.kind = svn_opt_revision_head;
	else if(oneIfUnspecified && m_revision.kind == svn_opt_revision_unspecified)
	{
		m_revision.kind = svn_opt_revision_number;
		m_revision.value.number = 1;
	}
}

Revision::~Revision()
{

}
const svn_opt_revision_t *Revision::revision () const
{
    return &m_revision;
}
<commit_msg> * Revision.cpp     (Revision::Revision)          Passing a Revision.DateSpec in javahl failed with           java.lang.NoSuchFieldError because java.util.Date.getTime() was           searched as a field when it is a method.<commit_after>/**
 * @copyright
 * ====================================================================
 * Copyright (c) 2003 CollabNet.  All rights reserved.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.  The terms
 * are also available at http://subversion.tigris.org/license-1.html.
 * If newer versions of this license are posted there, you may use a
 * newer version instead, at your option.
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://subversion.tigris.org/.
 * ====================================================================
 * @endcopyright
 *
 * @file Revision.cpp
 * @brief Implementation of the class Revision
 */

#include "Revision.h"
#include "org_tigris_subversion_javahl_Revision_Kind.h"
#include "JNIUtil.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
const svn_opt_revision_kind Revision::START = svn_opt_revision_unspecified;
const svn_opt_revision_kind Revision::HEAD = svn_opt_revision_head;

Revision::Revision (const svn_opt_revision_kind kind)
{
	m_revision.kind = kind;
	m_revision.value.number = 0;
}

Revision::Revision(jobject jthis, bool headIfUnspecified, bool oneIfUnspecified)
{
	if(jthis == NULL)
	{
		m_revision.kind = svn_opt_revision_unspecified;
		m_revision.value.number = 0;
	}
	else
	{
		JNIEnv *env = JNIUtil::getEnv();
		static jfieldID fid = 0;
		if(fid == 0)
		{
			jclass clazz = env->FindClass(JAVA_PACKAGE"/Revision");
			if(JNIUtil::isJavaExceptionThrown())
			{
				return;
			}
			fid = env->GetFieldID(clazz, "revKind", "I");
			if(JNIUtil::isJavaExceptionThrown())
			{
				return;
			}
			env->DeleteLocalRef(clazz);
			if(JNIUtil::isJavaExceptionThrown())
			{
				return;
			}
		}
		jint jKind = env->GetIntField(jthis, fid);
		if(JNIUtil::isJavaExceptionThrown())
		{
			return;
		}
		m_revision.value.number = 0;

		switch(jKind)
		{
		case org_tigris_subversion_javahl_Revision_Kind_unspecified:
			m_revision.kind = svn_opt_revision_unspecified;
			break;
		case org_tigris_subversion_javahl_Revision_Kind_number:
			m_revision.kind = svn_opt_revision_number;
			{
				static jfieldID fidNum = 0;
				if(fidNum == 0)
				{
					jclass clazz = env->FindClass(JAVA_PACKAGE"/Revision$Number");
					if(JNIUtil::isJavaExceptionThrown())
					{
						return;
					}
					fidNum = env->GetFieldID(clazz, "revNumber", "J");
					if(JNIUtil::isJavaExceptionThrown())
					{
						return;
					}
					env->DeleteLocalRef(clazz);
					if(JNIUtil::isJavaExceptionThrown())
					{
						return;
					}
				}
				jlong jNumber = env->GetLongField(jthis, fidNum);
				m_revision.value.number = jNumber;
			}
			break;
		case org_tigris_subversion_javahl_Revision_Kind_date:
			m_revision.kind = svn_opt_revision_date;
			{
				static jfieldID fidDate = 0;
				if(fidDate == 0)
				{
					jclass clazz = env->FindClass(JAVA_PACKAGE"/Revision$DateSpec");
					if(JNIUtil::isJavaExceptionThrown())
					{
						return;
					}
					fidDate = env->GetFieldID(clazz, "revDate", "Ljava/util/Date;");
					if(JNIUtil::isJavaExceptionThrown())
					{
						return;
					}
					env->DeleteLocalRef(clazz);
					if(JNIUtil::isJavaExceptionThrown())
					{
						return;
					}
				}
				jobject jDate = env->GetObjectField(jthis, fidDate);
				if(JNIUtil::isJavaExceptionThrown())
				{
					return;
				}

				static jmethodID mid = 0;
				if(mid == 0)
				{
					jclass clazz = env->FindClass("java/util/Date");
					if(JNIUtil::isJavaExceptionThrown())
					{
						return;
					}
					mid = env->GetMethodID(clazz, "getTime", "()J");
					if(JNIUtil::isJavaExceptionThrown())
					{
						return;
					}
					env->DeleteLocalRef(clazz);
					if(JNIUtil::isJavaExceptionThrown())
					{
						return;
					}
				}
				jlong jMillSec = env->CallLongMethod(jDate, mid);
				if(JNIUtil::isJavaExceptionThrown())
				{
					return;
				}
				env->DeleteLocalRef(jDate);
				if(JNIUtil::isJavaExceptionThrown())
				{
					return;
				}
				m_revision.value.date = jMillSec * 1000;
			}
			break;
		case org_tigris_subversion_javahl_Revision_Kind_committed:
			m_revision.kind = svn_opt_revision_committed;
			break;
		case org_tigris_subversion_javahl_Revision_Kind_previous:
			m_revision.kind = svn_opt_revision_previous;
			break;
		case org_tigris_subversion_javahl_Revision_Kind_base:
			m_revision.kind = svn_opt_revision_base;
			break;
		case org_tigris_subversion_javahl_Revision_Kind_working:
			m_revision.kind = svn_opt_revision_working;
			break;
		case org_tigris_subversion_javahl_Revision_Kind_head:
			m_revision.kind = svn_opt_revision_head;
			break;
		}
	}
	if(headIfUnspecified && m_revision.kind == svn_opt_revision_unspecified)
		m_revision.kind = svn_opt_revision_head;
	else if(oneIfUnspecified && m_revision.kind == svn_opt_revision_unspecified)
	{
		m_revision.kind = svn_opt_revision_number;
		m_revision.value.number = 1;
	}
}

Revision::~Revision()
{

}
const svn_opt_revision_t *Revision::revision () const
{
    return &m_revision;
}
<|endoftext|>


<commit_before>/***********************************************************************************************************************
*                                                                                *
* SPLASH build system v0.2                                                                                *
*                                                                                *
* Copyright (c) 2016 Andrew D. Zonenberg                                                                               *
* All rights reserved.                                                                                *
*                                                                                *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the     *
* following conditions are met:                                                                                *
*                                                                                *
*    * Redistributions of source code must retain the above copyright notice, this list of conditions, and the         *
*      following disclaimer.                                                                                *
*                                                                                *
*    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the       *
*      following disclaimer in the documentation and/or other materials provided with the distribution.                *
*                                                                                *
*    * Neither the name of the author nor the names of any contributors may be used to endorse or promote products     *
*      derived from this software without specific prior written permission.                                           *
*                                                                                *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES        *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR       *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE       *
* POSSIBILITY OF SUCH DAMAGE.                                                                                *
*                                                                                *
***********************************************************************************************************************/

#include "splashdev.h"

using namespace std;

void ShowUsage();
void ShowVersion();

/**
	@brief Program entry point
 */
int main(int argc, char* argv[])
{
	string source_dir;
	string ctl_server;

	LogSink::Severity console_verbosity = LogSink::NOTICE;

	//Parse command-line arguments
	for(int i=1; i<argc; i++)
	{
		string s(argv[i]);

		//Let the logger eat its args first
		if(ParseLoggerArguments(i, argc, argv, console_verbosity))
			continue;

		else if(s == "--help")
		{
			ShowUsage();
			return 0;
		}

		else if(s == "--version")
		{
			ShowVersion();
			return 0;
		}

		//Last two args without switches are source dir and control server.
		//TODO: mandatory arguments to introduce these?
		else if(source_dir == "")
			source_dir = argv[i];

		else
			ctl_server = argv[i];

	}

	//Set up logging
	g_log_sinks.emplace(g_log_sinks.begin(), new STDLogSink(console_verbosity));

	//Print header
	if(console_verbosity >= LogSink::NOTICE)
	{
		ShowVersion();
		printf("\n");
	}

	//Open the source directory and start an inotify watcher on it and all subdirectories
	source_dir = CanonicalizePath(source_dir);
	int hnotify = inotify_init();
	if(hnotify < 0)
		LogFatal("Couldn't start inotify\n");
	LogNotice("Running on directory: %s\n", source_dir.c_str());
	WatchDirRecursively(hnotify, source_dir);

	//TODO: signal handler so we can quit gracefully

	//Main event loop
	size_t buflen = 8192;
	char ebuf[buflen];
	while(1)
	{
		//Get the event
		size_t len = read(hnotify, ebuf, buflen);
		if(len <= 0)
			break;

		size_t offset = 0;
		while(offset < len)
		{
			inotify_event* evt = reinterpret_cast<inotify_event*>(ebuf + offset);

			//Skip events without a filename, or hidden files
			if( (evt->len != 0) && (evt->name[0] != '.') )
				WatchedFileChanged(evt->mask, CanonicalizePath(source_dir + "/" + evt->name));

			//Go on to the next one
			offset += sizeof(inotify_event) + evt->len;
		}
	}

	//Done
	close(hnotify);
	return 0;
}

/**
	@brief Add watches to a directory *and* all subdirectories
 */
void WatchDirRecursively(int hnotify, string dir)
{
	LogDebug("    Recursively watching directory %s\n", dir.c_str());

	//Watch changes to the directory
	if(0 > inotify_add_watch(
		hnotify,
		dir.c_str(),
		IN_CREATE | IN_DELETE | IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE_SELF))
	{
		LogFatal("Failed to watch directory %s\n", dir.c_str());
	}

	//Look for any subdirs and watch them
	vector<string> subdirs;
	FindSubdirs(dir, subdirs);
	for(auto s : subdirs)
		WatchDirRecursively(hnotify, s);
}

void ShowVersion()
{
	printf(
		"SPLASH build system developer daemon by Andrew D. Zonenberg.\n"
		"\n"
		"License: 3-clause BSD\n"
		"This is free software: you are free to change and redistribute it.\n"
		"There is NO WARRANTY, to the extent permitted by law.\n");
}

void ShowUsage()
{
	printf("Usage: splashdev srcdir ctlserver\n");
	exit(0);
}
<commit_msg>splashdev: Rephrased log message<commit_after>/***********************************************************************************************************************
*                                                                                *
* SPLASH build system v0.2                                                                                *
*                                                                                *
* Copyright (c) 2016 Andrew D. Zonenberg                                                                               *
* All rights reserved.                                                                                *
*                                                                                *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the     *
* following conditions are met:                                                                                *
*                                                                                *
*    * Redistributions of source code must retain the above copyright notice, this list of conditions, and the         *
*      following disclaimer.                                                                                *
*                                                                                *
*    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the       *
*      following disclaimer in the documentation and/or other materials provided with the distribution.                *
*                                                                                *
*    * Neither the name of the author nor the names of any contributors may be used to endorse or promote products     *
*      derived from this software without specific prior written permission.                                           *
*                                                                                *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES        *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR       *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE       *
* POSSIBILITY OF SUCH DAMAGE.                                                                                *
*                                                                                *
***********************************************************************************************************************/

#include "splashdev.h"

using namespace std;

void ShowUsage();
void ShowVersion();

/**
	@brief Program entry point
 */
int main(int argc, char* argv[])
{
	string source_dir;
	string ctl_server;

	LogSink::Severity console_verbosity = LogSink::NOTICE;

	//Parse command-line arguments
	for(int i=1; i<argc; i++)
	{
		string s(argv[i]);

		//Let the logger eat its args first
		if(ParseLoggerArguments(i, argc, argv, console_verbosity))
			continue;

		else if(s == "--help")
		{
			ShowUsage();
			return 0;
		}

		else if(s == "--version")
		{
			ShowVersion();
			return 0;
		}

		//Last two args without switches are source dir and control server.
		//TODO: mandatory arguments to introduce these?
		else if(source_dir == "")
			source_dir = argv[i];

		else
			ctl_server = argv[i];

	}

	//Set up logging
	g_log_sinks.emplace(g_log_sinks.begin(), new STDLogSink(console_verbosity));

	//Print header
	if(console_verbosity >= LogSink::NOTICE)
	{
		ShowVersion();
		printf("\n");
	}

	//Open the source directory and start an inotify watcher on it and all subdirectories
	source_dir = CanonicalizePath(source_dir);
	int hnotify = inotify_init();
	if(hnotify < 0)
		LogFatal("Couldn't start inotify\n");
	LogNotice("Working copy root directory: %s\n", source_dir.c_str());
	WatchDirRecursively(hnotify, source_dir);

	//TODO: signal handler so we can quit gracefully

	//Main event loop
	size_t buflen = 8192;
	char ebuf[buflen];
	while(1)
	{
		//Get the event
		size_t len = read(hnotify, ebuf, buflen);
		if(len <= 0)
			break;

		size_t offset = 0;
		while(offset < len)
		{
			inotify_event* evt = reinterpret_cast<inotify_event*>(ebuf + offset);

			//Skip events without a filename, or hidden files
			if( (evt->len != 0) && (evt->name[0] != '.') )
				WatchedFileChanged(evt->mask, CanonicalizePath(source_dir + "/" + evt->name));

			//Go on to the next one
			offset += sizeof(inotify_event) + evt->len;
		}
	}

	//Done
	close(hnotify);
	return 0;
}

/**
	@brief Add watches to a directory *and* all subdirectories
 */
void WatchDirRecursively(int hnotify, string dir)
{
	LogDebug("    Recursively watching directory %s\n", dir.c_str());

	//Watch changes to the directory
	if(0 > inotify_add_watch(
		hnotify,
		dir.c_str(),
		IN_CREATE | IN_DELETE | IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE_SELF))
	{
		LogFatal("Failed to watch directory %s\n", dir.c_str());
	}

	//Look for any subdirs and watch them
	vector<string> subdirs;
	FindSubdirs(dir, subdirs);
	for(auto s : subdirs)
		WatchDirRecursively(hnotify, s);
}

void ShowVersion()
{
	printf(
		"SPLASH build system developer daemon by Andrew D. Zonenberg.\n"
		"\n"
		"License: 3-clause BSD\n"
		"This is free software: you are free to change and redistribute it.\n"
		"There is NO WARRANTY, to the extent permitted by law.\n");
}

void ShowUsage()
{
	printf("Usage: splashdev srcdir ctlserver\n");
	exit(0);
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/sys/vfs/vfs_main.C $                                      */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2010,2020                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#include <string.h>
#include <errno.h>

#include <sys/msg.h>
#include <sys/vfs.h>
#include <sys/task.h>
#include <sys/sync.h>

#include <util/locked/list.H>
#include <kernel/console.H>  // TODO : Remove this.

const char* VFS_ROOT = "/";
const char* VFS_ROOT_BIN = "/bin/";
const char* VFS_ROOT_DATA = "/data/";
const char* VFS_ROOT_MSG = "/msg/";
const char* VFS_ROOT_MSG_VFS = "/msg/vfs";
const char* VFS_ROOT_MSG_MBOX = "/msg/mbox";
const char* VFS_ROOT_MSG_MCTP_IN = "/msg/mctpin";
const char* VFS_ROOT_MSG_MCTP_OUT = "/msg/mctpout";
const char* VFS_ROOT_MSG_PLDM_REQ_IN = "/msg/pldmreqin";
const char* VFS_ROOT_MSG_PLDM_RSP_IN = "/msg/pldmrspin";
const char* VFS_ROOT_MSG_PLDM_REQ_OUT= "/msg/pldrreqout";

void vfs_module_init();

struct VfsPath
{
    char key[64];

    bool operator!=(VfsPath& r) { return 0 != strcmp(key, r.key); };
};

struct VfsEntry
{
    typedef VfsPath key_type;
    key_type key;
    msg_q_t msg_q;

    VfsEntry* next;
    VfsEntry* prev;
};

void* vfs_main(void* i_barrier)
{
    // Detach this task from the parent
    task_detach();

    barrier_t * barrier = (barrier_t *)i_barrier;
    // Create message queue, register with kernel.
    msg_q_t vfsMsgQ = msg_q_create();
    msg_q_register(vfsMsgQ, VFS_ROOT);

    printk("done.\n");

    // Initalize modules.
    vfs_module_init();

    // Signal with sys/init to continue on.
    barrier_wait(barrier);

    Util::Locked::List<VfsEntry, VfsEntry::key_type> vfsContents;

    while(1)
    {
        msg_t* msg = msg_wait(vfsMsgQ);

        switch(msg->type)
        {
            case VFS_MSG_REGISTER_MSGQ:
                {
                    VfsEntry* e = new VfsEntry();
                    strcpy(e->key.key, (char*) msg->extra_data);
                    e->msg_q = (msg_q_t) msg->data[0];
                    vfsContents.insert(e);

                    printkd("VFS: Registering %p as %s\n",
                            e->msg_q, e->key.key);
                    msg_respond(vfsMsgQ, msg);
                }
                break;

            case VFS_MSG_REMOVE_MSGQ:
                {
                    VfsEntry::key_type k;
                    strcpy(k.key, (char*) msg->extra_data);
                    VfsEntry* e = vfsContents.find(k);
                    if(NULL != e)
                    {
                        msg->data[0] = 0; //(uint64_t) e->msg_q;
                        printkd("VFS: Removing msg queue %s\n",e->key.key);
                        vfsContents.erase(e);
                        delete e;
                    }
                    else
                    {
                        msg->data[0] = (uint64_t) (-ENXIO);
                    }
                    msg_respond(vfsMsgQ, msg);
                }
                break;

            case VFS_MSG_RESOLVE_MSGQ:
                {
                    VfsEntry::key_type k;
                    strcpy(k.key, (char*) msg->extra_data);
                    VfsEntry* e = vfsContents.find(k);
                    if (NULL == e)
                        msg->data[0] = (uint64_t) NULL;
                    else
                        msg->data[0] = (uint64_t) e->msg_q;
                    msg_respond(vfsMsgQ, msg);
                }
                break;

            case VFS_MSG_EXEC:
                {
                    printkd("VFS: Got exec request of %s\n",
                            (const char*)msg->data[0]);

                    VfsSystemModule* module =
                        vfs_find_module(VFS_MODULES,
                                        (const char *) msg->data[0]);

                    void* fnptr = vfs_start_entrypoint(module);

                    // child == -ENOENT means module not found in base image
                    // so send a message to VFS_MSG queue to look in the
                    // extended image VFS_MSG queue will handle the
                    // msg_respond()
                    if( fnptr == reinterpret_cast<void*>(-ENOENT) )
                        // forward msg to usr vfs
                    {
                        VfsEntry::key_type k;
                        strcpy(k.key, VFS_ROOT_MSG_VFS);
                        VfsEntry* e = vfsContents.find(k);
                        if(e != NULL)
                        {
                            msg_t* emsg = msg_allocate();
                            emsg->type = msg->type;
                            emsg->data[0] = (uint64_t) msg;
                            emsg->data[1] = (uint64_t) vfsMsgQ;
                            msg_send(e->msg_q, emsg); // send async msg
                        }
                        else  // Can't find VFS_MSG queue - not started yet
                        {
                            msg->data[0] = (uint64_t) fnptr;
                            msg_respond(vfsMsgQ, msg);
                        }
                    }
                    else // send back child (or errno)
                    {
                        msg->data[0] = (uint64_t) fnptr;
                        msg_respond(vfsMsgQ, msg);
                    }
                }
                break;

            default:
                msg_free(msg);
                break;
        }
    }   // end while(1)
    return NULL;
}

// ----------------------------------------------------------------------------

void* vfs_start_entrypoint(VfsSystemModule * i_module)
{
    void* ptr = reinterpret_cast<void*>(-ENOENT);
    if(i_module != NULL)
    {
        if (i_module->start == NULL)
        {
            // module has no start() routine
            ptr = reinterpret_cast<void*>(-ENOEXEC);
        }
        else
        {
            ptr = reinterpret_cast<void*>(i_module->start);
        }
    }
    return ptr;
}
<commit_msg>Update vfs_main.C<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/sys/vfs/vfs_main.C $                                      */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2010,2021                        */
/* [+] International Business Machines Corp.                              */
/* [+] dongshijiang                                                       */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#include <string.h>
#include <errno.h>

#include <sys/msg.h>
#include <sys/vfs.h>
#include <sys/task.h>
#include <sys/sync.h>

#include <util/locked/list.H>
#include <kernel/console.H>  // TODO : Remove this.

const char* VFS_ROOT = "/";
const char* VFS_ROOT_BIN = "/bin/";
const char* VFS_ROOT_DATA = "/data/";
const char* VFS_ROOT_MSG = "/msg/";
const char* VFS_ROOT_MSG_VFS = "/msg/vfs";
const char* VFS_ROOT_MSG_MBOX = "/msg/mbox";
const char* VFS_ROOT_MSG_MCTP_IN = "/msg/mctpin";
const char* VFS_ROOT_MSG_MCTP_OUT = "/msg/mctpout";
const char* VFS_ROOT_MSG_PLDM_REQ_IN = "/msg/pldmreqin";
const char* VFS_ROOT_MSG_PLDM_RSP_IN = "/msg/pldmrspin";
const char* VFS_ROOT_MSG_PLDM_REQ_OUT= "/msg/pldmreqout";

void vfs_module_init();

struct VfsPath
{
    char key[64];

    bool operator!=(VfsPath& r) { return 0 != strcmp(key, r.key); };
};

struct VfsEntry
{
    typedef VfsPath key_type;
    key_type key;
    msg_q_t msg_q;

    VfsEntry* next;
    VfsEntry* prev;
};

void* vfs_main(void* i_barrier)
{
    // Detach this task from the parent
    task_detach();

    barrier_t * barrier = (barrier_t *)i_barrier;
    // Create message queue, register with kernel.
    msg_q_t vfsMsgQ = msg_q_create();
    msg_q_register(vfsMsgQ, VFS_ROOT);

    printk("done.\n");

    // Initalize modules.
    vfs_module_init();

    // Signal with sys/init to continue on.
    barrier_wait(barrier);

    Util::Locked::List<VfsEntry, VfsEntry::key_type> vfsContents;

    while(1)
    {
        msg_t* msg = msg_wait(vfsMsgQ);

        switch(msg->type)
        {
            case VFS_MSG_REGISTER_MSGQ:
                {
                    VfsEntry* e = new VfsEntry();
                    strcpy(e->key.key, (char*) msg->extra_data);
                    e->msg_q = (msg_q_t) msg->data[0];
                    vfsContents.insert(e);

                    printkd("VFS: Registering %p as %s\n",
                            e->msg_q, e->key.key);
                    msg_respond(vfsMsgQ, msg);
                }
                break;

            case VFS_MSG_REMOVE_MSGQ:
                {
                    VfsEntry::key_type k;
                    strcpy(k.key, (char*) msg->extra_data);
                    VfsEntry* e = vfsContents.find(k);
                    if(NULL != e)
                    {
                        msg->data[0] = 0; //(uint64_t) e->msg_q;
                        printkd("VFS: Removing msg queue %s\n",e->key.key);
                        vfsContents.erase(e);
                        delete e;
                    }
                    else
                    {
                        msg->data[0] = (uint64_t) (-ENXIO);
                    }
                    msg_respond(vfsMsgQ, msg);
                }
                break;

            case VFS_MSG_RESOLVE_MSGQ:
                {
                    VfsEntry::key_type k;
                    strcpy(k.key, (char*) msg->extra_data);
                    VfsEntry* e = vfsContents.find(k);
                    if (NULL == e)
                        msg->data[0] = (uint64_t) NULL;
                    else
                        msg->data[0] = (uint64_t) e->msg_q;
                    msg_respond(vfsMsgQ, msg);
                }
                break;

            case VFS_MSG_EXEC:
                {
                    printkd("VFS: Got exec request of %s\n",
                            (const char*)msg->data[0]);

                    VfsSystemModule* module =
                        vfs_find_module(VFS_MODULES,
                                        (const char *) msg->data[0]);

                    void* fnptr = vfs_start_entrypoint(module);

                    // child == -ENOENT means module not found in base image
                    // so send a message to VFS_MSG queue to look in the
                    // extended image VFS_MSG queue will handle the
                    // msg_respond()
                    if( fnptr == reinterpret_cast<void*>(-ENOENT) )
                        // forward msg to usr vfs
                    {
                        VfsEntry::key_type k;
                        strcpy(k.key, VFS_ROOT_MSG_VFS);
                        VfsEntry* e = vfsContents.find(k);
                        if(e != NULL)
                        {
                            msg_t* emsg = msg_allocate();
                            emsg->type = msg->type;
                            emsg->data[0] = (uint64_t) msg;
                            emsg->data[1] = (uint64_t) vfsMsgQ;
                            msg_send(e->msg_q, emsg); // send async msg
                        }
                        else  // Can't find VFS_MSG queue - not started yet
                        {
                            msg->data[0] = (uint64_t) fnptr;
                            msg_respond(vfsMsgQ, msg);
                        }
                    }
                    else // send back child (or errno)
                    {
                        msg->data[0] = (uint64_t) fnptr;
                        msg_respond(vfsMsgQ, msg);
                    }
                }
                break;

            default:
                msg_free(msg);
                break;
        }
    }   // end while(1)
    return NULL;
}

// ----------------------------------------------------------------------------

void* vfs_start_entrypoint(VfsSystemModule * i_module)
{
    void* ptr = reinterpret_cast<void*>(-ENOENT);
    if(i_module != NULL)
    {
        if (i_module->start == NULL)
        {
            // module has no start() routine
            ptr = reinterpret_cast<void*>(-ENOEXEC);
        }
        else
        {
            ptr = reinterpret_cast<void*>(i_module->start);
        }
    }
    return ptr;
}
<|endoftext|>


<commit_before>#include "globals.h"
#include "syscalls.h"

#define LINUX_FUTEX_WAIT              0
#define LINUX_FUTEX_WAKE              1
#define LINUX_FUTEX_FD                2
#define LINUX_FUTEX_REQUEUE           3
#define LINUX_FUTEX_CMP_REQUEUE       4
#define LINUX_FUTEX_WAKE_OP           5
#define LINUX_FUTEX_LOCK_PI           6
#define LINUX_FUTEX_UNLOCK_PI         7
#define LINUX_FUTEX_TRYLOCK_PI        8
#define LINUX_FUTEX_WAIT_BITSET       9
#define LINUX_FUTEX_WAKE_BITSET       10

#define LINUX_FUTEX_PRIVATE_FLAG      128
#define LINUX_FUTEX_CMD_MASK          ~LINUX_FUTEX_PRIVATE_FLAG

#define LINUX_FUTEX_WAIT_PRIVATE      (LINUX_FUTEX_WAIT | LINUX_FUTEX_PRIVATE_FLAG)
#define LINUX_FUTEX_WAKE_PRIVATE      (LINUX_FUTEX_WAKE | LINUX_FUTEX_PRIVATE_FLAG)
#define LINUX_FUTEX_REQUEUE_PRIVATE   (LINUX_FUTEX_REQUEUE | LINUX_FUTEX_PRIVATE_FLAG)
#define LINUX_FUTEX_CMP_REQUEUE_PRIVATE (LINUX_FUTEX_CMP_REQUEUE | LINUX_FUTEX_PRIVATE_FLAG)
#define LINUX_FUTEX_WAKE_OP_PRIVATE   (LINUX_FUTEX_WAKE_OP | LINUX_FUTEX_PRIVATE_FLAG)
#define LINUX_FUTEX_LOCK_PI_PRIVATE   (LINUX_FUTEX_LOCK_PI | LINUX_FUTEX_PRIVATE_FLAG)
#define LINUX_FUTEX_UNLOCK_PI_PRIVATE (LINUX_FUTEX_UNLOCK_PI | LINUX_FUTEX_PRIVATE_FLAG)
#define LINUX_FUTEX_TRYLOCK_PI_PRIVATE (LINUX_FUTEX_TRYLOCK_PI | LINUX_FUTEX_PRIVATE_FLAG)
#define LINUX_FUTEX_WAIT_BITSET_PRIVATE       (LINUX_FUTEX_WAIT_BITS | LINUX_FUTEX_PRIVATE_FLAG)
#define LINUX_FUTEX_WAKE_BITSET_PRIVATE       (LINUX_FUTEX_WAKE_BITS | LINUX_FUTEX_PRIVATE_FLAG)

struct linux_user_desc {
	int  entry_number;
	unsigned int  base_addr;
	unsigned int  limit;
	unsigned int  seg_32bit:1;
	unsigned int  contents:2;
	unsigned int  read_exec_only:1;
	unsigned int  limit_in_pages:1;
	unsigned int  seg_not_present:1;
	unsigned int  useable:1;
};

static pthread_mutex_t tlsmutex = PTHREAD_MUTEX_INITIALIZER;

typedef u_int32_t DWORD;
typedef u_int32_t ULONG;
typedef u_int16_t WORD;
typedef u_int8_t BYTE;

#pragma pack(push)
struct LDT_ENTRY {
		WORD LimitLow;
		WORD BaseLow;
		union {
				struct {
						BYTE BaseMid;
						BYTE Flags1;
						BYTE Flags2;
						BYTE BaseHi;
				} Bytes;
				struct {
						DWORD BaseMid:8;
						DWORD Type:5;
						DWORD Dpl:2;
						DWORD Pres:1;
						DWORD LimitHi:4;
						DWORD Sys:1;
						DWORD Reserved_0:1;
						DWORD Default_Big:1;
						DWORD Granularity:1;
						DWORD BaseHi:8;
				} Bits;
		} HighWord;
};
#pragma pack(pop)

extern "C" u_int32_t __stdcall NtSetLdtEntries(
	/*IN*/ ULONG  Selector1,
	/*IN*/ LDT_ENTRY  LdtEntry1,
	/*IN*/ ULONG  Selector2,
	/*IN*/ LDT_ENTRY  LdtEntry2);
asm ("_NtSetLdtEntries: jmp _NtSetLdtEntries@24");

extern "C" u_int32_t __stdcall NtQueryInformationProcess(
  /*IN*/ int32_t ProcessHandle,
  /*IN*/ int32_t ProcessInformationClass,
  /*OUT*/ void* ProcessInformation,
  /*IN*/ u_int32_t ProcessInformationLength,
  /*OUT*/ u_int32_t* ReturnLength  /*OPTIONAL*/);
asm ("_NtQueryInformationProcess: jmp _NtQueryInformationProcess@20");

extern "C" u_int32_t __stdcall NtSetInformationProcess(
  /*IN*/ int32_t ProcessHandle,
  /*IN*/ int32_t ProcessInformationClass,
  /*IN*/ void* ProcessInformation,
  /*IN*/ u_int32_t ProcessInformationLength);
asm ("_NtSetInformationProcess: jmp _NtSetInformationProcess@16");

static u_int32_t read_ldt(u_int32_t selector, LDT_ENTRY& ldt)
{
	u_int32_t buffer[4];
	buffer[0] = selector << 3;
	buffer[1] = sizeof(ldt);

	u_int32_t result = NtQueryInformationProcess(-1, 10, buffer, 16, NULL);
	if (buffer[1] == 0)
		ldt.HighWord.Bits.Pres = 0;
	else
		memcpy(&ldt, &buffer[2], sizeof(ldt));
	return result;
}

static u_int32_t write_ldt(u_int32_t selector, const LDT_ENTRY& ldt)
{
	u_int32_t buffer[4];
	buffer[0] = selector << 3;
	buffer[1] = sizeof(ldt);
	memcpy(&buffer[2], &ldt, sizeof(ldt));

	return NtSetInformationProcess(-1, 10, buffer, 16);
}

static int
display_selector (LDT_ENTRY& info)
{
      int base, limit;
      if (!info.HighWord.Bits.Pres)
	{
	  log ("Segment not present\n");
	  return 0;
	}
      base = (info.HighWord.Bits.BaseHi << 24) +
	     (info.HighWord.Bits.BaseMid << 16)
	     + info.BaseLow;
      limit = (info.HighWord.Bits.LimitHi << 16) + info.LimitLow;
      if (info.HighWord.Bits.Granularity)
	limit = (limit << 12) | 0xfff;
      log ("base=0x%08x limit=0x%08x", base, limit);
      if (info.HighWord.Bits.Default_Big)
	log(" 32-bit ");
      else
	log(" 16-bit ");
      switch ((info.HighWord.Bits.Type & 0xf) >> 1)
	{
	case 0:
	  log ("Data (Read-Only, Exp-up");
	  break;
	case 1:
	  log ("Data (Read/Write, Exp-up");
	  break;
	case 2:
	  log ("Unused segment (");
	  break;
	case 3:
	  log ("Data (Read/Write, Exp-down");
	  break;
	case 4:
	  log ("Code (Exec-Only, N.Conf");
	  break;
	case 5:
	  log ("Code (Exec/Read, N.Conf");
	  break;
	case 6:
	  log ("Code (Exec-Only, Conf");
	  break;
	case 7:
	  log ("Code (Exec/Read, Conf");
	  break;
	default:
	  log ("Unknown type 0x%x",info.HighWord.Bits.Type);
	}
      if ((info.HighWord.Bits.Type & 0x1) == 0)
	log(", N.Acc");
      log (")\n");
      if ((info.HighWord.Bits.Type & 0x10) == 0)
	log("System selector ");
      log ("Priviledge level = %d. ", info.HighWord.Bits.Dpl);
      if (info.HighWord.Bits.Granularity)
	log ("Page granular.\n");
      else
	log ("Byte granular.\n");
      return 1;
}

static bool try_perversion(Registers& regs, int offset)
{
	u_int16_t& insn = *(u_int16_t*)(regs.eip+offset);
	if (insn == 0xe88e)
	{
		insn = 0x9090;
		return true;
	}
	return false;
}

int32_t sys_set_thread_area(Registers& regs)
{
	Arguments& arg = regs.arg;
	struct linux_user_desc& u = *(struct linux_user_desc*) arg.a0.p;

#if 0
	log("  entry_number = %d", u.entry_number);
	log("  base_addr = %08x", u.base_addr);
	log("  limit = %08x", u.limit);
	log("  seg_32bit = %d", u.seg_32bit);
	log("  contents = %d", u.contents);
	log("  read_exec_only = %d", u.read_exec_only);
	log("  limit_in_pages = %d", u.limit_in_pages);
	log("  seg_not_present = %d", u.seg_not_present);
	log("  useable = %d", u.useable);
#endif

	/* Sanitise the limit; NT enforces a certain upper limit. */

	u_int64_t maximum = u.limit;
	if (u.limit_in_pages)
		maximum <<= 12;
	maximum += u.base_addr;
	if (maximum > 0x7ff00000)
		maximum = 0x7ff00000;

	LDT_ENTRY ldt;

	if (u.entry_number == -1)
	{
		/* Search for an unused segment. */

		int selector = 512;
		while (selector < 8192)
		{
			//log("examining selector %d", selector);
			u_int32_t r = read_ldt(selector, ldt);
			if (r != 0)
				break;
			if (!ldt.HighWord.Bits.Pres)
			{
				/* This selector is unused. */
				u.entry_number = selector;
				break;
			}
			selector++;
		}
		//log("found unused selector %d", u.entry_number);
	}

	if (u.entry_number == -1)
		return -ENOMEM;

	memset(&ldt, 0, sizeof(ldt));

	u_int32_t limit = maximum - u.base_addr;
	//log("maximum=%08llx, limit=%08x", maximum, limit);
	ldt.BaseLow                    = (u.base_addr & 0xFFFF);
	ldt.HighWord.Bits.BaseMid      = (u.base_addr >> 16) & 0xFF;
	ldt.HighWord.Bits.BaseHi       = (u.base_addr >> 24) & 0xFF;
	ldt.HighWord.Bits.Type         = 0x13; // RW data segment
	ldt.HighWord.Bits.Dpl          = 3;    // user segment
	ldt.HighWord.Bits.Pres         = 1;    // present
	ldt.HighWord.Bits.Sys          = 0;
	ldt.HighWord.Bits.Default_Big  = 1;    // 386 segment

	if (limit > 0x100000)
	{
		ldt.HighWord.Bits.Granularity = 1;
		limit >>= 12;
	}
	else
		ldt.HighWord.Bits.Granularity = 0;

	ldt.LimitLow                   = (limit & 0xFFFF);
	ldt.HighWord.Bits.LimitHi      = (limit >> 16) & 0xF;

	//display_selector(ldt);
	u_int32_t r = write_ldt(u.entry_number, ldt);
	if (r)
		return -EINVAL;

	if (try_perversion(regs, 48) ||
		try_perversion(regs, 18) ||
		try_perversion(regs, 28))
	{
		u_int16_t fs;
		asm volatile ("mov %%fs, %w0" : "=r" (fs));

		u_int16_t gs = (u.entry_number << 3) | 7;
		log("GS %04x now pointing at linear %08x", gs, u.base_addr);
		SetGS(gs, (void*) u.base_addr);
		//DumpMemory(u.base_addr, 32);
	}
	else
	{
		DumpMemory(regs.eip, 128);
		sleep(-1);
		error("unable to pervert GDT selector load; check code at %08x", regs.eip);
	}

	return 0;
}

/* Not implemented --- nop */
SYSCALL(sys_set_tid_address)
{
	Warning("sys_set_tid_address() currently unimplemented");
	return getpid();
}

/* Not implemented */
SYSCALL(compat_sys_set_robust_list)
{
	Warning("compat_sys_set_robust_list() currently unimplemented");
	return -LINUX_ENOSYS;
}

SYSCALL(compat_sys_futex)
{
	int* uaddr = (int*) arg.a0.p;
	int op = arg.a1.s;
	int val = arg.a2.s;
	const void* timespec = (const void*) arg.a3.p;
	int* uaddr2 = (int*) arg.a4.p;
	int val3 = arg.a5.s;

	log("uaddr=%08x, *uaddr=%08x, val=%08x", uaddr, *uaddr, val);
	//sleep(-1);
	log("compat_sys_futex(%x) currently unimplemented", op);
	return -LINUX_ENOSYS;
}

SYSCALL(sys_gettid)
{
	return (u32) pthread_self();
}
<commit_msg>Added just enough futex support to keep glibc happy when forking.<commit_after>#include "globals.h"
#include "syscalls.h"

#define LINUX_FUTEX_WAIT              0
#define LINUX_FUTEX_WAKE              1
#define LINUX_FUTEX_FD                2
#define LINUX_FUTEX_REQUEUE           3
#define LINUX_FUTEX_CMP_REQUEUE       4
#define LINUX_FUTEX_WAKE_OP           5
#define LINUX_FUTEX_LOCK_PI           6
#define LINUX_FUTEX_UNLOCK_PI         7
#define LINUX_FUTEX_TRYLOCK_PI        8
#define LINUX_FUTEX_WAIT_BITSET       9
#define LINUX_FUTEX_WAKE_BITSET       10

#define LINUX_FUTEX_PRIVATE_FLAG      128
#define LINUX_FUTEX_CLOCK_REALTIME	256
#define LINUX_FUTEX_CMD_MASK		~(LINUX_FUTEX_PRIVATE_FLAG | LINUX_FUTEX_CLOCK_REALTIME)

#define LINUX_FUTEX_WAIT_PRIVATE      (LINUX_FUTEX_WAIT | LINUX_FUTEX_PRIVATE_FLAG)
#define LINUX_FUTEX_WAKE_PRIVATE      (LINUX_FUTEX_WAKE | LINUX_FUTEX_PRIVATE_FLAG)
#define LINUX_FUTEX_REQUEUE_PRIVATE   (LINUX_FUTEX_REQUEUE | LINUX_FUTEX_PRIVATE_FLAG)
#define LINUX_FUTEX_CMP_REQUEUE_PRIVATE (LINUX_FUTEX_CMP_REQUEUE | LINUX_FUTEX_PRIVATE_FLAG)
#define LINUX_FUTEX_WAKE_OP_PRIVATE   (LINUX_FUTEX_WAKE_OP | LINUX_FUTEX_PRIVATE_FLAG)
#define LINUX_FUTEX_LOCK_PI_PRIVATE   (LINUX_FUTEX_LOCK_PI | LINUX_FUTEX_PRIVATE_FLAG)
#define LINUX_FUTEX_UNLOCK_PI_PRIVATE (LINUX_FUTEX_UNLOCK_PI | LINUX_FUTEX_PRIVATE_FLAG)
#define LINUX_FUTEX_TRYLOCK_PI_PRIVATE (LINUX_FUTEX_TRYLOCK_PI | LINUX_FUTEX_PRIVATE_FLAG)
#define LINUX_FUTEX_WAIT_BITSET_PRIVATE       (LINUX_FUTEX_WAIT_BITS | LINUX_FUTEX_PRIVATE_FLAG)
#define LINUX_FUTEX_WAKE_BITSET_PRIVATE       (LINUX_FUTEX_WAKE_BITS | LINUX_FUTEX_PRIVATE_FLAG)

struct linux_user_desc {
	int  entry_number;
	unsigned int  base_addr;
	unsigned int  limit;
	unsigned int  seg_32bit:1;
	unsigned int  contents:2;
	unsigned int  read_exec_only:1;
	unsigned int  limit_in_pages:1;
	unsigned int  seg_not_present:1;
	unsigned int  useable:1;
};

static pthread_mutex_t tlsmutex = PTHREAD_MUTEX_INITIALIZER;

typedef u_int32_t DWORD;
typedef u_int32_t ULONG;
typedef u_int16_t WORD;
typedef u_int8_t BYTE;

#pragma pack(push)
struct LDT_ENTRY {
		WORD LimitLow;
		WORD BaseLow;
		union {
				struct {
						BYTE BaseMid;
						BYTE Flags1;
						BYTE Flags2;
						BYTE BaseHi;
				} Bytes;
				struct {
						DWORD BaseMid:8;
						DWORD Type:5;
						DWORD Dpl:2;
						DWORD Pres:1;
						DWORD LimitHi:4;
						DWORD Sys:1;
						DWORD Reserved_0:1;
						DWORD Default_Big:1;
						DWORD Granularity:1;
						DWORD BaseHi:8;
				} Bits;
		} HighWord;
};
#pragma pack(pop)

extern "C" u_int32_t __stdcall NtSetLdtEntries(
	/*IN*/ ULONG  Selector1,
	/*IN*/ LDT_ENTRY  LdtEntry1,
	/*IN*/ ULONG  Selector2,
	/*IN*/ LDT_ENTRY  LdtEntry2);
asm ("_NtSetLdtEntries: jmp _NtSetLdtEntries@24");

extern "C" u_int32_t __stdcall NtQueryInformationProcess(
  /*IN*/ int32_t ProcessHandle,
  /*IN*/ int32_t ProcessInformationClass,
  /*OUT*/ void* ProcessInformation,
  /*IN*/ u_int32_t ProcessInformationLength,
  /*OUT*/ u_int32_t* ReturnLength  /*OPTIONAL*/);
asm ("_NtQueryInformationProcess: jmp _NtQueryInformationProcess@20");

extern "C" u_int32_t __stdcall NtSetInformationProcess(
  /*IN*/ int32_t ProcessHandle,
  /*IN*/ int32_t ProcessInformationClass,
  /*IN*/ void* ProcessInformation,
  /*IN*/ u_int32_t ProcessInformationLength);
asm ("_NtSetInformationProcess: jmp _NtSetInformationProcess@16");

static u_int32_t read_ldt(u_int32_t selector, LDT_ENTRY& ldt)
{
	u_int32_t buffer[4];
	buffer[0] = selector << 3;
	buffer[1] = sizeof(ldt);

	u_int32_t result = NtQueryInformationProcess(-1, 10, buffer, 16, NULL);
	if (buffer[1] == 0)
		ldt.HighWord.Bits.Pres = 0;
	else
		memcpy(&ldt, &buffer[2], sizeof(ldt));
	return result;
}

static u_int32_t write_ldt(u_int32_t selector, const LDT_ENTRY& ldt)
{
	u_int32_t buffer[4];
	buffer[0] = selector << 3;
	buffer[1] = sizeof(ldt);
	memcpy(&buffer[2], &ldt, sizeof(ldt));

	return NtSetInformationProcess(-1, 10, buffer, 16);
}

static int
display_selector (LDT_ENTRY& info)
{
      int base, limit;
      if (!info.HighWord.Bits.Pres)
	{
	  log ("Segment not present\n");
	  return 0;
	}
      base = (info.HighWord.Bits.BaseHi << 24) +
	     (info.HighWord.Bits.BaseMid << 16)
	     + info.BaseLow;
      limit = (info.HighWord.Bits.LimitHi << 16) + info.LimitLow;
      if (info.HighWord.Bits.Granularity)
	limit = (limit << 12) | 0xfff;
      log ("base=0x%08x limit=0x%08x", base, limit);
      if (info.HighWord.Bits.Default_Big)
	log(" 32-bit ");
      else
	log(" 16-bit ");
      switch ((info.HighWord.Bits.Type & 0xf) >> 1)
	{
	case 0:
	  log ("Data (Read-Only, Exp-up");
	  break;
	case 1:
	  log ("Data (Read/Write, Exp-up");
	  break;
	case 2:
	  log ("Unused segment (");
	  break;
	case 3:
	  log ("Data (Read/Write, Exp-down");
	  break;
	case 4:
	  log ("Code (Exec-Only, N.Conf");
	  break;
	case 5:
	  log ("Code (Exec/Read, N.Conf");
	  break;
	case 6:
	  log ("Code (Exec-Only, Conf");
	  break;
	case 7:
	  log ("Code (Exec/Read, Conf");
	  break;
	default:
	  log ("Unknown type 0x%x",info.HighWord.Bits.Type);
	}
      if ((info.HighWord.Bits.Type & 0x1) == 0)
	log(", N.Acc");
      log (")\n");
      if ((info.HighWord.Bits.Type & 0x10) == 0)
	log("System selector ");
      log ("Priviledge level = %d. ", info.HighWord.Bits.Dpl);
      if (info.HighWord.Bits.Granularity)
	log ("Page granular.\n");
      else
	log ("Byte granular.\n");
      return 1;
}

static bool try_perversion(Registers& regs, int offset)
{
	u_int16_t& insn = *(u_int16_t*)(regs.eip+offset);
	if (insn == 0xe88e)
	{
		insn = 0x9090;
		return true;
	}
	return false;
}

int32_t sys_set_thread_area(Registers& regs)
{
	Arguments& arg = regs.arg;
	struct linux_user_desc& u = *(struct linux_user_desc*) arg.a0.p;

#if 0
	log("  entry_number = %d", u.entry_number);
	log("  base_addr = %08x", u.base_addr);
	log("  limit = %08x", u.limit);
	log("  seg_32bit = %d", u.seg_32bit);
	log("  contents = %d", u.contents);
	log("  read_exec_only = %d", u.read_exec_only);
	log("  limit_in_pages = %d", u.limit_in_pages);
	log("  seg_not_present = %d", u.seg_not_present);
	log("  useable = %d", u.useable);
#endif

	/* Sanitise the limit; NT enforces a certain upper limit. */

	u_int64_t maximum = u.limit;
	if (u.limit_in_pages)
		maximum <<= 12;
	maximum += u.base_addr;
	if (maximum > 0x7ff00000)
		maximum = 0x7ff00000;

	LDT_ENTRY ldt;

	if (u.entry_number == -1)
	{
		/* Search for an unused segment. */

		int selector = 512;
		while (selector < 8192)
		{
			//log("examining selector %d", selector);
			u_int32_t r = read_ldt(selector, ldt);
			if (r != 0)
				break;
			if (!ldt.HighWord.Bits.Pres)
			{
				/* This selector is unused. */
				u.entry_number = selector;
				break;
			}
			selector++;
		}
		//log("found unused selector %d", u.entry_number);
	}

	if (u.entry_number == -1)
		return -ENOMEM;

	memset(&ldt, 0, sizeof(ldt));

	u_int32_t limit = maximum - u.base_addr;
	//log("maximum=%08llx, limit=%08x", maximum, limit);
	ldt.BaseLow                    = (u.base_addr & 0xFFFF);
	ldt.HighWord.Bits.BaseMid      = (u.base_addr >> 16) & 0xFF;
	ldt.HighWord.Bits.BaseHi       = (u.base_addr >> 24) & 0xFF;
	ldt.HighWord.Bits.Type         = 0x13; // RW data segment
	ldt.HighWord.Bits.Dpl          = 3;    // user segment
	ldt.HighWord.Bits.Pres         = 1;    // present
	ldt.HighWord.Bits.Sys          = 0;
	ldt.HighWord.Bits.Default_Big  = 1;    // 386 segment

	if (limit > 0x100000)
	{
		ldt.HighWord.Bits.Granularity = 1;
		limit >>= 12;
	}
	else
		ldt.HighWord.Bits.Granularity = 0;

	ldt.LimitLow                   = (limit & 0xFFFF);
	ldt.HighWord.Bits.LimitHi      = (limit >> 16) & 0xF;

	//display_selector(ldt);
	u_int32_t r = write_ldt(u.entry_number, ldt);
	if (r)
		return -EINVAL;

	if (try_perversion(regs, 48) ||
		try_perversion(regs, 18) ||
		try_perversion(regs, 28))
	{
		u_int16_t fs;
		asm volatile ("mov %%fs, %w0" : "=r" (fs));

		u_int16_t gs = (u.entry_number << 3) | 7;
		log("GS %04x now pointing at linear %08x", gs, u.base_addr);
		SetGS(gs, (void*) u.base_addr);
		//DumpMemory(u.base_addr, 32);
	}
	else
	{
		DumpMemory(regs.eip, 128);
		sleep(-1);
		error("unable to pervert GDT selector load; check code at %08x", regs.eip);
	}

	return 0;
}

/* Not implemented --- nop */
SYSCALL(sys_set_tid_address)
{
	Warning("sys_set_tid_address() currently unimplemented");
	return getpid();
}

/* Not implemented */
SYSCALL(compat_sys_set_robust_list)
{
	Warning("compat_sys_set_robust_list() currently unimplemented");
	return 0; //-LINUX_ENOSYS;
}

SYSCALL(compat_sys_futex)
{
	int* uaddr = (int*) arg.a0.p;
	int op = arg.a1.s;
	int val = arg.a2.s;
	const void* timespec = (const void*) arg.a3.p;
	int* uaddr2 = (int*) arg.a4.p;
	int val3 = arg.a5.s;

	log("op=%02x uaddr=%08x, *uaddr=%08x, val=%08x, timespec=%p, uaddr2=%08x, val3=%08x", op, uaddr, *uaddr, val,
			timespec, uaddr2, val3);

	int cmd = op & LINUX_FUTEX_CMD_MASK;
	switch (cmd)
	{
		case LINUX_FUTEX_WAIT:
			*uaddr = 0;
			log("FUTEX_WAIT faked");
			return 0;

		case LINUX_FUTEX_WAKE:
			return 0;

		case LINUX_FUTEX_WAIT_BITSET:
			throw EINVAL;

		default:
			error("compat_sys_futex(%x) currently unimplemented", op);
	}

	//sleep(-1);
	throw ENOSYS;
}

SYSCALL(sys_gettid)
{
	return (u32) pthread_self();
}
<|endoftext|>