mirror of
https://github.com/outbackdingo/sysadm.git
synced 2026-01-28 10:20:22 +00:00
Compare commits
80 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d018263559 | ||
|
|
b7fa03d2b8 | ||
|
|
f467df4133 | ||
|
|
694951384d | ||
|
|
10d00d97d9 | ||
|
|
32d74530ad | ||
|
|
4b0d6334d1 | ||
|
|
ed2c244282 | ||
|
|
8ba0b72cd0 | ||
|
|
67e687ba4c | ||
|
|
0fdcdb2c9b | ||
|
|
aab6f484ef | ||
|
|
25177739c2 | ||
|
|
25ca2d430d | ||
|
|
6630432922 | ||
|
|
d7c4e29d9a | ||
|
|
fd5504b304 | ||
|
|
b08d8461fc | ||
|
|
c1be586f87 | ||
|
|
dd4ab15bb4 | ||
|
|
6b43bc6a29 | ||
|
|
d6147d70f4 | ||
|
|
77986e0312 | ||
|
|
06e2f83902 | ||
|
|
42adfc6ca1 | ||
|
|
f4a2459429 | ||
|
|
c5bf944017 | ||
|
|
2157dbb6c2 | ||
|
|
d07658ee21 | ||
|
|
355b47d93a | ||
|
|
62655ebd41 | ||
|
|
ce53715265 | ||
|
|
4247c3529a | ||
|
|
bb1ec413eb | ||
|
|
d7ddcb5ae0 | ||
|
|
654b1a72d5 | ||
|
|
3cb89665b7 | ||
|
|
5807bedd68 | ||
|
|
2240fdd8c7 | ||
|
|
52ae9e8e5c | ||
|
|
068ef24a66 | ||
|
|
fba91d29c9 | ||
|
|
a239e43c05 | ||
|
|
991dcdd2f9 | ||
|
|
e9a338fa0f | ||
|
|
6447b0fed1 | ||
|
|
cf5b11a539 | ||
|
|
93f4d89b7d | ||
|
|
4e23691d50 | ||
|
|
376eaa4e37 | ||
|
|
4dded17898 | ||
|
|
6ab7c3dc01 | ||
|
|
34b388277d | ||
|
|
00251895a3 | ||
|
|
09c41edaca | ||
|
|
4a866b924f | ||
|
|
58d309031f | ||
|
|
e78f6a003f | ||
|
|
724c8ac7a8 | ||
|
|
c4750152a6 | ||
|
|
a0a585353c | ||
|
|
3276b32f80 | ||
|
|
c744785115 | ||
|
|
acbf8d6730 | ||
|
|
b428fb531a | ||
|
|
737e90c42a | ||
|
|
a3c44a5f5b | ||
|
|
fdd864e298 | ||
|
|
4333ac6fba | ||
|
|
859b441ae2 | ||
|
|
ebae121639 | ||
|
|
2bf23b8aaf | ||
|
|
f1c3651ba5 | ||
|
|
35759b12a1 | ||
|
|
0e2d941ae1 | ||
|
|
2105b59780 | ||
|
|
6392cc362f | ||
|
|
dfb6e1b6a6 | ||
|
|
cad95cbec8 | ||
|
|
97f82a06d8 |
107
README.md
107
README.md
@@ -13,6 +13,23 @@
|
|||||||
|
|
||||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
|
||||||
|
**General Project Information: Table of Contents**
|
||||||
|
|
||||||
|
- [General TrueOS Information](#gentrosinfo)
|
||||||
|
- [TrueOS Project Documentation](#docs)
|
||||||
|
- [TrueOS Handbook](#trueosdoc)
|
||||||
|
- [Lumina Handbook](#luminadoc)
|
||||||
|
- [SysAdm Handbooks](#sysadmdoc)
|
||||||
|
- [Filing Issues or Feature Requests](#fileissues)
|
||||||
|
- [Community Channels](#community)
|
||||||
|
- [Discourse](#discourse)
|
||||||
|
- [Gitter](#gitter)
|
||||||
|
- [IRC](#irc)
|
||||||
|
- [Subreddit](#subreddit)
|
||||||
|
- [Social Media](#socialmedia)
|
||||||
|
|
||||||
|
<!-- END GENERAL INFO TOC -->
|
||||||
|
|
||||||
# SysAdm
|
# SysAdm
|
||||||
|
|
||||||
Official repo for TrueOS' sysadm middleware WebSocket & REST server
|
Official repo for TrueOS' sysadm middleware WebSocket & REST server
|
||||||
@@ -105,3 +122,93 @@ have verified the functionality of your new call you should add the output <br /
|
|||||||
of the test script (either from copy-n-paste, or from the file /tmp/api-response) <br />
|
of the test script (either from copy-n-paste, or from the file /tmp/api-response) <br />
|
||||||
to your commit. (This will allow us to document the new call / class)
|
to your commit. (This will allow us to document the new call / class)
|
||||||
|
|
||||||
|
# General TrueOS Information <a name="gentrosinfo"></a>
|
||||||
|
|
||||||
|
This section describes where you can find more information about TrueOS and its related projects, file new issues on GitHub, and converse with other users or contributors to the project.
|
||||||
|
|
||||||
|
## TrueOS Project Documentation <a name="docs"></a>
|
||||||
|
|
||||||
|
A number of [Sphinx](http://www.sphinx-doc.org/en/stable/) generated reStructuredText handbooks are available to introduce you to the TrueOS, Lumina, and SysAdm projects. These handbooks are open source, and users are always encouraged to open GitHub issues or fix any errors they find in the documentation.
|
||||||
|
|
||||||
|
### TrueOS Handbook <a name="trueosdoc"></a>
|
||||||
|
|
||||||
|
The [TrueOS User Guide](https://www.trueos.org/handbook/trueos.html) is a comprehensive guide to install TrueOS, along with post-installation configuration help, recommendations for useful utilities and applications, and a help and support section containing solutions for common issues and links to community and development chat channels for uncommon issues. There is also a chapter describing the experimental TrueOS Pico project and links to the Lumina and SysAdm documentation. All TrueOS documentation is hosted on the [TrueOS website](https://www.trueos.org).
|
||||||
|
|
||||||
|
### Lumina Handbook <a name="luminadoc"></a>
|
||||||
|
|
||||||
|
The Lumina Desktop Environment has its own [handbook](https://lumina-desktop.org/handbook/), hosted on the [Lumina Website](https://lumina-desktop.org). This handbook contains brief installation instructions. However, due to the highly customizable nature of Lumina, the focus of the handbook lies mainly in documenting all user configurable settings. Each option is typically described in detail, with both text and screenshots. Finally, the suite of unique Qt5 utilities included with Lumina are also documented.
|
||||||
|
|
||||||
|
TrueOS users are encouraged to review the Lumina documentation, as the Lumina Desktop Environment is installed by default with TrueOS.
|
||||||
|
|
||||||
|
### SysAdm Handbooks <a name="sysadmdoc"></a>
|
||||||
|
|
||||||
|
Due to complexity of this project, SysAdm documentation is split into three different guides:
|
||||||
|
|
||||||
|
1. **API Reference Guide** (https://api.sysadm.us/getstarted.html)
|
||||||
|
|
||||||
|
The Application Programming Interface (API) Reference Guide is a comprehensive library of all API calls and WebSocket requests for SysAdm. In addition to documenting all SysAdm subsystems and classes, the guide provides detailed examples of requests and responses, authentication, and SSL certificate management. This guide is constantly updated, ensuring it provides accurate information at all times.
|
||||||
|
|
||||||
|
2. **Client Handbook** (https://sysadm.us/handbook/client/)
|
||||||
|
|
||||||
|
The SysAdm Client handbook documents all aspects of the SysAdm client, as well as describing of the PC-BSD system utilities is replaces. Detailed descriptions of utilities such as Appcafe, Life Preserver, and the Boot Environment Manager are contained here, as well as a general guide to using these utilities. TrueOS users are encouraged to reference this guide, as the SysAdm client is included with TrueOS.
|
||||||
|
|
||||||
|
3. **Server Handbook** (https://sysadm.us/handbook/server/introduction.html)
|
||||||
|
|
||||||
|
The Server handbook is a basic installation guide, walking new users through the process of initializing SysAdm with a bridge and server connection.
|
||||||
|
|
||||||
|
## Filing Issues or Feature Requests <a name="fileissues"></a>
|
||||||
|
|
||||||
|
Due to the number of repositories under the TrueOS "umbrella", the TrueOS Project consolidates its issue trackers into a few repositories:
|
||||||
|
|
||||||
|
* [trueos-core](https://github.com/trueos/trueos-core) : Used for general TrueOS issues, Pico issues, and feature requests.
|
||||||
|
* [lumina](https://github.com/trueos/lumina) : Issues related to using the Lumina Desktop Environment.
|
||||||
|
* [sysadm](https://github.com/trueos/sysadm) : Issues with using the SysAdm client or server.
|
||||||
|
* [trueos-docs](https://github.com/trueos/trueos-docs) : Issues related to the TrueOS Handbook.
|
||||||
|
* [lumina-docs](https://github.com/trueos/lumina-docs) : Issues related to the Lumina Handbook.
|
||||||
|
* [sysadm-docs](https://github.com/trueos/sysadm-docs) : Issues related to the SysAdm API Guide, Client, and Server Handbooks.
|
||||||
|
* [trueos-website](https://github.com/trueos/trueos-website) : Issues involving any of the TrueOS Project websites:
|
||||||
|
- https://www.lumina-desktop.org
|
||||||
|
- https://www.trueos.org
|
||||||
|
- https://www.sysadm.us
|
||||||
|
|
||||||
|
The TrueOS handbook has detailed instructions to help you report a bug (https://www.trueos.org/handbook/helpsupport.html#report-a-bug). It is recommended to refer to these instructions when creating new GitHub issues. Better bug reports usually result in faster fixes!
|
||||||
|
|
||||||
|
To request a feature, open a new issue in one of the related GitHub issue repositories and begin the title with *Feature Request:*.
|
||||||
|
|
||||||
|
## Community Channels <a name="community"></a>
|
||||||
|
|
||||||
|
The TrueOS community has a wide variety of chat channels and forum options available for users to interact with not only each other, but contributors to the project and the core development team too.
|
||||||
|
|
||||||
|
### Discourse <a name="discourse"></a>
|
||||||
|
|
||||||
|
TrueOS has a [Discourse channel](https://discourse.trueos.org/) managed concurrently with the TrueOS Subreddit. New users need to sign up with Discourse in order to create posts, but it is possible to view posts without an account.
|
||||||
|
|
||||||
|
### Gitter <a name="gitter"></a>
|
||||||
|
|
||||||
|
The TrueOS Project uses Gitter to provide real-time chat and collaboration with TrueOS users and developers. Gitter does not require an application to use, but does require a login using either an existing GitHub or Twitter account.
|
||||||
|
|
||||||
|
To access the TrueOS Gitter community, point a web browser to https://gitter.im/trueos.
|
||||||
|
|
||||||
|
Gitter also maintains a full archive of the chat history. This means lengthy conversations about hardware issues or workarounds are always available for reference. To access the Gitter archive, navigate to the desired TrueOS room’s archive. For example, here is the address of the TrueOS Lobby archive: https://gitter.im/trueos/Lobby/archives.
|
||||||
|
|
||||||
|
### IRC <a name="irc"></a>
|
||||||
|
|
||||||
|
Like many open source projects, TrueOS has an Internet Relay Chat (IRC) channel so users can chat and get help in real time. To get connected, use this information in your IRC client:
|
||||||
|
|
||||||
|
* Server name: irc.freenode.net
|
||||||
|
* Channel name: #trueos (note the # is required)
|
||||||
|
|
||||||
|
### Subreddit <a name="subreddit"></a>
|
||||||
|
|
||||||
|
The TrueOS Project also has a [Subreddit](https://www.reddit.com/r/TrueOS/) for users who prefer to use Reddit to ask questions and to search for or post how-tos. A Reddit account is not required in order to read the Subreddit, but it is necessary to create a login account to submit or comment on posts.
|
||||||
|
|
||||||
|
## Social Media <a name="socialmedia"></a>
|
||||||
|
|
||||||
|
The TrueOS Project also maintains a number of social media accounts you can watch:
|
||||||
|
|
||||||
|
* Facebook: https://www.facebook.com/groups/4210443834/
|
||||||
|
* Linkedin: http://www.linkedin.com/groups?gid=1942544
|
||||||
|
* TrueOS Blog: https://www.trueos.org/blog/
|
||||||
|
* Twitter: https://twitter.com/TrueOS_Project/
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
# Created by: Kris Moore <kmoore@FreeBSD.org>
|
|
||||||
# $FreeBSD$
|
# $FreeBSD$
|
||||||
|
|
||||||
PORTNAME= sysadm
|
PORTNAME= sysadm
|
||||||
PORTVERSION= %%CHGVERSION%%
|
PORTVERSION= %%CHGVERSION%%
|
||||||
CATEGORIES= sysutils
|
CATEGORIES= sysutils
|
||||||
|
|
||||||
MAINTAINER= kmoore@FreeBSD.org
|
MAINTAINER= jt@ixsystems.com
|
||||||
COMMENT= SysAdm API server
|
COMMENT= SysAdm API server
|
||||||
|
|
||||||
LICENSE= BSD3CLAUSE
|
LICENSE= BSD3CLAUSE
|
||||||
|
|
||||||
WRKSRC_SUBDIR= src
|
WRKSRC_SUBDIR= src
|
||||||
USE_QT5= concurrent core network buildtools qmake gui websockets
|
USES= pkgconfig tar:xz qmake ssl qt:5
|
||||||
USES= pkgconfig tar:xz qmake
|
USE_QT= concurrent core network buildtools_build qmake_build websockets sql
|
||||||
MAKE_ARGS= PREFIX=${STAGEDIR}${PREFIX}
|
MAKE_ARGS= PREFIX=${STAGEDIR}${PREFIX}
|
||||||
|
|
||||||
USE_GITHUB= yes
|
USE_GITHUB= yes
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
Sysadm API server and websocket daemon
|
SysAdm is a FreeBSD-based service which provides a stable API for
|
||||||
|
administrating FreeBSD and TrueOS systems. It is composed of a
|
||||||
|
headless daemon that runs in the background on any system to be
|
||||||
|
administrated, providing both web socket and REST network services.
|
||||||
|
|
||||||
WWW: https://github.com/pcbsd/sysadm
|
WWW: https://sysadm.us
|
||||||
|
|||||||
21
src/qMDNS/LICENSE.md
Normal file
21
src/qMDNS/LICENSE.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016 Alex Spataru
|
||||||
|
|
||||||
|
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.
|
||||||
701
src/qMDNS/qMDNS.cpp
Normal file
701
src/qMDNS/qMDNS.cpp
Normal file
@@ -0,0 +1,701 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Alex Spataru <alex_spataru@outlook.com>
|
||||||
|
*
|
||||||
|
* This file is part of qMDNS, which is released under the MIT license.
|
||||||
|
* For more information, please read the LICENSE file in the root directory
|
||||||
|
* of this project.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qMDNS.h"
|
||||||
|
|
||||||
|
#include <QHostInfo>
|
||||||
|
#include <QUdpSocket>
|
||||||
|
#include <QHostAddress>
|
||||||
|
#include <QNetworkInterface>
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DNS port and mutlicast addresses
|
||||||
|
*/
|
||||||
|
const quint16 MDNS_PORT = 5353;
|
||||||
|
const QHostAddress IPV6_ADDRESS = QHostAddress ("FF02::FB");
|
||||||
|
const QHostAddress IPV4_ADDRESS = QHostAddress ("224.0.0.251");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mDNS/DNS operation flags
|
||||||
|
*/
|
||||||
|
const quint16 kQR_Query = 0x0000;
|
||||||
|
const quint16 kQR_Response = 0x8000;
|
||||||
|
const quint16 kRecordA = 0x0001;
|
||||||
|
const quint16 kRecordAAAA = 0x001C;
|
||||||
|
const quint16 kNsecType = 0x002F;
|
||||||
|
const quint16 kFQDN_Separator = 0x0000;
|
||||||
|
const quint16 kFQDN_Length = 0xC00C;
|
||||||
|
const quint16 kIN_BitFlush = 0x8001;
|
||||||
|
const quint16 kIN_Normal = 0x0001;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DNS query properties
|
||||||
|
*/
|
||||||
|
const quint16 kQuery_QDCOUNT = 0x02;
|
||||||
|
const quint16 kQuery_ANCOUNT = 0x00;
|
||||||
|
const quint16 kQuery_NSCOUNT = 0x00;
|
||||||
|
const quint16 kQuery_ARCOUNT = 0x00;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DNS response properties
|
||||||
|
*/
|
||||||
|
const quint16 kResponse_QDCOUNT = 0x00;
|
||||||
|
const quint16 kResponse_ANCOUNT = 0x01;
|
||||||
|
const quint16 kResponse_NSCOUNT = 0x00;
|
||||||
|
const quint16 kResponse_ARCOUNT = 0x02;
|
||||||
|
|
||||||
|
/* Packet constants */
|
||||||
|
const int MIN_LENGTH = 13;
|
||||||
|
const int IPI_LENGTH = 10;
|
||||||
|
const int IP4_LENGTH = IPI_LENGTH + 4;
|
||||||
|
const int IP6_LENGTH = IPI_LENGTH + 16;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encondes the 16-bit \a number as two 8-bit numbers in a byte array
|
||||||
|
*/
|
||||||
|
QByteArray ENCODE_16_BIT (quint16 number) {
|
||||||
|
QByteArray data;
|
||||||
|
data.append ((number & 0xff00) >> 8);
|
||||||
|
data.append ((number & 0xff));
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes the 32-bit \a number as four 8-bit numbers
|
||||||
|
*/
|
||||||
|
QByteArray ENCODE_32_BIT (quint32 number) {
|
||||||
|
QByteArray data;
|
||||||
|
data.append ((number & 0xff000000UL) >> 24);
|
||||||
|
data.append ((number & 0x00ff0000UL) >> 16);
|
||||||
|
data.append ((number & 0x0000ff00UL) >> 8);
|
||||||
|
data.append ((number & 0x000000ffUL));
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the 16-bit number stored in the \a upper and \a lower 8-bit numbers
|
||||||
|
*/
|
||||||
|
quint16 DECODE_16_BIT (quint8 upper, quint8 lower) {
|
||||||
|
return (quint16) ((upper << 8) | lower);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds the given \a socket to the given \a address and \a port.
|
||||||
|
* Under GNU/Linux, this function implements a workaround of QTBUG-33419.
|
||||||
|
*/
|
||||||
|
bool BIND (QUdpSocket* socket, const QHostAddress& address, const int port) {
|
||||||
|
if (!socket)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
int reuse = 1;
|
||||||
|
int domain = PF_UNSPEC;
|
||||||
|
|
||||||
|
if (address.protocol() == QAbstractSocket::IPv4Protocol)
|
||||||
|
domain = PF_INET;
|
||||||
|
else if (address.protocol() == QAbstractSocket::IPv6Protocol)
|
||||||
|
domain = PF_INET6;
|
||||||
|
|
||||||
|
socket->setSocketDescriptor (::socket (domain, SOCK_DGRAM, 0),
|
||||||
|
QUdpSocket::UnconnectedState);
|
||||||
|
|
||||||
|
setsockopt (socket->socketDescriptor(), SOL_SOCKET, SO_REUSEADDR,
|
||||||
|
&reuse, sizeof (reuse));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return socket->bind (address, port,
|
||||||
|
QUdpSocket::ShareAddress |
|
||||||
|
QUdpSocket::ReuseAddressHint);
|
||||||
|
}
|
||||||
|
|
||||||
|
qMDNS::qMDNS() {
|
||||||
|
/* Set default TTL to 4500 seconds */
|
||||||
|
m_ttl = 4500;
|
||||||
|
|
||||||
|
/* Initialize sockets */
|
||||||
|
m_IPv4Socket = new QUdpSocket (this);
|
||||||
|
m_IPv6Socket = new QUdpSocket (this);
|
||||||
|
|
||||||
|
/* Read and interpret data received from mDNS group */
|
||||||
|
connect (m_IPv4Socket, &QUdpSocket::readyRead, this, &qMDNS::onReadyRead);
|
||||||
|
connect (m_IPv6Socket, &QUdpSocket::readyRead, this, &qMDNS::onReadyRead);
|
||||||
|
|
||||||
|
/* Bind the sockets to the mDNS multicast group */
|
||||||
|
if (BIND (m_IPv4Socket, QHostAddress::AnyIPv4, MDNS_PORT))
|
||||||
|
m_IPv4Socket->joinMulticastGroup (IPV4_ADDRESS);
|
||||||
|
if (BIND (m_IPv6Socket, QHostAddress::AnyIPv6, MDNS_PORT))
|
||||||
|
m_IPv6Socket->joinMulticastGroup (IPV6_ADDRESS);
|
||||||
|
|
||||||
|
cacheCleanTimer = new QTimer(this);
|
||||||
|
cacheCleanTimer->setInterval(60000); //1 minute checks
|
||||||
|
connect(cacheCleanTimer, SIGNAL(timeout()), this, SLOT(cleanCache()) );
|
||||||
|
|
||||||
|
knownHash = new QHash<QDateTime, QHostInfo>();
|
||||||
|
|
||||||
|
//connect the internal signal/slot for the cache
|
||||||
|
connect(this, SIGNAL(hostFound(const QHostInfo&)), this, SLOT(NewHostFound(QHostInfo)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
qMDNS::~qMDNS() {
|
||||||
|
delete m_IPv4Socket;
|
||||||
|
delete m_IPv6Socket;
|
||||||
|
delete knownHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the only running instance of this class
|
||||||
|
*/
|
||||||
|
qMDNS* qMDNS::getInstance() {
|
||||||
|
static qMDNS instance;
|
||||||
|
return &instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the mDNS name assigned to the client computer
|
||||||
|
*/
|
||||||
|
QString qMDNS::hostName() const {
|
||||||
|
return m_hostName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that the given \a string is a valid mDNS/DNS address.
|
||||||
|
*/
|
||||||
|
QString qMDNS::getAddress (const QString& string) {
|
||||||
|
QString address = string;
|
||||||
|
|
||||||
|
if (!string.endsWith (".local") && !string.contains ("."))
|
||||||
|
address = string + ".local";
|
||||||
|
|
||||||
|
if (string.endsWith ("."))
|
||||||
|
return "";
|
||||||
|
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QHostInfo> qMDNS::knownHosts(){
|
||||||
|
QList<QDateTime> keys = knownHash->keys();
|
||||||
|
QList<QHostInfo> addrs;
|
||||||
|
for(int i=0; i<keys.length(); i++){ addrs << knownHash->value(keys[i]); }
|
||||||
|
//Go through and remove any duplicate addresses
|
||||||
|
/*QStringList chk;
|
||||||
|
for(int i=0; i<addrs.length(); i++){
|
||||||
|
QString tmp = addrs[i]->toString();
|
||||||
|
if(chk.contains(tmp)){
|
||||||
|
//duplicate address - remove it
|
||||||
|
addrs.removeAt(i); i--;
|
||||||
|
}else{
|
||||||
|
chk << tmp; //unique address - add it to the check list
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
return addrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the TTL send to other computers in the mDNS network
|
||||||
|
*/
|
||||||
|
void qMDNS::setTTL (const quint32 ttl) {
|
||||||
|
m_ttl = ttl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a mDNS lookup to find the given host \a name.
|
||||||
|
* If \a preferIPv6 is set to \c true, then this function will generate a
|
||||||
|
* packet that requests an AAAA-type Resource Record instead of an A-type
|
||||||
|
* Resource Record.
|
||||||
|
*/
|
||||||
|
void qMDNS::lookup (const QString& name) {
|
||||||
|
/* The host name is empty, abort lookup */
|
||||||
|
if (name.isEmpty()) {
|
||||||
|
qWarning() << Q_FUNC_INFO << "Empty host name specified";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure that we host name is a valid DNS address */
|
||||||
|
QString address = getAddress (name);
|
||||||
|
if (address.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Check if we are dealing with a normal DNS address */
|
||||||
|
if (!address.endsWith (".local", Qt::CaseInsensitive)) {
|
||||||
|
QHostInfo::lookupHost (address, this, SIGNAL (hostFound (QHostInfo)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform a mDNS lookup */
|
||||||
|
else {
|
||||||
|
QByteArray data;
|
||||||
|
|
||||||
|
/* Get the host name and domain */
|
||||||
|
QString host = address.split (".").first();
|
||||||
|
QString domain = address.split (".").last();
|
||||||
|
|
||||||
|
/* Check that domain length is valid */
|
||||||
|
if (host.length() > 255) {
|
||||||
|
qWarning() << Q_FUNC_INFO << host << "is too long!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create header & flags */
|
||||||
|
data.append (ENCODE_16_BIT (0));
|
||||||
|
data.append (ENCODE_16_BIT (kQR_Query));
|
||||||
|
data.append (ENCODE_16_BIT (kQuery_QDCOUNT));
|
||||||
|
data.append (ENCODE_16_BIT (kQuery_ANCOUNT));
|
||||||
|
data.append (ENCODE_16_BIT (kQuery_NSCOUNT));
|
||||||
|
data.append (ENCODE_16_BIT (kQuery_ARCOUNT));
|
||||||
|
|
||||||
|
/* Add name data */
|
||||||
|
data.append (host.length());
|
||||||
|
data.append (host.toUtf8());
|
||||||
|
|
||||||
|
/* Add domain data */
|
||||||
|
data.append (domain.length());
|
||||||
|
data.append (domain.toUtf8());
|
||||||
|
|
||||||
|
/* Add FQDN/TLD separator */
|
||||||
|
data.append ((char) kFQDN_Separator);
|
||||||
|
|
||||||
|
/* Add IPv4 record type */
|
||||||
|
data.append (ENCODE_16_BIT (kRecordA));
|
||||||
|
data.append (ENCODE_16_BIT (kIN_Normal));
|
||||||
|
|
||||||
|
/* Add FQDN length */
|
||||||
|
data.append (ENCODE_16_BIT (kFQDN_Length));
|
||||||
|
|
||||||
|
/* Add IPv6 record type */
|
||||||
|
data.append (ENCODE_16_BIT (kRecordAAAA));
|
||||||
|
data.append (ENCODE_16_BIT (kIN_Normal));
|
||||||
|
|
||||||
|
/* Send the datagram */
|
||||||
|
sendPacket (data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the host name of the client computer
|
||||||
|
*/
|
||||||
|
void qMDNS::setHostName (const QString& name) {
|
||||||
|
if (name.contains (".") && !name.endsWith (".local")) {
|
||||||
|
qWarning() << "Invalid domain name";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_hostName = getAddress (name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when we receive data from a mDNS client on the network.
|
||||||
|
*/
|
||||||
|
void qMDNS::onReadyRead() {
|
||||||
|
QByteArray data;
|
||||||
|
QUdpSocket* socket = qobject_cast<QUdpSocket*> (sender());
|
||||||
|
|
||||||
|
/* Read data from the socket */
|
||||||
|
if (socket) {
|
||||||
|
while (socket->hasPendingDatagrams()) {
|
||||||
|
data.resize (socket->pendingDatagramSize());
|
||||||
|
socket->readDatagram (data.data(), data.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Packet is a valid mDNS datagram */
|
||||||
|
if (data.length() > MIN_LENGTH) {
|
||||||
|
quint16 flag = DECODE_16_BIT (data.at (2), data.at (3));
|
||||||
|
|
||||||
|
if (flag == kQR_Query)
|
||||||
|
readQuery (data);
|
||||||
|
|
||||||
|
else if (flag >= kQR_Response)
|
||||||
|
readResponse (data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the given query \a data and instructs the class to send a response
|
||||||
|
* packet if the query is looking for the host name assigned to this computer.
|
||||||
|
*/
|
||||||
|
void qMDNS::readQuery (const QByteArray& data) {
|
||||||
|
/* Query packet is invalid */
|
||||||
|
if (data.length() < MIN_LENGTH)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Get the lengths of the host name and domain */
|
||||||
|
int n = 12;
|
||||||
|
int hostLength = data.at (n);
|
||||||
|
int domainLength = data.at (n + hostLength + 1);
|
||||||
|
|
||||||
|
/* Read the host name until we stumble with the domain length character */
|
||||||
|
QString name;
|
||||||
|
int h = n + 1;
|
||||||
|
while (data.at (h) != (char) domainLength) {
|
||||||
|
name.append (data.at (h));
|
||||||
|
++h;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read domain length until we stumble with the FQDN/TLD separator */
|
||||||
|
QString domain;
|
||||||
|
int d = n + hostLength + 2;
|
||||||
|
while (data.at (d) != kFQDN_Separator) {
|
||||||
|
domain.append (data.at (d));
|
||||||
|
++d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Construct the full host name (name + domain) */
|
||||||
|
QString host = getAddress (name + "." + domain);
|
||||||
|
|
||||||
|
/* The query packet wants to know more about us */
|
||||||
|
if (host.toLower() == hostName().toLower())
|
||||||
|
sendResponse (DECODE_16_BIT (data.at (0), data.at (1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the given \a data to both the IPv4 and IPv6 mDNS multicast groups
|
||||||
|
*/
|
||||||
|
void qMDNS::sendPacket (const QByteArray& data) {
|
||||||
|
if (!data.isEmpty()) {
|
||||||
|
m_IPv4Socket->writeDatagram (data, IPV4_ADDRESS, MDNS_PORT);
|
||||||
|
m_IPv6Socket->writeDatagram (data, IPV6_ADDRESS, MDNS_PORT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the given \a data of a response packet and obtains:
|
||||||
|
* - The remote host name
|
||||||
|
* - The remote IPv4
|
||||||
|
* - The remote IPv6
|
||||||
|
*/
|
||||||
|
void qMDNS::readResponse (const QByteArray& data) {
|
||||||
|
if (data.length() < MIN_LENGTH)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString host = getHostNameFromResponse (data);
|
||||||
|
QList<QHostAddress> addresses = getAddressesFromResponse (data, host);
|
||||||
|
|
||||||
|
if (!host.isEmpty() && !addresses.isEmpty()) {
|
||||||
|
QHostInfo info;
|
||||||
|
info.setHostName (host);
|
||||||
|
info.setAddresses (addresses);
|
||||||
|
info.setError (QHostInfo::NoError);
|
||||||
|
|
||||||
|
emit hostFound (info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a response packet with:
|
||||||
|
* - Our mDNS host name
|
||||||
|
* - Our IPv4 address
|
||||||
|
* - Our IPv6 address
|
||||||
|
*/
|
||||||
|
void qMDNS::sendResponse (const quint16 query_id) {
|
||||||
|
if (!hostName().isEmpty() && hostName().endsWith (".local")) {
|
||||||
|
QByteArray data;
|
||||||
|
|
||||||
|
/* Get the host name and domain */
|
||||||
|
QString host = hostName().split (".").first();
|
||||||
|
QString domain = hostName().split (".").last();
|
||||||
|
|
||||||
|
/* Get local IPs */
|
||||||
|
quint32 ipv4 = 0;
|
||||||
|
QList<QIPv6Address> ipv6;
|
||||||
|
foreach (QHostAddress address, QNetworkInterface::allAddresses()) {
|
||||||
|
if (!address.isLoopback()) {
|
||||||
|
if (address.protocol() == QAbstractSocket::IPv4Protocol)
|
||||||
|
ipv4 = (ipv4 == 0 ? address.toIPv4Address() : ipv4);
|
||||||
|
|
||||||
|
if (address.protocol() == QAbstractSocket::IPv6Protocol)
|
||||||
|
ipv6.append (address.toIPv6Address());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that domain length is valid */
|
||||||
|
if (host.length() > 255) {
|
||||||
|
qWarning() << Q_FUNC_INFO << host << "is too long!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create header and flags */
|
||||||
|
data.append (ENCODE_16_BIT (query_id));
|
||||||
|
data.append (ENCODE_16_BIT (kQR_Response));
|
||||||
|
data.append (ENCODE_16_BIT (kResponse_QDCOUNT));
|
||||||
|
data.append (ENCODE_16_BIT (kResponse_ANCOUNT));
|
||||||
|
data.append (ENCODE_16_BIT (kResponse_NSCOUNT));
|
||||||
|
data.append (ENCODE_16_BIT (kResponse_ARCOUNT));
|
||||||
|
|
||||||
|
/* Add name data */
|
||||||
|
data.append (host.length());
|
||||||
|
data.append (host.toUtf8());
|
||||||
|
|
||||||
|
/* Add domain data and FQDN/TLD separator */
|
||||||
|
data.append (domain.length());
|
||||||
|
data.append (domain.toUtf8());
|
||||||
|
data.append ((char) kFQDN_Separator);
|
||||||
|
|
||||||
|
/* Add IPv4 address header */
|
||||||
|
data.append (ENCODE_16_BIT (kRecordA));
|
||||||
|
data.append (ENCODE_16_BIT (kIN_BitFlush));
|
||||||
|
data.append (ENCODE_32_BIT (m_ttl));
|
||||||
|
data.append (ENCODE_16_BIT (sizeof (ipv4)));
|
||||||
|
|
||||||
|
/* Add IPv4 bytes */
|
||||||
|
data.append (ENCODE_32_BIT (ipv4));
|
||||||
|
|
||||||
|
/* Add FQDN offset */
|
||||||
|
data.append (ENCODE_16_BIT (kFQDN_Length));
|
||||||
|
|
||||||
|
/* Add IPv6 addresses */
|
||||||
|
foreach (QIPv6Address ip, ipv6) {
|
||||||
|
data.append (ENCODE_16_BIT (kRecordAAAA));
|
||||||
|
data.append (ENCODE_16_BIT (kIN_BitFlush));
|
||||||
|
data.append (ENCODE_32_BIT (m_ttl));
|
||||||
|
data.append (ENCODE_16_BIT (sizeof (ip.c)));
|
||||||
|
|
||||||
|
/* Add IPv6 bytes */
|
||||||
|
for (unsigned long i = 0; i < sizeof (ip.c); ++i)
|
||||||
|
data.append (ip.c [i]);
|
||||||
|
|
||||||
|
/* Add FQDN offset */
|
||||||
|
data.append (ENCODE_16_BIT (kFQDN_Length));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Generate NSEC code block */
|
||||||
|
int nsec_length = 0;
|
||||||
|
|
||||||
|
/* Add NSEC data */
|
||||||
|
data.append (ENCODE_16_BIT (kNsecType));
|
||||||
|
data.append (ENCODE_16_BIT (kIN_BitFlush));
|
||||||
|
data.append (ENCODE_32_BIT (m_ttl));
|
||||||
|
data.append (ENCODE_16_BIT (nsec_length));
|
||||||
|
|
||||||
|
/* Send the response */
|
||||||
|
sendPacket (data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Internal slot for saving the host information into the cache */
|
||||||
|
void qMDNS::NewHostFound(QHostInfo info){
|
||||||
|
if(info.addresses().isEmpty()){ return; } //no address associated with this host - skip it
|
||||||
|
knownHash->insert(QDateTime::currentDateTime(), info);
|
||||||
|
if(!cacheCleanTimer->isActive()){ cacheCleanTimer->start(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
void qMDNS::cleanCache(){
|
||||||
|
QList<QDateTime> keys = knownHash->keys();
|
||||||
|
QDateTime cdt = QDateTime::currentDateTime().addSecs( 0-(60*15)); //15 minutes in the past
|
||||||
|
for(int i=0; i<keys.length(); i++){
|
||||||
|
if(keys[i] < cdt){ knownHash->remove(keys[i]); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the host name from the \a data received from the mDNS network.
|
||||||
|
* The host name begins at byte #12 (when the header and flags end) and ends
|
||||||
|
* with a mandatory NUL character after the domain.
|
||||||
|
*
|
||||||
|
* The host name is constructed in the following way (without spaces):
|
||||||
|
* \c NAME_LENGTH + \c NAME + \c DOMAIN_LENGTH + \c DOMAIN + \c NUL
|
||||||
|
*
|
||||||
|
* For example, appletv.local would be formatted as:
|
||||||
|
* \c 0x07 + \c appletv + \c 0x05 + \c local + \c 0x00
|
||||||
|
*
|
||||||
|
* Or, if you prefer hex data:
|
||||||
|
* \c { 07 61 70 70 6c 65 74 76 05 6c 6f 63 61 6c 00 }
|
||||||
|
* \c { 7 a p p l e t v 5 l o c a l 0 }
|
||||||
|
*
|
||||||
|
* In order to obtain the full host name (and its mDNS domain), we construct
|
||||||
|
* the string backwards. When the code notices that the current character is
|
||||||
|
* the same as the domain length, we know that the domain name has been
|
||||||
|
* extracted, and thus we can replace the domain length with a dot (.) and
|
||||||
|
* begin extracting the host name.
|
||||||
|
*/
|
||||||
|
QString qMDNS::getHostNameFromResponse (const QByteArray& data) {
|
||||||
|
QList<char> list;
|
||||||
|
QString address = "";
|
||||||
|
|
||||||
|
/* Begin reading host name at byte 13 (byte 12 is the host name length) */
|
||||||
|
int n = 13;
|
||||||
|
|
||||||
|
/* Read the host name until we stumble with the FQDN/TLD separator */
|
||||||
|
while (data.at (n) != kFQDN_Separator) {
|
||||||
|
list.append (data.at (n));
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Construct the string backwards (to replace domain length with a dot) */
|
||||||
|
for (int i = 0; i < list.count(); ++i) {
|
||||||
|
char character = list.at (list.count() - i - 1);
|
||||||
|
|
||||||
|
if (character == (char) address.length())
|
||||||
|
address.prepend (".");
|
||||||
|
else
|
||||||
|
address.prepend (character);
|
||||||
|
}
|
||||||
|
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the IPv4 from the \a data received from the mDNS network.
|
||||||
|
* The IPv4 data begins when the host name data ends.
|
||||||
|
*
|
||||||
|
* For the packet to contain IPv4 information, the DNS Record Type code must
|
||||||
|
* be "A" (IPv4) and the DNS Class code should correspond to "IN" (Internet).
|
||||||
|
*
|
||||||
|
* Here is the layout of the IPv4 section of the packet:
|
||||||
|
*
|
||||||
|
* - DNS Record Type
|
||||||
|
* - DNS Class Code
|
||||||
|
* - TTL
|
||||||
|
* - IP length
|
||||||
|
* - IP address bytes
|
||||||
|
*
|
||||||
|
* This is an example IPv4 section:
|
||||||
|
* \c {00 01 80 01 00 00 78 00 00 04 99 6d 07 5a}
|
||||||
|
*
|
||||||
|
* Data in example section:
|
||||||
|
* - \c {00 01} Type Codes
|
||||||
|
* - \c {80 01} Class Codes
|
||||||
|
* - \c {00 00 78 00} IP TTL
|
||||||
|
* - \c {00 04} Number of address bytes (length in layman's terms)
|
||||||
|
* - \c {99 6d 07 5a} IPv4 Address bytes (153, 109, 7, 90)
|
||||||
|
*/
|
||||||
|
QString qMDNS::getIPv4FromResponse (const QByteArray& data,
|
||||||
|
const QString& host) {
|
||||||
|
QString ip = "";
|
||||||
|
|
||||||
|
/* n stands for the byte index in which the host name data ends */
|
||||||
|
int n = MIN_LENGTH + host.length();
|
||||||
|
|
||||||
|
/* Packet is too small */
|
||||||
|
if (data.length() < n + IP4_LENGTH)
|
||||||
|
return ip;
|
||||||
|
|
||||||
|
/* Get the IP type and class codes */
|
||||||
|
quint16 typeCode = DECODE_16_BIT (data.at (n + 1), data.at (n + 2));
|
||||||
|
quint16 classCode = DECODE_16_BIT (data.at (n + 3), data.at (n + 4));
|
||||||
|
|
||||||
|
/* Check if type and class codes are good */
|
||||||
|
if (typeCode != kRecordA || classCode != kIN_BitFlush)
|
||||||
|
return ip;
|
||||||
|
|
||||||
|
/* Skip TTL indicator and obtain the number of address bytes */
|
||||||
|
quint8 length = data.at (n + IPI_LENGTH);
|
||||||
|
|
||||||
|
/* Append each IPv4 address byte (and decimal dots) to the IP string */
|
||||||
|
for (int i = 1; i < length + 1; ++i) {
|
||||||
|
ip += QString::number ((quint8) data.at (n + IPI_LENGTH + i));
|
||||||
|
ip += (i < length) ? "." : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the IPv6 from the \a data received from the mDNS network.
|
||||||
|
* The IPv6 data begins when the host name data ends.
|
||||||
|
*
|
||||||
|
* For the packet to contain IPv6 information, the DNS Record Type code must
|
||||||
|
* be "AAAA" (IPv6) and the DNS Class code should correspond to "IN" (Internet).
|
||||||
|
*
|
||||||
|
* Here is the layout of the IPv4 section of the packet:
|
||||||
|
*
|
||||||
|
* - DNS Record Type
|
||||||
|
* - DNS Class Code
|
||||||
|
* - TTL
|
||||||
|
* - IP length
|
||||||
|
* - IP address bytes
|
||||||
|
*
|
||||||
|
* This is an example IPv6 section:
|
||||||
|
* \c { 00 1c 80 01 00 00 78 00 00 10 fe 80 00 00 00 00 00 00 02 23 32 ff fe b1 21 52 }
|
||||||
|
*
|
||||||
|
* Data in example section:
|
||||||
|
* - \c {00 1c} Type Codes
|
||||||
|
* - \c {80 01} Class Codes
|
||||||
|
* - \c {00 00 78 00} IP TTL
|
||||||
|
* - \c {00 10} Number of address bytes (length in layman's terms)
|
||||||
|
* - \c {fe 80 00 00 ... 52} IPv6 Address bytes (there are 16 of them)
|
||||||
|
*/
|
||||||
|
QStringList qMDNS::getIPv6FromResponse (const QByteArray& data,
|
||||||
|
const QString& host) {
|
||||||
|
QStringList list;
|
||||||
|
|
||||||
|
/* Skip the FQDN and IPv4 section */
|
||||||
|
int n = MIN_LENGTH + IP4_LENGTH + host.length();
|
||||||
|
|
||||||
|
/* Get the IPv6 list */
|
||||||
|
bool isIPv6 = true;
|
||||||
|
while (isIPv6) {
|
||||||
|
/* Skip FQDN bytes */
|
||||||
|
n += 2;
|
||||||
|
|
||||||
|
/* Packet is invalid */
|
||||||
|
if (data.length() < n + IP6_LENGTH)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Get the IP type and class codes */
|
||||||
|
quint16 typeCode = DECODE_16_BIT (data.at (n + 1), data.at (n + 2));
|
||||||
|
quint16 classCode = DECODE_16_BIT (data.at (n + 3), data.at (n + 4));
|
||||||
|
isIPv6 = (typeCode == kRecordAAAA && classCode == kIN_BitFlush);
|
||||||
|
|
||||||
|
/* IP type and class codes are OK, extract IP */
|
||||||
|
if (isIPv6) {
|
||||||
|
/* Skip TTL indicator and obtain the number of address bytes */
|
||||||
|
quint8 length = data.at (n + IPI_LENGTH);
|
||||||
|
|
||||||
|
/* Append each IPv6 address byte (encoded as hex) to the IP string */
|
||||||
|
QString ip = "";
|
||||||
|
for (int i = 1; i < length + 1; ++i) {
|
||||||
|
/* Get the hexadecimal representation of the byte */
|
||||||
|
QString byte;
|
||||||
|
byte.setNum ((quint8) data.at (n + i + IPI_LENGTH), 16);
|
||||||
|
|
||||||
|
/* Add the obtained string */
|
||||||
|
ip += byte;
|
||||||
|
|
||||||
|
/* Append colons after even indexes (except in the last byte) */
|
||||||
|
if ((i & 1) == 0 && (i < length))
|
||||||
|
ip += ":";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increase the counter to 'jump' to the next section */
|
||||||
|
n += 26;
|
||||||
|
|
||||||
|
/* Append the obtained IP to the list */
|
||||||
|
if (!list.contains (ip))
|
||||||
|
list.append (ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the IPv4 and IPv6 addresses from the received data.
|
||||||
|
* \note This function will only generate a list with the valid IP addresses.
|
||||||
|
*/
|
||||||
|
QList<QHostAddress> qMDNS::getAddressesFromResponse (const QByteArray& data,
|
||||||
|
const QString& host) {
|
||||||
|
QList<QHostAddress> list;
|
||||||
|
|
||||||
|
/* Add IPv4 address */
|
||||||
|
QHostAddress IPv4Address = QHostAddress (getIPv4FromResponse (data, host));
|
||||||
|
if (!IPv4Address.isNull())
|
||||||
|
list.append (IPv4Address);
|
||||||
|
|
||||||
|
/* Add IPv6 addresses */
|
||||||
|
foreach (QString ip, getIPv6FromResponse (data, host)) {
|
||||||
|
QHostAddress address = QHostAddress (ip);
|
||||||
|
if (!address.isNull())
|
||||||
|
list.append (address);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
84
src/qMDNS/qMDNS.h
Normal file
84
src/qMDNS/qMDNS.h
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Alex Spataru <alex_spataru@outlook.com>
|
||||||
|
*
|
||||||
|
* This file is part of qMDNS, which is released under the MIT license.
|
||||||
|
* For more information, please read the LICENSE file in the root directory
|
||||||
|
* of this project.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Modified May 2017 By Ken Moore <ken@ixsystems.com>
|
||||||
|
// to provide caching/results of the network at any point in time
|
||||||
|
// available under the 3-clause BSD license (or MIT license if preferred)
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QHostInfo>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
|
class QHostInfo;
|
||||||
|
class QUdpSocket;
|
||||||
|
class QHostAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Implements a simple mDNS responder using Qt
|
||||||
|
*
|
||||||
|
* This implementation is able perform mDNS queries and mDNS responses in any
|
||||||
|
* operating system supported by the Qt network module.
|
||||||
|
*
|
||||||
|
* You can obtain the IP of an mDNS device using the \c lookup() function,
|
||||||
|
* the \c hostFound() signal will be emitted whenever this class interprets
|
||||||
|
* a mDNS response packet and obtains valid information about a remote host.
|
||||||
|
*
|
||||||
|
* You can change the name that the local computer uses to identify itself
|
||||||
|
* in the mDNS network using the \c setHostName() function.
|
||||||
|
*
|
||||||
|
* \todo Implement NSEC block code generation in the \c sendResponse() packet
|
||||||
|
*/
|
||||||
|
class qMDNS : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void hostFound (const QHostInfo& info);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static qMDNS* getInstance();
|
||||||
|
|
||||||
|
QString hostName() const;
|
||||||
|
QString getAddress (const QString& string);
|
||||||
|
|
||||||
|
QList<QHostInfo> knownHosts(); // KM: return list of known/available hosts (those active within the last 15 minutes)
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit qMDNS();
|
||||||
|
~qMDNS();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setTTL (const quint32 ttl);
|
||||||
|
void lookup (const QString& name);
|
||||||
|
void setHostName (const QString& name);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onReadyRead();
|
||||||
|
void readQuery (const QByteArray& data);
|
||||||
|
void sendPacket (const QByteArray& data);
|
||||||
|
void readResponse (const QByteArray& data);
|
||||||
|
void sendResponse (const quint16 query_id);
|
||||||
|
void NewHostFound(QHostInfo info); // KM: internal slot for caching the new host information
|
||||||
|
void cleanCache(); //KM: internal slot for cleaning out old cached info on a regular basis
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString getHostNameFromResponse (const QByteArray& data);
|
||||||
|
QString getIPv4FromResponse (const QByteArray& data, const QString& host);
|
||||||
|
QStringList getIPv6FromResponse (const QByteArray& data, const QString& host);
|
||||||
|
QList<QHostAddress> getAddressesFromResponse (const QByteArray& data,
|
||||||
|
const QString& host);
|
||||||
|
|
||||||
|
private:
|
||||||
|
quint32 m_ttl;
|
||||||
|
QString m_hostName;
|
||||||
|
QUdpSocket* m_IPv4Socket;
|
||||||
|
QUdpSocket* m_IPv6Socket;
|
||||||
|
QHash<QDateTime, QHostInfo> *knownHash; //KM: internal cache for the host addresses that were found
|
||||||
|
QTimer *cacheCleanTimer; //KM: Timer for cleaning up old entries in the cache
|
||||||
|
};
|
||||||
7
src/qMDNS/qMDNS.pri
Normal file
7
src/qMDNS/qMDNS.pri
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
QT *= core network
|
||||||
|
|
||||||
|
INCLUDEPATH *= $$PWD
|
||||||
|
|
||||||
|
HEADERS *= $$PWD/qMDNS.h
|
||||||
|
|
||||||
|
SOURCES *= $$PWD/qMDNS.cpp
|
||||||
@@ -33,7 +33,7 @@ void DProcess::procReady(){
|
|||||||
rawcmds = cmds;
|
rawcmds = cmds;
|
||||||
proclog.insert("cmd_list",QJsonArray::fromStringList(cmds));
|
proclog.insert("cmd_list",QJsonArray::fromStringList(cmds));
|
||||||
proclog.insert("process_id",ID);
|
proclog.insert("process_id",ID);
|
||||||
proclog.insert("state","pending");
|
proclog.insert("state","pending");
|
||||||
this->emit ProcUpdate(ID, proclog);
|
this->emit ProcUpdate(ID, proclog);
|
||||||
uptimer->setSingleShot(false);
|
uptimer->setSingleShot(false);
|
||||||
uptimer->setInterval(2000); //2 second intervals for "pending" pings
|
uptimer->setInterval(2000); //2 second intervals for "pending" pings
|
||||||
@@ -42,12 +42,12 @@ void DProcess::procReady(){
|
|||||||
|
|
||||||
void DProcess::startProc(){
|
void DProcess::startProc(){
|
||||||
cmds.removeAll(""); //make sure no empty commands
|
cmds.removeAll(""); //make sure no empty commands
|
||||||
if(cmds.isEmpty()){
|
if(cmds.isEmpty()){
|
||||||
proclog.insert("state","finished");
|
proclog.insert("state","finished");
|
||||||
proclog.insert("time_finished", QDateTime::currentDateTime().toString(Qt::ISODate));
|
proclog.insert("time_finished", QDateTime::currentDateTime().toString(Qt::ISODate));
|
||||||
proclog.remove("current_cmd");
|
proclog.remove("current_cmd");
|
||||||
emit ProcFinished(ID, proclog);
|
emit ProcFinished(ID, proclog);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(proclog.value("state").toString()=="pending"){
|
if(proclog.value("state").toString()=="pending"){
|
||||||
//first cmd started
|
//first cmd started
|
||||||
@@ -66,7 +66,7 @@ void DProcess::startProc(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool DProcess::isRunning(){
|
bool DProcess::isRunning(){
|
||||||
return (this->state()!=QProcess::NotRunning);
|
return (this->state()!=QProcess::NotRunning);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DProcess::isDone(){
|
bool DProcess::isDone(){
|
||||||
@@ -90,10 +90,10 @@ void DProcess::cmdFinished(int ret, QProcess::ExitStatus status){
|
|||||||
//update the log before starting another command
|
//update the log before starting another command
|
||||||
proclog.insert(cCmd, proclog.value(cCmd).toString().append(this->readAllStandardOutput()) );
|
proclog.insert(cCmd, proclog.value(cCmd).toString().append(this->readAllStandardOutput()) );
|
||||||
proclog.insert("return_codes/"+cCmd, QString::number(ret));
|
proclog.insert("return_codes/"+cCmd, QString::number(ret));
|
||||||
|
|
||||||
//Now run any additional commands
|
//Now run any additional commands
|
||||||
//qDebug() << "Proc Finished:" << ID << success << proclog;
|
//qDebug() << "Proc Finished:" << ID << success << proclog;
|
||||||
if(success && !cmds.isEmpty()){
|
if(success && !cmds.isEmpty()){
|
||||||
emit ProcUpdate(ID, proclog);
|
emit ProcUpdate(ID, proclog);
|
||||||
startProc();
|
startProc();
|
||||||
}else{
|
}else{
|
||||||
@@ -105,12 +105,18 @@ void DProcess::cmdFinished(int ret, QProcess::ExitStatus status){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DProcess::updateLog(){
|
void DProcess::updateLog(){
|
||||||
proclog.insert(cCmd, proclog.value(cCmd).toString().append(this->readAllStandardOutput()) );
|
QString tmp = this->readAllStandardOutput();
|
||||||
|
lognew.append(tmp);
|
||||||
|
proclog.insert(cCmd, proclog.value(cCmd).toString().append(tmp) );
|
||||||
if(!uptimer->isActive()){ uptimer->start(); }
|
if(!uptimer->isActive()){ uptimer->start(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
void DProcess::emitUpdate(){
|
void DProcess::emitUpdate(){
|
||||||
emit ProcUpdate(ID, proclog);
|
QJsonObject tmp = proclog;
|
||||||
|
//only emit the latest changes to the log - not the full thing
|
||||||
|
tmp.insert(cCmd, lognew );
|
||||||
|
emit ProcUpdate(ID, tmp);
|
||||||
|
lognew.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================
|
// ================================
|
||||||
@@ -123,7 +129,7 @@ Dispatcher::Dispatcher(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
Dispatcher::~Dispatcher(){
|
Dispatcher::~Dispatcher(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject Dispatcher::listJobs(){
|
QJsonObject Dispatcher::listJobs(){
|
||||||
@@ -153,7 +159,7 @@ QJsonObject Dispatcher::listJobs(){
|
|||||||
}
|
}
|
||||||
out.insert(qname,obj);
|
out.insert(qname,obj);
|
||||||
}
|
}
|
||||||
} //end loop over queue types
|
} //end loop over queue types
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,6 +182,24 @@ QJsonObject Dispatcher::killJobs(QStringList ids){
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Dispatcher::isJobActive(QString ID){
|
||||||
|
//qDebug() << " - Is Job Active:" << ID;
|
||||||
|
for(int i=0; i<enum_length; i++){
|
||||||
|
PROC_QUEUE queue = static_cast<PROC_QUEUE>(i);
|
||||||
|
if(HASH.contains(queue)){
|
||||||
|
QList<DProcess*> list = HASH[queue];
|
||||||
|
for(int j=0; j<list.length(); j++){
|
||||||
|
if(ID == list[j]->ID){
|
||||||
|
//qDebug() << " -- " << !list[j]->isDone();
|
||||||
|
return !(list[j]->isDone());
|
||||||
|
}
|
||||||
|
} //end loop over list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//qDebug() << " -- NO";
|
||||||
|
return false; //could not find process with this ID
|
||||||
|
}
|
||||||
|
|
||||||
void Dispatcher::start(QString queuefile){
|
void Dispatcher::start(QString queuefile){
|
||||||
//Setup connections here (in case it was moved to different thread after creation)
|
//Setup connections here (in case it was moved to different thread after creation)
|
||||||
//connect(this, SIGNAL(mkprocs(Dispatcher::PROC_QUEUE, DProcess*)), this, SLOT(mkProcs(Dispatcher::PROC_QUEUE, DProcess*)) );
|
//connect(this, SIGNAL(mkprocs(Dispatcher::PROC_QUEUE, DProcess*)), this, SLOT(mkProcs(Dispatcher::PROC_QUEUE, DProcess*)) );
|
||||||
@@ -190,41 +214,42 @@ void Dispatcher::stop(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Overloaded Main Calling Functions (single command, or multiple in-order commands)
|
//Overloaded Main Calling Functions (single command, or multiple in-order commands)
|
||||||
DProcess* Dispatcher::queueProcess(QString ID, QString cmd){
|
DProcess* Dispatcher::queueProcess(QString ID, QString cmd, QString workdir){
|
||||||
return queueProcess(NO_QUEUE, ID, QStringList() << cmd);
|
return queueProcess(NO_QUEUE, ID, QStringList() << cmd, workdir);
|
||||||
}
|
}
|
||||||
DProcess* Dispatcher::queueProcess(QString ID, QStringList cmds){
|
DProcess* Dispatcher::queueProcess(QString ID, QStringList cmds, QString workdir){
|
||||||
return queueProcess(NO_QUEUE, ID, cmds);
|
return queueProcess(NO_QUEUE, ID, cmds, workdir);
|
||||||
}
|
}
|
||||||
DProcess* Dispatcher::queueProcess(Dispatcher::PROC_QUEUE queue, QString ID, QString cmd){
|
DProcess* Dispatcher::queueProcess(Dispatcher::PROC_QUEUE queue, QString ID, QString cmd, QString workdir){
|
||||||
return queueProcess(queue, ID, QStringList() << cmd);
|
return queueProcess(queue, ID, QStringList() << cmd, workdir);
|
||||||
}
|
}
|
||||||
DProcess* Dispatcher::queueProcess(Dispatcher::PROC_QUEUE queue, QString ID, QStringList cmds){
|
DProcess* Dispatcher::queueProcess(Dispatcher::PROC_QUEUE queue, QString ID, QStringList cmds, QString workdir){
|
||||||
//This is the primary queueProcess() function - all the overloads end up here to do the actual work
|
//This is the primary queueProcess() function - all the overloads end up here to do the actual work
|
||||||
//For multi-threading, need to emit a signal/slot for this action (object creations need to be in same thread as parent)
|
//For multi-threading, need to emit a signal/slot for this action (object creations need to be in same thread as parent)
|
||||||
//qDebug() << "Queue Process:" << queue << ID << cmds;
|
//qDebug() << "Queue Process:" << queue << ID << cmds;
|
||||||
DProcess *P = createProcess(ID, cmds);
|
DProcess *P = createProcess(ID, cmds, workdir);
|
||||||
this->emit mkprocs(queue, P);
|
this->emit mkprocs(queue, P);
|
||||||
return P;
|
return P;
|
||||||
}
|
}
|
||||||
|
|
||||||
// === PRIVATE ===
|
// === PRIVATE ===
|
||||||
//Simplification routine for setting up a process
|
//Simplification routine for setting up a process
|
||||||
DProcess* Dispatcher::createProcess(QString ID, QStringList cmds){
|
DProcess* Dispatcher::createProcess(QString ID, QStringList cmds, QString workdir){
|
||||||
DProcess *P = new DProcess();
|
DProcess *P = new DProcess();
|
||||||
P->moveToThread(this->thread());
|
P->moveToThread(this->thread());
|
||||||
P->cmds = cmds;
|
P->cmds = cmds;
|
||||||
P->ID = ID;
|
P->ID = ID;
|
||||||
|
if(!workdir.isEmpty()){ P->setWorkingDirectory(workdir); }
|
||||||
return P;
|
return P;
|
||||||
}
|
}
|
||||||
|
|
||||||
// === PRIVATE SLOTS ===
|
// === PRIVATE SLOTS ===
|
||||||
void Dispatcher::mkProcs(Dispatcher::PROC_QUEUE queue, DProcess *P){
|
void Dispatcher::mkProcs(Dispatcher::PROC_QUEUE queue, DProcess *P){
|
||||||
//qDebug() << "mkProcs()";
|
//qDebug() << "mkProcs()";
|
||||||
QList<DProcess*> list = HASH.value(queue);
|
QList<DProcess*> list = HASH.value(queue);
|
||||||
list << P;
|
list << P;
|
||||||
//qDebug() << " - add to queue:" << queue;
|
//qDebug() << " - add to queue:" << queue;
|
||||||
HASH.insert(queue,list);
|
HASH.insert(queue,list);
|
||||||
connect(P, SIGNAL(ProcFinished(QString, QJsonObject)), this, SLOT(ProcFinished(QString, QJsonObject)) );
|
connect(P, SIGNAL(ProcFinished(QString, QJsonObject)), this, SLOT(ProcFinished(QString, QJsonObject)) );
|
||||||
connect(P, SIGNAL(ProcUpdate(QString, QJsonObject)), this, SLOT(ProcUpdated(QString, QJsonObject)) );
|
connect(P, SIGNAL(ProcUpdate(QString, QJsonObject)), this, SLOT(ProcUpdated(QString, QJsonObject)) );
|
||||||
P->procReady();
|
P->procReady();
|
||||||
@@ -236,7 +261,7 @@ void Dispatcher::ProcFinished(QString ID, QJsonObject log){
|
|||||||
//qDebug() << " - Got Proc Finished Signal:" << ID;
|
//qDebug() << " - Got Proc Finished Signal:" << ID;
|
||||||
LogManager::log(LogManager::DISPATCH, log);
|
LogManager::log(LogManager::DISPATCH, log);
|
||||||
//First emit any subsystem-specific event, falling back on the raw log
|
//First emit any subsystem-specific event, falling back on the raw log
|
||||||
QJsonObject ev = CreateDispatcherEventNotification(ID,log);
|
QJsonObject ev = CreateDispatcherEventNotification(ID,log, true);
|
||||||
if(!ev.isEmpty()){
|
if(!ev.isEmpty()){
|
||||||
emit DispatchEvent(ev);
|
emit DispatchEvent(ev);
|
||||||
}else{
|
}else{
|
||||||
@@ -247,7 +272,7 @@ void Dispatcher::ProcFinished(QString ID, QJsonObject log){
|
|||||||
|
|
||||||
void Dispatcher::ProcUpdated(QString ID, QJsonObject log){
|
void Dispatcher::ProcUpdated(QString ID, QJsonObject log){
|
||||||
//See if this needs to generate an event
|
//See if this needs to generate an event
|
||||||
QJsonObject ev = CreateDispatcherEventNotification(ID,log);
|
QJsonObject ev = CreateDispatcherEventNotification(ID,log, false);
|
||||||
if(!ev.isEmpty()){
|
if(!ev.isEmpty()){
|
||||||
emit DispatchEvent(ev);
|
emit DispatchEvent(ev);
|
||||||
}
|
}
|
||||||
@@ -280,6 +305,6 @@ for(int i=0; i<enum_length; i++){
|
|||||||
}
|
}
|
||||||
} //end loop over list
|
} //end loop over list
|
||||||
}
|
}
|
||||||
|
|
||||||
} //end loop over queue types
|
} //end loop over queue types
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class DProcess : public QProcess{
|
|||||||
public:
|
public:
|
||||||
DProcess(QObject *parent = 0);
|
DProcess(QObject *parent = 0);
|
||||||
~DProcess();
|
~DProcess();
|
||||||
|
|
||||||
QString ID;
|
QString ID;
|
||||||
QStringList cmds;
|
QStringList cmds;
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ public slots:
|
|||||||
void startProc();
|
void startProc();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString cCmd;
|
QString cCmd, lognew;
|
||||||
QJsonObject proclog;
|
QJsonObject proclog;
|
||||||
QTimer *uptimer;
|
QTimer *uptimer;
|
||||||
|
|
||||||
@@ -50,19 +50,20 @@ signals:
|
|||||||
//Generic signals for subsystem usage (no direct proc access later)
|
//Generic signals for subsystem usage (no direct proc access later)
|
||||||
void ProcUpdate(QString, QJsonObject); // ID/log
|
void ProcUpdate(QString, QJsonObject); // ID/log
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Dispatcher : public QObject{
|
class Dispatcher : public QObject{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
enum PROC_QUEUE { NO_QUEUE = 0, PKG_QUEUE, IOCAGE_QUEUE };
|
enum PROC_QUEUE { NO_QUEUE = 0, PKG_QUEUE, IOCAGE_QUEUE };
|
||||||
#define enum_length 3 //This needs to be the number of items in the enum above
|
#define enum_length 3 //This needs to be the number of items in the enum above
|
||||||
|
|
||||||
Dispatcher();
|
Dispatcher();
|
||||||
~Dispatcher();
|
~Dispatcher();
|
||||||
|
|
||||||
QJsonObject listJobs();
|
QJsonObject listJobs();
|
||||||
QJsonObject killJobs(QStringList ids);
|
QJsonObject killJobs(QStringList ids);
|
||||||
|
bool isJobActive(QString ID); //returns true if a job with this ID is running/pending
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
//Main start/stop
|
//Main start/stop
|
||||||
@@ -70,21 +71,21 @@ public slots:
|
|||||||
void stop(); //save any currently-unrun processes for next time
|
void stop(); //save any currently-unrun processes for next time
|
||||||
|
|
||||||
//Main Calling Functions (single command, or multiple in-order commands)
|
//Main Calling Functions (single command, or multiple in-order commands)
|
||||||
DProcess* queueProcess(QString ID, QString cmd); //uses NO_QUEUE
|
DProcess* queueProcess(QString ID, QString cmd, QString workdir = ""); //uses NO_QUEUE
|
||||||
DProcess* queueProcess(QString ID, QStringList cmds); //uses NO_QUEUE
|
DProcess* queueProcess(QString ID, QStringList cmds, QString workdir = ""); //uses NO_QUEUE
|
||||||
DProcess* queueProcess(Dispatcher::PROC_QUEUE, QString ID, QString cmd);
|
DProcess* queueProcess(Dispatcher::PROC_QUEUE, QString ID, QString cmd, QString workdir = "");
|
||||||
DProcess* queueProcess(Dispatcher::PROC_QUEUE, QString ID, QStringList cmds);
|
DProcess* queueProcess(Dispatcher::PROC_QUEUE, QString ID, QStringList cmds, QString workdir = "");
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Queue file
|
// Queue file
|
||||||
QString queue_file;
|
QString queue_file;
|
||||||
|
|
||||||
//Internal lists
|
//Internal lists
|
||||||
QHash<PROC_QUEUE, QList<DProcess*> > HASH;
|
QHash<PROC_QUEUE, QList<DProcess*> > HASH;
|
||||||
|
|
||||||
//Simplification routine for setting up a process
|
//Simplification routine for setting up a process
|
||||||
DProcess* createProcess(QString ID, QStringList cmds);
|
DProcess* createProcess(QString ID, QStringList cmds, QString workdir = "");
|
||||||
QJsonObject CreateDispatcherEventNotification(QString, QJsonObject);
|
QJsonObject CreateDispatcherEventNotification(QString, QJsonObject, bool);
|
||||||
|
|
||||||
// Functions to do parsing out dispatcher queued tasks
|
// Functions to do parsing out dispatcher queued tasks
|
||||||
// Please keep these sorted
|
// Please keep these sorted
|
||||||
@@ -104,7 +105,7 @@ signals:
|
|||||||
//Signals for private usage
|
//Signals for private usage
|
||||||
void mkprocs(Dispatcher::PROC_QUEUE, DProcess*);
|
void mkprocs(Dispatcher::PROC_QUEUE, DProcess*);
|
||||||
void checkProcs();
|
void checkProcs();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -9,8 +9,13 @@
|
|||||||
#include "globals-qt.h"
|
#include "globals-qt.h"
|
||||||
#include "EventWatcher.h"
|
#include "EventWatcher.h"
|
||||||
#include "Dispatcher.h"
|
#include "Dispatcher.h"
|
||||||
|
#include "library/sysadm-update.h"
|
||||||
|
#include "library/sysadm-sourcectl.h"
|
||||||
|
|
||||||
|
|
||||||
|
QJsonObject Dispatcher::CreateDispatcherEventNotification(QString ID, QJsonObject log, bool full_log){
|
||||||
|
//NOTE: full_log = true when the process has finished. If it is false, the process is still running and you are probably getting an incremental update of the process log
|
||||||
|
|
||||||
QJsonObject Dispatcher::CreateDispatcherEventNotification(QString ID, QJsonObject log){
|
|
||||||
//key outputs - need to set these if an event is going to be sent out
|
//key outputs - need to set these if an event is going to be sent out
|
||||||
QJsonObject args; //any arguments to send out
|
QJsonObject args; //any arguments to send out
|
||||||
QString namesp, name; //the namespace/name of the subsystem used
|
QString namesp, name; //the namespace/name of the subsystem used
|
||||||
@@ -26,7 +31,7 @@ QJsonObject Dispatcher::CreateDispatcherEventNotification(QString ID, QJsonObjec
|
|||||||
//Add the generic process values
|
//Add the generic process values
|
||||||
args.insert("state",log.value("state").toString());
|
args.insert("state",log.value("state").toString());
|
||||||
args.insert("process_details", log); //full process log array here
|
args.insert("process_details", log); //full process log array here
|
||||||
|
|
||||||
//Now parse the notification based on the dispatch ID or current command
|
//Now parse the notification based on the dispatch ID or current command
|
||||||
//NOTE: There might be a random string on the end of the ID (to accomodate similar process calls)
|
//NOTE: There might be a random string on the end of the ID (to accomodate similar process calls)
|
||||||
// == sysadm/iohyve ==
|
// == sysadm/iohyve ==
|
||||||
@@ -37,14 +42,18 @@ QJsonObject Dispatcher::CreateDispatcherEventNotification(QString ID, QJsonObjec
|
|||||||
//Do some parsing of the log
|
//Do some parsing of the log
|
||||||
parseIohyveFetchOutput(cLog,&args);
|
parseIohyveFetchOutput(cLog,&args);
|
||||||
}
|
}
|
||||||
|
|
||||||
// == sysadm/update ==
|
// == sysadm/update ==
|
||||||
}else if(ID.startsWith("sysadm_update")){
|
}else if(ID.startsWith("sysadm_update")){
|
||||||
namesp = "sysadm"; name="update";
|
if(ID.section("::",0,0)=="sysadm_update_runupdates"){
|
||||||
//No special parsing here: the pc-updatemanager output should be available as-is
|
namesp = "sysadm"; name="update";
|
||||||
args.insert("update_log",cLog);
|
//No special parsing here: the pc-updatemanager output should be available as-is
|
||||||
|
args.insert("update_log",cLog);
|
||||||
|
}else if(isFinished && full_log && ID.section("::",0,0)=="sysadm_update_checkupdates"){
|
||||||
|
//qDebug() << "Got update check process finished";
|
||||||
|
sysadm::Update::saveCheckUpdateLog(cLog); //save this for use later
|
||||||
|
}
|
||||||
|
|
||||||
// == sysadm/pkg ==
|
// == sysadm/pkg ==
|
||||||
}else if(ID.startsWith("sysadm_pkg")){
|
}else if(ID.startsWith("sysadm_pkg")){
|
||||||
namesp = "sysadm"; name="pkg";
|
namesp = "sysadm"; name="pkg";
|
||||||
@@ -56,7 +65,7 @@ QJsonObject Dispatcher::CreateDispatcherEventNotification(QString ID, QJsonObjec
|
|||||||
bool hasupdates = !cLog.contains("Your packages are up to date.");
|
bool hasupdates = !cLog.contains("Your packages are up to date.");
|
||||||
args.insert("updates_available", hasupdates ? "true" : "false");
|
args.insert("updates_available", hasupdates ? "true" : "false");
|
||||||
}
|
}
|
||||||
|
|
||||||
}else if(ID.section("-",0,0)=="sysadm_pkg_audit" && isFinished){
|
}else if(ID.section("-",0,0)=="sysadm_pkg_audit" && isFinished){
|
||||||
QStringList info = cLog.split("\n");
|
QStringList info = cLog.split("\n");
|
||||||
QStringList vuln, effects;
|
QStringList vuln, effects;
|
||||||
@@ -71,11 +80,21 @@ QJsonObject Dispatcher::CreateDispatcherEventNotification(QString ID, QJsonObjec
|
|||||||
args.insert("vulnerable_pkgs",QJsonArray::fromStringList(vuln));
|
args.insert("vulnerable_pkgs",QJsonArray::fromStringList(vuln));
|
||||||
args.insert("impacts_pkgs",QJsonArray::fromStringList(effects));
|
args.insert("impacts_pkgs",QJsonArray::fromStringList(effects));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// == sysadm/sourcecrl ==
|
||||||
|
}else if(ID.startsWith("sysadm_sourcectl_")){
|
||||||
|
QString type = ID.section("::",0,0).section("_",2,-1); //type of sourcectl process
|
||||||
|
namesp = "sysadm"; name="sourcectl";
|
||||||
|
//No special parsing here: the git output should be available as-is
|
||||||
|
args.insert("update_log",cLog);
|
||||||
|
if(full_log){
|
||||||
|
//qDebug() << "Got update check process finished";
|
||||||
|
sysadm::sourcectl::savePortsLog(cLog); //save this for use later
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Now assemble the output as needed
|
//Now assemble the output as needed
|
||||||
if(namesp.isEmpty() || name.isEmpty()){ return QJsonObject(); } //no event
|
if(namesp.isEmpty() || name.isEmpty() || args.isEmpty()){ return QJsonObject(); } //no event
|
||||||
args.insert("event_system",namesp+"/"+name);
|
args.insert("event_system",namesp+"/"+name);
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
@@ -93,3 +112,7 @@ void Dispatcher::parseIohyveFetchOutput(QString outputLog, QJsonObject *out){
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*void Dispatcher::parseUpdateCheckOutput(QString outputLog, QJsonObject *out){
|
||||||
|
|
||||||
|
}*/
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ void EventWatcher::start(){
|
|||||||
// - Life Preserver Events
|
// - Life Preserver Events
|
||||||
WatcherUpdate(LPLOG); //load it initially (will also add it to the watcher);
|
WatcherUpdate(LPLOG); //load it initially (will also add it to the watcher);
|
||||||
WatcherUpdate(LPERRLOG); //load it initially (will also add it to the watcher);
|
WatcherUpdate(LPERRLOG); //load it initially (will also add it to the watcher);
|
||||||
|
|
||||||
filechecktimer->start();
|
filechecktimer->start();
|
||||||
syschecktimer->start();
|
syschecktimer->start();
|
||||||
QTimer::singleShot(60000, this, SLOT(CheckSystemState()) ); //wait 1 minute for networking to settle down first
|
QTimer::singleShot(60000, this, SLOT(CheckSystemState()) ); //wait 1 minute for networking to settle down first
|
||||||
@@ -64,7 +64,7 @@ QString EventWatcher::typeToString(EventWatcher::EVENT_TYPE typ){
|
|||||||
QJsonValue EventWatcher::lastEvent(EVENT_TYPE type){
|
QJsonValue EventWatcher::lastEvent(EVENT_TYPE type){
|
||||||
CheckLogFiles();
|
CheckLogFiles();
|
||||||
if(HASH.contains(type)){ return HASH.value(type); }
|
if(HASH.contains(type)){ return HASH.value(type); }
|
||||||
else{ qDebug() << "No saved event:" << type; return QJsonValue(); }
|
else{ return QJsonValue(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// === PRIVATE ===
|
// === PRIVATE ===
|
||||||
@@ -88,11 +88,11 @@ QString EventWatcher::readFile(QString path){
|
|||||||
QString contents = in.readAll();
|
QString contents = in.readAll();
|
||||||
file.close();
|
file.close();
|
||||||
if(contents.endsWith("\n")){ contents.chop(1); }
|
if(contents.endsWith("\n")){ contents.chop(1); }
|
||||||
return contents;
|
return contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
double EventWatcher::displayToDoubleK(QString displayNumber){
|
double EventWatcher::displayToDoubleK(QString displayNumber){
|
||||||
QStringList labels;
|
QStringList labels;
|
||||||
labels << "K" << "M" << "G" << "T" << "P" << "E";
|
labels << "K" << "M" << "G" << "T" << "P" << "E";
|
||||||
QString clab = displayNumber.right(1); //last character is the size label
|
QString clab = displayNumber.right(1); //last character is the size label
|
||||||
displayNumber.chop(1); //remove the label from the number
|
displayNumber.chop(1); //remove the label from the number
|
||||||
@@ -122,12 +122,12 @@ void EventWatcher::DispatchStarting(QString ID){
|
|||||||
void EventWatcher::DispatchEvent(QJsonObject obj){
|
void EventWatcher::DispatchEvent(QJsonObject obj){
|
||||||
LogManager::log(LogManager::EV_DISPATCH, obj);
|
LogManager::log(LogManager::EV_DISPATCH, obj);
|
||||||
//qDebug() << "Got Dispatch Finished: sending event...";
|
//qDebug() << "Got Dispatch Finished: sending event...";
|
||||||
emit NewEvent(DISPATCHER, obj);
|
emit NewEvent(DISPATCHER, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
// === PRIVATE SLOTS ===
|
// === PRIVATE SLOTS ===
|
||||||
void EventWatcher::WatcherUpdate(const QString &path){
|
void EventWatcher::WatcherUpdate(const QString &path){
|
||||||
if(!starting){ qDebug() << "Event Watcher Update:" << path; }
|
//if(!starting){ qDebug() << "Event Watcher Update:" << path; }
|
||||||
if(path==LPLOG){
|
if(path==LPLOG){
|
||||||
//Main Life Preserver Log File
|
//Main Life Preserver Log File
|
||||||
ReadLPLogFile();
|
ReadLPLogFile();
|
||||||
@@ -159,11 +159,12 @@ void EventWatcher::CheckLogFiles(){
|
|||||||
void EventWatcher::ReadLPLogFile(){
|
void EventWatcher::ReadLPLogFile(){
|
||||||
//Open/Read any new info in the file
|
//Open/Read any new info in the file
|
||||||
QFile LPlogfile(LPLOG);
|
QFile LPlogfile(LPLOG);
|
||||||
|
if( !LPlogfile.exists() ){ return; }
|
||||||
if( !LPlogfile.open(QIODevice::ReadOnly) ){ return; } //could not open file
|
if( !LPlogfile.open(QIODevice::ReadOnly) ){ return; } //could not open file
|
||||||
QTextStream STREAM(&LPlogfile);
|
QTextStream STREAM(&LPlogfile);
|
||||||
qint64 LPlog_pos = CONFIG->value("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-log-pos",0).toLongLong();
|
qint64 LPlog_pos = CONFIG->value("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-log-pos",0).toLongLong();
|
||||||
if(LPlog_pos>0 && QFileInfo(LPlogfile).created() < CONFIG->value("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-log-lastread").toDateTime() ){
|
if(LPlog_pos>0 && QFileInfo(LPlogfile).created() < CONFIG->value("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-log-lastread").toDateTime() ){
|
||||||
STREAM.seek(LPlog_pos);
|
STREAM.seek(LPlog_pos);
|
||||||
}
|
}
|
||||||
QStringList info = STREAM.readAll().split("\n");
|
QStringList info = STREAM.readAll().split("\n");
|
||||||
//Now save the file pointer for later
|
//Now save the file pointer for later
|
||||||
@@ -174,7 +175,7 @@ void EventWatcher::ReadLPLogFile(){
|
|||||||
for(int i=0; i<info.length(); i++){
|
for(int i=0; i<info.length(); i++){
|
||||||
if(info[i].isEmpty()){ continue; }
|
if(info[i].isEmpty()){ continue; }
|
||||||
QString log = info[i];
|
QString log = info[i];
|
||||||
if(!starting){ qDebug() << "Read LP Log File Line:" << log; }
|
// if(!starting){ qDebug() << "Read LP Log File Line:" << log; }
|
||||||
//Divide up the log into it's sections
|
//Divide up the log into it's sections
|
||||||
QString timestamp = log.section(":",0,2).simplified();
|
QString timestamp = log.section(":",0,2).simplified();
|
||||||
QString time = timestamp.section(" ",3,3).simplified();
|
QString time = timestamp.section(" ",3,3).simplified();
|
||||||
@@ -243,16 +244,15 @@ void EventWatcher::ReadLPLogFile(){
|
|||||||
HASH.insert(122, tr("Replication Failed") ); //summary
|
HASH.insert(122, tr("Replication Failed") ); //summary
|
||||||
HASH.insert(123, tt );
|
HASH.insert(123, tt );
|
||||||
HASH.insert(124, timestamp); //full timestamp
|
HASH.insert(124, timestamp); //full timestamp
|
||||||
HASH.insert(125, time); // time only
|
HASH.insert(125, time); // time only
|
||||||
HASH.insert(126, tr("Replication Error Log")+" <"+file+">" );
|
HASH.insert(126, tr("Replication Error Log")+" <"+file+">" );
|
||||||
sendLPEvent("replication", 7, timestamp+": "+tt);
|
sendLPEvent("replication", 7, timestamp+": "+tt);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventWatcher::ReadLPErrFile(){
|
void EventWatcher::ReadLPErrFile(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventWatcher::ReadLPRepFile(){
|
void EventWatcher::ReadLPRepFile(){
|
||||||
@@ -260,7 +260,8 @@ void EventWatcher::ReadLPRepFile(){
|
|||||||
QString repTotK = CONFIG->value("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-rep-totk","").toString();
|
QString repTotK = CONFIG->value("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-rep-totk","").toString();
|
||||||
QString lastSize = CONFIG->value("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-rep-lastsize","").toString();
|
QString lastSize = CONFIG->value("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-rep-lastsize","").toString();
|
||||||
//Open/Read any new info in the file
|
//Open/Read any new info in the file
|
||||||
QFile LPlogfile(LPLOG);
|
QFile LPlogfile(tmpLPRepFile);
|
||||||
|
if( !LPlogfile.exists() ){ return; }
|
||||||
if( !LPlogfile.open(QIODevice::ReadOnly) ){ return; } //could not open file
|
if( !LPlogfile.open(QIODevice::ReadOnly) ){ return; } //could not open file
|
||||||
QTextStream STREAM(&LPlogfile);
|
QTextStream STREAM(&LPlogfile);
|
||||||
qint64 LPrep_pos = CONFIG->value("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-rep-pos",0).toLongLong();
|
qint64 LPrep_pos = CONFIG->value("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-rep-pos",0).toLongLong();
|
||||||
@@ -268,7 +269,7 @@ void EventWatcher::ReadLPRepFile(){
|
|||||||
//New file location
|
//New file location
|
||||||
stat.clear();
|
stat.clear();
|
||||||
repTotK.clear();
|
repTotK.clear();
|
||||||
lastSize.clear();
|
lastSize.clear();
|
||||||
}
|
}
|
||||||
QStringList info = STREAM.readAll().split("\n");
|
QStringList info = STREAM.readAll().split("\n");
|
||||||
CONFIG->setValue("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-rep-pos",STREAM.pos());
|
CONFIG->setValue("internal/"+QString(WS_MODE ? "ws" : "tcp")+"/lp-rep-pos",STREAM.pos());
|
||||||
@@ -283,7 +284,7 @@ void EventWatcher::ReadLPRepFile(){
|
|||||||
else{ stat = line; } //only save the relevant/latest status line
|
else{ stat = line; } //only save the relevant/latest status line
|
||||||
}
|
}
|
||||||
if(!stat.isEmpty()){
|
if(!stat.isEmpty()){
|
||||||
//qDebug() << "New Status Message:" << stat;
|
//qDebug() << "New Status Message:" << stat;
|
||||||
//Divide up the status message into sections
|
//Divide up the status message into sections
|
||||||
stat.replace("\t"," ");
|
stat.replace("\t"," ");
|
||||||
QString dataset = stat.section(" ",2,2,QString::SectionSkipEmpty).section("/",0,0).simplified();
|
QString dataset = stat.section(" ",2,2,QString::SectionSkipEmpty).section("/",0,0).simplified();
|
||||||
@@ -343,7 +344,7 @@ void EventWatcher::CheckSystemState(){
|
|||||||
}
|
}
|
||||||
obj.insert("hostname",oldhostname);
|
obj.insert("hostname",oldhostname);
|
||||||
|
|
||||||
//Next Check zpools
|
//Next Check zpools
|
||||||
QJsonObject zpools = sysadm::ZFS::zpool_list();
|
QJsonObject zpools = sysadm::ZFS::zpool_list();
|
||||||
if(!zpools.isEmpty()){
|
if(!zpools.isEmpty()){
|
||||||
//Scan each pool for any bad indicators
|
//Scan each pool for any bad indicators
|
||||||
@@ -369,10 +370,11 @@ void EventWatcher::CheckSystemState(){
|
|||||||
|
|
||||||
//Next Check for Updates
|
//Next Check for Updates
|
||||||
QJsonObject updates = sysadm::Update::checkUpdates(true); //do the "fast" version of updates
|
QJsonObject updates = sysadm::Update::checkUpdates(true); //do the "fast" version of updates
|
||||||
|
//qDebug() << "Health check - got updates status:" << updates;
|
||||||
if(!updates.isEmpty()){
|
if(!updates.isEmpty()){
|
||||||
if(updates.value("status").toString()!="noupdates"){
|
if(updates.value("status").toString()!="noupdates"){
|
||||||
int tmp = 2;
|
int tmp = 2;
|
||||||
if(updates.value("status").toString()=="rebootrequired"){
|
if(updates.value("status").toString()=="rebootrequired"){
|
||||||
tmp = 9; //user input required
|
tmp = 9; //user input required
|
||||||
//Check if the auto_update_reboot flag is set, and reboot as needed
|
//Check if the auto_update_reboot flag is set, and reboot as needed
|
||||||
QJsonObject upset = sysadm::Update::readSettings();
|
QJsonObject upset = sysadm::Update::readSettings();
|
||||||
@@ -384,10 +386,12 @@ void EventWatcher::CheckSystemState(){
|
|||||||
QDateTime finished = sysadm::Update::rebootRequiredSince();
|
QDateTime finished = sysadm::Update::rebootRequiredSince();
|
||||||
QDateTime cdt = QDateTime::currentDateTime();
|
QDateTime cdt = QDateTime::currentDateTime();
|
||||||
if( (finished.addSecs(60*60*24)<cdt) || cdt.time().hour() == hour){ //more than 24 hours have passed, or time has come
|
if( (finished.addSecs(60*60*24)<cdt) || cdt.time().hour() == hour){ //more than 24 hours have passed, or time has come
|
||||||
sysadm::SysMgmt::systemReboot();
|
sysadm::Update::applyUpdates();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}else if(updates.value("status").toString()=="checkingforupdates"){
|
||||||
|
//do nothing more here - still checking for updates
|
||||||
}else if(updates.value("status").toString()!="updaterunning"){
|
}else if(updates.value("status").toString()!="updaterunning"){
|
||||||
//updates are available - see if the auto-update flag is set, and start the updates as needed
|
//updates are available - see if the auto-update flag is set, and start the updates as needed
|
||||||
QJsonObject upset = sysadm::Update::readSettings();
|
QJsonObject upset = sysadm::Update::readSettings();
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ void LogManager::checkLogDir(){
|
|||||||
QDir dir(logd);
|
QDir dir(logd);
|
||||||
dir.mkpath(logd);
|
dir.mkpath(logd);
|
||||||
}
|
}
|
||||||
int daysold = CONFIG->value("prune_log_days_old",90).toInt(); //90 days by default
|
int daysold = CONFIG->value("prune_log_days_old",30).toInt(); //90 days by default
|
||||||
if(daysold>0){
|
if(daysold>0){
|
||||||
LogManager::pruneLogs(QDate::currentDate().addDays(0-daysold));
|
LogManager::pruneLogs(QDate::currentDate().addDays(0-daysold));
|
||||||
}
|
}
|
||||||
@@ -35,7 +35,7 @@ void LogManager::pruneLogs(QDate olderthan){
|
|||||||
for(int i=0; i<files.length(); i++){
|
for(int i=0; i<files.length(); i++){
|
||||||
QDate fdate = QDate::fromString( files[i].section(".log",0,0).section("-",-3,-1), Qt::ISODate);
|
QDate fdate = QDate::fromString( files[i].section(".log",0,0).section("-",-3,-1), Qt::ISODate);
|
||||||
//qDebug() << "Check File Date:" << fdate << olderthan;
|
//qDebug() << "Check File Date:" << fdate << olderthan;
|
||||||
if( fdate < olderthan && fdate.isValid()){
|
if( fdate < olderthan && fdate.isValid()){
|
||||||
dir.remove(files[i]);
|
dir.remove(files[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "library/sysadm-firewall.h"
|
#include "library/sysadm-firewall.h"
|
||||||
#include "library/sysadm-moused.h"
|
#include "library/sysadm-moused.h"
|
||||||
#include "library/sysadm-powerd.h"
|
#include "library/sysadm-powerd.h"
|
||||||
|
#include "library/sysadm-sourcectl.h"
|
||||||
|
|
||||||
#define DEBUG 0
|
#define DEBUG 0
|
||||||
//#define SCLISTDELIM QString("::::") //SysCache List Delimiter
|
//#define SCLISTDELIM QString("::::") //SysCache List Delimiter
|
||||||
@@ -41,11 +42,10 @@ RestOutputStruct::ExitCode WebSocket::AvailableSubsystems(bool allaccess, QJsonO
|
|||||||
out->insert("rpc/logs", allaccess ? "read/write" : "read");
|
out->insert("rpc/logs", allaccess ? "read/write" : "read");
|
||||||
|
|
||||||
// - beadm
|
// - beadm
|
||||||
if(QFile::exists("/usr/local/sbin/beadm")){
|
if(QFile::exists("/usr/local/sbin/beadm") || QFile::exists("/sbin/beadm") ){
|
||||||
out->insert("sysadm/beadm", "read/write");
|
out->insert("sysadm/beadm", "read/write");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// - dispatcher (Internal to server - always available)
|
// - dispatcher (Internal to server - always available)
|
||||||
//"read" is the event notifications, "write" is the ability to queue up jobs
|
//"read" is the event notifications, "write" is the ability to queue up jobs
|
||||||
out->insert("rpc/dispatcher", allaccess ? "read/write" : "read");
|
out->insert("rpc/dispatcher", allaccess ? "read/write" : "read");
|
||||||
@@ -70,22 +70,22 @@ RestOutputStruct::ExitCode WebSocket::AvailableSubsystems(bool allaccess, QJsonO
|
|||||||
if(QFile::exists("/usr/local/sbin/iohyve")){
|
if(QFile::exists("/usr/local/sbin/iohyve")){
|
||||||
out->insert("sysadm/iohyve", "read/write");
|
out->insert("sysadm/iohyve", "read/write");
|
||||||
}
|
}
|
||||||
|
|
||||||
// - zfs
|
// - zfs
|
||||||
if(QFile::exists("/sbin/zfs") && QFile::exists("/sbin/zpool")){
|
if(QFile::exists("/sbin/zfs") && QFile::exists("/sbin/zpool")){
|
||||||
out->insert("sysadm/zfs", allaccess ? "read/write" : "read");
|
out->insert("sysadm/zfs", allaccess ? "read/write" : "read");
|
||||||
}
|
}
|
||||||
|
|
||||||
// - pkg
|
// - pkg
|
||||||
if(QFile::exists("/usr/local/sbin/pkg")){
|
if(QFile::exists("/usr/local/sbin/pkg") || QFile::exists("/usr/sbin/pkg")){
|
||||||
out->insert("sysadm/pkg", "read/write");
|
out->insert("sysadm/pkg", "read/write");
|
||||||
}
|
}
|
||||||
|
|
||||||
// - Generic system information
|
// - Generic system information
|
||||||
out->insert("sysadm/systemmanager","read/write");
|
out->insert("sysadm/systemmanager","read/write");
|
||||||
|
|
||||||
// - PC-BSD/TrueOS Updater
|
// - Legacy PC-BSD/TrueOS Updater
|
||||||
if(QFile::exists("/usr/local/bin/pc-updatemanager")){
|
if( QFile::exists("/usr/local/bin/pc-updatemanager") ){
|
||||||
out->insert("sysadm/update", "read/write");
|
out->insert("sysadm/update", "read/write");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,6 +104,10 @@ RestOutputStruct::ExitCode WebSocket::AvailableSubsystems(bool allaccess, QJsonO
|
|||||||
if(QFile::exists("/usr/sbin/powerd")){
|
if(QFile::exists("/usr/sbin/powerd")){
|
||||||
out->insert("sysadm/powerd", "read/write");
|
out->insert("sysadm/powerd", "read/write");
|
||||||
}
|
}
|
||||||
|
// - sourcectl
|
||||||
|
if(QFile::exists("/usr/local/bin/git")){
|
||||||
|
out->insert("sysadm/sourcectl", "read/write");
|
||||||
|
}
|
||||||
|
|
||||||
return RestOutputStruct::OK;
|
return RestOutputStruct::OK;
|
||||||
}
|
}
|
||||||
@@ -164,6 +168,8 @@ RestOutputStruct::ExitCode WebSocket::EvaluateBackendRequest(const RestInputStru
|
|||||||
return EvaluateSysadmMousedRequest(IN.args, out);
|
return EvaluateSysadmMousedRequest(IN.args, out);
|
||||||
}else if(namesp=="sysadm" && name=="powerd"){
|
}else if(namesp=="sysadm" && name=="powerd"){
|
||||||
return EvaluateSysadmPowerdRequest(IN.args, out);
|
return EvaluateSysadmPowerdRequest(IN.args, out);
|
||||||
|
}else if(namesp=="sysadm" && name=="sourcectl"){
|
||||||
|
return EvaluateSysadmSourceCTLRequest(IN.args, out);
|
||||||
}else{
|
}else{
|
||||||
return RestOutputStruct::BADREQUEST;
|
return RestOutputStruct::BADREQUEST;
|
||||||
}
|
}
|
||||||
@@ -187,7 +193,7 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmSettingsRequest(const QJsonV
|
|||||||
pub_key = argsO.value("pub_key").toString();
|
pub_key = argsO.value("pub_key").toString();
|
||||||
if(keys.contains("nickname")){ nickname = argsO.value("nickname").toString(); }
|
if(keys.contains("nickname")){ nickname = argsO.value("nickname").toString(); }
|
||||||
if(keys.contains("email")){ email = argsO.value("email").toString(); }
|
if(keys.contains("email")){ email = argsO.value("email").toString(); }
|
||||||
|
|
||||||
if(!pub_key.isEmpty()){
|
if(!pub_key.isEmpty()){
|
||||||
ok = AUTHSYSTEM->RegisterCertificate(SockAuthToken, pub_key, nickname, email);
|
ok = AUTHSYSTEM->RegisterCertificate(SockAuthToken, pub_key, nickname, email);
|
||||||
if(!ok){ return RestOutputStruct::FORBIDDEN; }
|
if(!ok){ return RestOutputStruct::FORBIDDEN; }
|
||||||
@@ -264,7 +270,7 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmLogsRequest(bool allaccess,
|
|||||||
else if(logs[i]=="events-dispatcher"){ log = 2; }
|
else if(logs[i]=="events-dispatcher"){ log = 2; }
|
||||||
else if(logs[i]=="events-lifepreserver"){ log = 3; }
|
else if(logs[i]=="events-lifepreserver"){ log = 3; }
|
||||||
else if(logs[i]=="events-state"){ log = 4; }
|
else if(logs[i]=="events-state"){ log = 4; }
|
||||||
|
|
||||||
if(log>=0){
|
if(log>=0){
|
||||||
QStringList info = LogManager::readLog( (LogManager::LOG_FILE)(log), starttime, endtime);
|
QStringList info = LogManager::readLog( (LogManager::LOG_FILE)(log), starttime, endtime);
|
||||||
//REMINDER of format: "[datetime]<message>"
|
//REMINDER of format: "[datetime]<message>"
|
||||||
@@ -366,7 +372,7 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmBEADMRequest(const QJsonValu
|
|||||||
}else if(act=="umountbe"){
|
}else if(act=="umountbe"){
|
||||||
ok = true;
|
ok = true;
|
||||||
out->insert("umountbe", sysadm::BEADM::umountBE(in_args.toObject()));
|
out->insert("umountbe", sysadm::BEADM::umountBE(in_args.toObject()));
|
||||||
}
|
}
|
||||||
} //end of "action" key usage
|
} //end of "action" key usage
|
||||||
|
|
||||||
//If nothing done - return the proper code
|
//If nothing done - return the proper code
|
||||||
@@ -409,9 +415,9 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmNetworkRequest(const QJsonVa
|
|||||||
bool ok = false;
|
bool ok = false;
|
||||||
if(keys.contains("action")){
|
if(keys.contains("action")){
|
||||||
QString act = JsonValueToString(in_args.toObject().value("action"));
|
QString act = JsonValueToString(in_args.toObject().value("action"));
|
||||||
|
QStringList devs = sysadm::NetDevice::listNetDevices();
|
||||||
if(act=="list-devices"){
|
if(act=="list-devices"){
|
||||||
ok = true;
|
ok = true;
|
||||||
QStringList devs = sysadm::NetDevice::listNetDevices();
|
|
||||||
for(int i=0; i<devs.length(); i++){
|
for(int i=0; i<devs.length(); i++){
|
||||||
sysadm::NetDevice D(devs[i]);
|
sysadm::NetDevice D(devs[i]);
|
||||||
QJsonObject obj;
|
QJsonObject obj;
|
||||||
@@ -428,6 +434,31 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmNetworkRequest(const QJsonVa
|
|||||||
//Add this device info to the main output structure
|
//Add this device info to the main output structure
|
||||||
out->insert(devs[i], obj);
|
out->insert(devs[i], obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}else if(act=="list-settings"){
|
||||||
|
ok = true;
|
||||||
|
for(int i=0; i<devs.length(); i++){
|
||||||
|
sysadm::NetDevSettings D = sysadm::Network::deviceRCSettings(devs[i]);
|
||||||
|
if(D.device.isEmpty()){ continue; } //nothing for this device
|
||||||
|
QJsonObject obj;
|
||||||
|
//assemble the information about this device into an output object
|
||||||
|
obj.insert("device", D.device);
|
||||||
|
obj.insert("associated_device", D.asDevice);
|
||||||
|
obj.insert("use_dhcp", D.useDHCP ? "true" : "false" );
|
||||||
|
obj.insert("static_ipv4", D.staticIPv4);
|
||||||
|
obj.insert("static_ipv6", D.staticIPv6);
|
||||||
|
obj.insert("static_netmask", D.staticNetmask);
|
||||||
|
obj.insert("static_gateway", D.staticGateway);
|
||||||
|
if(D.wifihost){
|
||||||
|
obj.insert("wifi_country", D.wifiCountry);
|
||||||
|
obj.insert("wifi_ssid", D.wifiSSID);
|
||||||
|
obj.insert("wifi_bssid", D.wifiBSSID);
|
||||||
|
obj.insert("wifi_channel", D.wifiChannel);
|
||||||
|
obj.insert("wifi_use_wpa", D.wifisecurity ? "true" : "false");
|
||||||
|
}
|
||||||
|
//Add this device info to the main output structure
|
||||||
|
out->insert(devs[i], obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} //end of "action" key usage
|
} //end of "action" key usage
|
||||||
@@ -529,50 +560,58 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmSystemMgmtRequest(const QJso
|
|||||||
ok = true;
|
ok = true;
|
||||||
out->insert("batteryinfo", sysadm::SysMgmt::batteryInfo());
|
out->insert("batteryinfo", sysadm::SysMgmt::batteryInfo());
|
||||||
}
|
}
|
||||||
if(act=="cpupercentage"){
|
else if(act=="cpupercentage"){
|
||||||
ok = true;
|
ok = true;
|
||||||
out->insert("cpupercentage", sysadm::SysMgmt::cpuPercentage());
|
out->insert("cpupercentage", sysadm::SysMgmt::cpuPercentage());
|
||||||
}
|
}
|
||||||
if(act=="cputemps"){
|
else if(act=="cputemps"){
|
||||||
ok = true;
|
ok = true;
|
||||||
out->insert("cputemps", sysadm::SysMgmt::cpuTemps());
|
out->insert("cputemps", sysadm::SysMgmt::cpuTemps());
|
||||||
}
|
}
|
||||||
if(act=="externalmounts"){
|
else if(act=="externalmounts"){
|
||||||
ok = true;
|
ok = true;
|
||||||
out->insert("externalmounts", sysadm::SysMgmt::externalDevicePaths());
|
out->insert("externalmounts", sysadm::SysMgmt::externalDevicePaths());
|
||||||
}
|
}
|
||||||
if(act=="halt"){
|
else if(act=="halt"){
|
||||||
ok = true;
|
ok = true;
|
||||||
out->insert("halt", sysadm::SysMgmt::systemHalt());
|
out->insert("halt", sysadm::SysMgmt::systemHalt());
|
||||||
}
|
}
|
||||||
if(act=="killproc"){
|
else if(act=="killproc"){
|
||||||
ok = true;
|
ok = true;
|
||||||
out->insert("killproc", sysadm::SysMgmt::killProc(in_args.toObject()));
|
out->insert("killproc", sysadm::SysMgmt::killProc(in_args.toObject()));
|
||||||
}
|
}
|
||||||
if(act=="memorystats"){
|
else if(act=="memorystats"){
|
||||||
ok = true;
|
ok = true;
|
||||||
out->insert("memorystats", sysadm::SysMgmt::memoryStats());
|
out->insert("memorystats", sysadm::SysMgmt::memoryStats());
|
||||||
}
|
}
|
||||||
if(act=="procinfo"){
|
else if(act=="procinfo"){
|
||||||
ok = true;
|
ok = true;
|
||||||
out->insert("procinfo", sysadm::SysMgmt::procInfo());
|
out->insert("procinfo", sysadm::SysMgmt::procInfo());
|
||||||
}
|
}
|
||||||
if(act=="reboot"){
|
else if(act=="reboot"){
|
||||||
ok = true;
|
ok = true;
|
||||||
out->insert("reboot", sysadm::SysMgmt::systemReboot());
|
out->insert("reboot", sysadm::SysMgmt::systemReboot());
|
||||||
}
|
}
|
||||||
if(act=="setsysctl"){
|
else if(act=="getsysctl"){
|
||||||
|
ok = true;
|
||||||
|
out->insert("getsysctl", sysadm::SysMgmt::getSysctl(in_args.toObject()));
|
||||||
|
}
|
||||||
|
else if(act=="setsysctl"){
|
||||||
ok = true;
|
ok = true;
|
||||||
out->insert("setsysctl", sysadm::SysMgmt::setSysctl(in_args.toObject()));
|
out->insert("setsysctl", sysadm::SysMgmt::setSysctl(in_args.toObject()));
|
||||||
}
|
}
|
||||||
if(act=="sysctllist"){
|
else if(act=="sysctllist"){
|
||||||
ok = true;
|
ok = true;
|
||||||
out->insert("sysctllist", sysadm::SysMgmt::sysctlList());
|
out->insert("sysctllist", sysadm::SysMgmt::sysctlList());
|
||||||
}
|
}
|
||||||
if(act=="systeminfo"){
|
else if(act=="systeminfo"){
|
||||||
ok = true;
|
ok = true;
|
||||||
out->insert("systeminfo", sysadm::SysMgmt::systemInfo());
|
out->insert("systeminfo", sysadm::SysMgmt::systemInfo());
|
||||||
}
|
}
|
||||||
|
else if(act=="deviceinfo"){
|
||||||
|
ok = true;
|
||||||
|
out->insert("deviceinfo", sysadm::SysMgmt::systemDevices());
|
||||||
|
}
|
||||||
|
|
||||||
} //end of "action" key usage
|
} //end of "action" key usage
|
||||||
|
|
||||||
@@ -598,11 +637,11 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmUpdateRequest(const QJsonVal
|
|||||||
bool fastcheck = true;
|
bool fastcheck = true;
|
||||||
fastcheck = in_args.toObject().value("force").toString().toLower()!="true";
|
fastcheck = in_args.toObject().value("force").toString().toLower()!="true";
|
||||||
out->insert("checkupdates", sysadm::Update::checkUpdates(fastcheck));
|
out->insert("checkupdates", sysadm::Update::checkUpdates(fastcheck));
|
||||||
|
|
||||||
}else if(act=="listbranches"){
|
}else if(act=="listbranches"){
|
||||||
ok = true;
|
ok = true;
|
||||||
out->insert("listbranches", sysadm::Update::listBranches());
|
out->insert("listbranches", sysadm::Update::listBranches());
|
||||||
|
|
||||||
}else if(act=="startupdate"){
|
}else if(act=="startupdate"){
|
||||||
ok = true;
|
ok = true;
|
||||||
out->insert("startupdate", sysadm::Update::startUpdate(in_args.toObject()) );
|
out->insert("startupdate", sysadm::Update::startUpdate(in_args.toObject()) );
|
||||||
@@ -611,6 +650,10 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmUpdateRequest(const QJsonVal
|
|||||||
ok = true;
|
ok = true;
|
||||||
out->insert("stopupdate", sysadm::Update::stopUpdate() );
|
out->insert("stopupdate", sysadm::Update::stopUpdate() );
|
||||||
|
|
||||||
|
}else if(act=="applyupdate"){
|
||||||
|
ok = true;
|
||||||
|
out->insert("applyupdate", sysadm::Update::applyUpdates() );
|
||||||
|
|
||||||
}else if(act=="listsettings"){
|
}else if(act=="listsettings"){
|
||||||
ok = true;
|
ok = true;
|
||||||
out->insert("listsettings", sysadm::Update::readSettings() );
|
out->insert("listsettings", sysadm::Update::readSettings() );
|
||||||
@@ -650,7 +693,7 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmIocageRequest(const QJsonVal
|
|||||||
QJsonObject retObj;
|
QJsonObject retObj;
|
||||||
if(act=="activatepool"){ retObj = sysadm::Iocage::activatePool(in_args.toObject()); }
|
if(act=="activatepool"){ retObj = sysadm::Iocage::activatePool(in_args.toObject()); }
|
||||||
else if(act=="deactivatepool"){retObj = sysadm::Iocage::deactivatePool(in_args.toObject()); }
|
else if(act=="deactivatepool"){retObj = sysadm::Iocage::deactivatePool(in_args.toObject()); }
|
||||||
|
else if(act=="activatestatus"){ retObj = sysadm::Iocage::activateStatus(); }
|
||||||
/*if(act=="execjail"){
|
/*if(act=="execjail"){
|
||||||
ok = true;
|
ok = true;
|
||||||
out->insert("execjail", sysadm::Iocage::execJail(in_args.toObject()));
|
out->insert("execjail", sysadm::Iocage::execJail(in_args.toObject()));
|
||||||
@@ -675,14 +718,6 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmIocageRequest(const QJsonVal
|
|||||||
ok = true;
|
ok = true;
|
||||||
out->insert("cleanall", sysadm::Iocage::cleanAll());
|
out->insert("cleanall", sysadm::Iocage::cleanAll());
|
||||||
}
|
}
|
||||||
else if(act=="cleantemplates"){
|
|
||||||
ok = true;
|
|
||||||
out->insert("cleantemplates", sysadm::Iocage::cleanTemplates());
|
|
||||||
}
|
|
||||||
else if(act=="cleanreleases"){
|
|
||||||
ok = true;
|
|
||||||
out->insert("cleanreleases", sysadm::Iocage::cleanReleases());
|
|
||||||
}
|
|
||||||
else if(act=="cleanjails"){
|
else if(act=="cleanjails"){
|
||||||
ok = true;
|
ok = true;
|
||||||
out->insert("cleanjails", sysadm::Iocage::cleanJails());
|
out->insert("cleanjails", sysadm::Iocage::cleanJails());
|
||||||
@@ -702,19 +737,21 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmIocageRequest(const QJsonVal
|
|||||||
else if(act=="getjailsettings"){
|
else if(act=="getjailsettings"){
|
||||||
ok = true;
|
ok = true;
|
||||||
out->insert("getjailsettings", sysadm::Iocage::getJailSettings(in_args.toObject()));
|
out->insert("getjailsettings", sysadm::Iocage::getJailSettings(in_args.toObject()));
|
||||||
}
|
|
||||||
else if(act=="listjails"){
|
|
||||||
ok = true;
|
|
||||||
out->insert("listjails", sysadm::Iocage::listJails());
|
|
||||||
}
|
|
||||||
else if(act=="listtemplates"){
|
|
||||||
ok = true;
|
|
||||||
out->insert("listtemplates", sysadm::Iocage::listTemplates());
|
|
||||||
}
|
|
||||||
else if(act=="listreleases"){
|
|
||||||
ok = true;
|
|
||||||
out->insert("listjails", sysadm::Iocage::listReleases());
|
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
//JAILS (GENERIC)
|
||||||
|
else if(act=="listjails"){ retObj = sysadm::Iocage::listJails(); }
|
||||||
|
//TEMPLATES
|
||||||
|
else if(act=="listtemplates"){ retObj = sysadm::Iocage::listTemplates(); }
|
||||||
|
else if(act=="cleantemplates"){ retObj = sysadm::Iocage::cleanTemplates(); }
|
||||||
|
//RELEASES
|
||||||
|
else if(act=="listreleases"){ retObj = sysadm::Iocage::listReleases(); }
|
||||||
|
else if(act=="fetchreleases"){ retObj = sysadm::Iocage::fetchReleases(in_args.toObject()); }
|
||||||
|
else if(act=="cleanreleases"){ retObj = sysadm::Iocage::cleanReleases(); }
|
||||||
|
//PLUGINS
|
||||||
|
else if(act=="listplugins"){ retObj = sysadm::Iocage::listPlugins(); }
|
||||||
|
else if(act=="createplugin"){ retObj = sysadm::Iocage::fetchPlugin(in_args.toObject()); }
|
||||||
|
|
||||||
ok = !retObj.keys().isEmpty();
|
ok = !retObj.keys().isEmpty();
|
||||||
if(ok){ out->insert(act,retObj); }
|
if(ok){ out->insert(act,retObj); }
|
||||||
} //end of "action" key usage
|
} //end of "action" key usage
|
||||||
@@ -863,20 +900,20 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmPkgRequest(const QJsonValue
|
|||||||
if(in_args.toObject().value("pkg_origins").isString()){ pkgs << in_args.toObject().value("pkg_origins").toString(); }
|
if(in_args.toObject().value("pkg_origins").isString()){ pkgs << in_args.toObject().value("pkg_origins").toString(); }
|
||||||
else if(in_args.toObject().value("pkg_origins").isArray()){ pkgs = JsonArrayToStringList(in_args.toObject().value("pkg_origins").toArray()); }
|
else if(in_args.toObject().value("pkg_origins").isArray()){ pkgs = JsonArrayToStringList(in_args.toObject().value("pkg_origins").toArray()); }
|
||||||
}
|
}
|
||||||
|
|
||||||
//Parse the action and perform accordingly
|
//Parse the action and perform accordingly
|
||||||
if(act=="pkg_info"){
|
if(act=="pkg_info"){
|
||||||
//OPTIONAL: "pkg_origins" OR "category"
|
//OPTIONAL: "pkg_origins" OR "category"
|
||||||
//OPTIONAL: "repo"
|
//OPTIONAL: "repo"
|
||||||
//OPTIONAL: "result" = "full" or "simple" (Default: "simple")
|
//OPTIONAL: "result" = "full" or "simple" (Default: "simple")
|
||||||
bool fullresults = false;
|
bool fullresults = false;
|
||||||
if(in_args.toObject().contains("result")){ fullresults = (in_args.toObject().value("result").toString()=="full"); }
|
if(in_args.toObject().contains("result")){ fullresults = (in_args.toObject().value("result").toString()=="full"); }
|
||||||
|
|
||||||
//Now run the info fetch routine
|
//Now run the info fetch routine
|
||||||
QJsonObject info = sysadm::PKG::pkg_info(pkgs, repo, cat, fullresults);
|
QJsonObject info = sysadm::PKG::pkg_info(pkgs, repo, cat, fullresults);
|
||||||
if(!info.isEmpty()){ out->insert("pkg_info",info); }
|
if(!info.isEmpty()){ out->insert("pkg_info",info); }
|
||||||
else{ return RestOutputStruct::NOCONTENT; }
|
else{ return RestOutputStruct::NOCONTENT; }
|
||||||
|
|
||||||
}else if(act=="pkg_search" && in_args.toObject().contains("search_term")){
|
}else if(act=="pkg_search" && in_args.toObject().contains("search_term")){
|
||||||
//REQUIRED: "search_term" (string to search for)
|
//REQUIRED: "search_term" (string to search for)
|
||||||
//OPTIONAL: "repo"
|
//OPTIONAL: "repo"
|
||||||
@@ -897,22 +934,26 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmPkgRequest(const QJsonValue
|
|||||||
}else{
|
}else{
|
||||||
return RestOutputStruct::NOCONTENT;
|
return RestOutputStruct::NOCONTENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
}else if(act=="list_categories"){
|
}else if(act=="list_categories"){
|
||||||
//OPTIONAL: "repo"
|
//OPTIONAL: "repo"
|
||||||
QJsonArray cats = sysadm::PKG::list_categories(repo);
|
QJsonArray cats = sysadm::PKG::list_categories(repo);
|
||||||
if(!cats.isEmpty()){ out->insert("list_categories", cats); }
|
if(!cats.isEmpty()){ out->insert("list_categories", cats); }
|
||||||
else{ return RestOutputStruct::NOCONTENT; }
|
else{ return RestOutputStruct::NOCONTENT; }
|
||||||
|
|
||||||
}else if(act=="list_repos"){
|
}else if(act=="list_repos"){
|
||||||
QJsonArray repos = sysadm::PKG::list_repos();
|
QJsonArray repos = sysadm::PKG::list_repos();
|
||||||
if(!repos.isEmpty()){ out->insert("list_repos", repos); }
|
if(!repos.isEmpty()){ out->insert("list_repos", repos); }
|
||||||
else{ return RestOutputStruct::NOCONTENT; }
|
else{ return RestOutputStruct::NOCONTENT; }
|
||||||
|
|
||||||
}else if(act=="pkg_install" && !pkgs.isEmpty() ){
|
}else if(act=="pkg_install" && !pkgs.isEmpty() ){
|
||||||
//REQUIRED: "pkg_origins"
|
//REQUIRED: "pkg_origins"
|
||||||
//OPTIONAL: "repo" (pkg will determine the best repo to use if not supplied)
|
//OPTIONAL: "repo" (pkg will determine the best repo to use if not supplied)
|
||||||
out->insert("pkg_install", sysadm::PKG::pkg_install(pkgs,repo));
|
out->insert("pkg_install", sysadm::PKG::pkg_install(pkgs,repo));
|
||||||
|
|
||||||
|
}else if(act=="pkg_install_verify"){
|
||||||
|
//REQUIRED: "pkg_origins", "repo"
|
||||||
|
out->insert("pkg_install_verify", sysadm::PKG::evaluateInstall(pkgs,repo) );
|
||||||
}else if(act=="pkg_remove" && !pkgs.isEmpty() ){
|
}else if(act=="pkg_remove" && !pkgs.isEmpty() ){
|
||||||
//REQUIRED: "pkg_origins"
|
//REQUIRED: "pkg_origins"
|
||||||
//OPTIONAL: "recursive"="true" or "false" (default: "true")
|
//OPTIONAL: "recursive"="true" or "false" (default: "true")
|
||||||
@@ -921,10 +962,10 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmPkgRequest(const QJsonValue
|
|||||||
out->insert("pkg_remove", sysadm::PKG::pkg_remove(pkgs, recursive));
|
out->insert("pkg_remove", sysadm::PKG::pkg_remove(pkgs, recursive));
|
||||||
}else if(act=="pkg_lock" && !pkgs.isEmpty() ){
|
}else if(act=="pkg_lock" && !pkgs.isEmpty() ){
|
||||||
//REQUIRED: "pkg_origins"
|
//REQUIRED: "pkg_origins"
|
||||||
out->insert("pkg_lock", sysadm::PKG::pkg_lock(pkgs));
|
out->insert("pkg_lock", sysadm::PKG::pkg_lock(pkgs));
|
||||||
}else if(act=="pkg_unlock" && !pkgs.isEmpty() ){
|
}else if(act=="pkg_unlock" && !pkgs.isEmpty() ){
|
||||||
//REQUIRED: "pkg_origins"
|
//REQUIRED: "pkg_origins"
|
||||||
out->insert("pkg_unlock", sysadm::PKG::pkg_unlock(pkgs));
|
out->insert("pkg_unlock", sysadm::PKG::pkg_unlock(pkgs));
|
||||||
}else if(act=="pkg_update"){
|
}else if(act=="pkg_update"){
|
||||||
//OPTIONAL: "force" = ["true"/"false"] (default: "false")
|
//OPTIONAL: "force" = ["true"/"false"] (default: "false")
|
||||||
bool force = false;
|
bool force = false;
|
||||||
@@ -942,7 +983,7 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmPkgRequest(const QJsonValue
|
|||||||
//unknown action
|
//unknown action
|
||||||
return RestOutputStruct::BADREQUEST;
|
return RestOutputStruct::BADREQUEST;
|
||||||
}
|
}
|
||||||
|
|
||||||
return RestOutputStruct::OK;
|
return RestOutputStruct::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1245,6 +1286,12 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmMousedRequest(const QJsonVal
|
|||||||
outobj = sysadm::moused::enableDevice(in_args.toObject());
|
outobj = sysadm::moused::enableDevice(in_args.toObject());
|
||||||
}else if(action == "set_device_inactive"){
|
}else if(action == "set_device_inactive"){
|
||||||
outobj = sysadm::moused::disableDevice(in_args.toObject());
|
outobj = sysadm::moused::disableDevice(in_args.toObject());
|
||||||
|
}else if(action == "get_tap_to_click"){
|
||||||
|
outobj = sysadm::moused::tapToClick();
|
||||||
|
}else if(action == "set_tap_to_click"){
|
||||||
|
outobj = sysadm::moused::setTapToClick(in_args.toObject());
|
||||||
|
}else if(action == "get_synaptics_options"){
|
||||||
|
outobj = sysadm::moused::synapticsSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
//check return structure for validity
|
//check return structure for validity
|
||||||
@@ -1286,3 +1333,33 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmPowerdRequest(const QJsonVal
|
|||||||
return RestOutputStruct::BADREQUEST;
|
return RestOutputStruct::BADREQUEST;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==== SYSADM SOURCECTL API ====
|
||||||
|
RestOutputStruct::ExitCode WebSocket::EvaluateSysadmSourceCTLRequest(const QJsonValue in_args, QJsonObject *out){
|
||||||
|
QString action = in_args.toObject().value("action").toString();
|
||||||
|
QJsonObject outobj;
|
||||||
|
if(action == "downloadports"){
|
||||||
|
outobj = sysadm::sourcectl::downloadports();
|
||||||
|
}else if(action == "updateports"){
|
||||||
|
outobj = sysadm::sourcectl::updateports();
|
||||||
|
}else if(action == "deleteports"){
|
||||||
|
outobj = sysadm::sourcectl::deleteports();
|
||||||
|
}else if(action == "stopports"){
|
||||||
|
outobj = sysadm::sourcectl::stopports();
|
||||||
|
}else if(action == "downloadsource"){
|
||||||
|
outobj = sysadm::sourcectl::downloadsource();
|
||||||
|
}else if(action == "updatesource"){
|
||||||
|
outobj = sysadm::sourcectl::updatesource();
|
||||||
|
}else if(action == "deletesource"){
|
||||||
|
outobj = sysadm::sourcectl::deletesource();
|
||||||
|
}else if(action == "stopsource"){
|
||||||
|
outobj = sysadm::sourcectl::stopsource();
|
||||||
|
//check return structure for validity
|
||||||
|
if(!outobj.keys().isEmpty()){
|
||||||
|
out->insert(action, outobj);
|
||||||
|
return RestOutputStruct::OK;
|
||||||
|
}else{
|
||||||
|
return RestOutputStruct::BADREQUEST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -255,7 +255,7 @@ void WebSocket::EvaluateRequest(const RestInputStruct &REQ){
|
|||||||
QString user, pass;
|
QString user, pass;
|
||||||
if(out.in_struct.args.toObject().contains("username")){ user = JsonValueToString(out.in_struct.args.toObject().value("username")); }
|
if(out.in_struct.args.toObject().contains("username")){ user = JsonValueToString(out.in_struct.args.toObject().value("username")); }
|
||||||
if(out.in_struct.args.toObject().contains("password")){ pass = JsonValueToString(out.in_struct.args.toObject().value("password")); }
|
if(out.in_struct.args.toObject().contains("password")){ pass = JsonValueToString(out.in_struct.args.toObject().value("password")); }
|
||||||
|
|
||||||
//Use the given password
|
//Use the given password
|
||||||
cur_auth_tok = AUTHSYSTEM->LoginUP(host, user, pass);
|
cur_auth_tok = AUTHSYSTEM->LoginUP(host, user, pass);
|
||||||
}else if(out.in_struct.name=="auth_ssl"){
|
}else if(out.in_struct.name=="auth_ssl"){
|
||||||
@@ -294,7 +294,7 @@ void WebSocket::EvaluateRequest(const RestInputStruct &REQ){
|
|||||||
out.CODE = RestOutputStruct::OK;
|
out.CODE = RestOutputStruct::OK;
|
||||||
QString msg = out.assembleMessage();
|
QString msg = out.assembleMessage();
|
||||||
if(SOCKET!=0 && !REQ.bridgeID.isEmpty()){
|
if(SOCKET!=0 && !REQ.bridgeID.isEmpty()){
|
||||||
//BRIDGE RELAY - alternate format
|
//BRIDGE RELAY - alternate format
|
||||||
//Note that the Stage 1 SSL auth reply is only partially encrypted (specific variables only, not bulk message encryption)
|
//Note that the Stage 1 SSL auth reply is only partially encrypted (specific variables only, not bulk message encryption)
|
||||||
//Now add the destination ID
|
//Now add the destination ID
|
||||||
msg.prepend( REQ.bridgeID+"\n");
|
msg.prepend( REQ.bridgeID+"\n");
|
||||||
@@ -307,10 +307,10 @@ void WebSocket::EvaluateRequest(const RestInputStruct &REQ){
|
|||||||
}else if(out.in_struct.name == "auth_clear"){
|
}else if(out.in_struct.name == "auth_clear"){
|
||||||
return; //don't send a return message after clearing an auth (already done)
|
return; //don't send a return message after clearing an auth (already done)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Now check the auth and respond appropriately
|
//Now check the auth and respond appropriately
|
||||||
if(AUTHSYSTEM->checkAuth(cur_auth_tok)){
|
if(AUTHSYSTEM->checkAuth(cur_auth_tok)){
|
||||||
//Good Authentication - return the new token
|
//Good Authentication - return the new token
|
||||||
QJsonArray array;
|
QJsonArray array;
|
||||||
array.append(cur_auth_tok);
|
array.append(cur_auth_tok);
|
||||||
array.append(AUTHSYSTEM->checkAuthTimeoutSecs(cur_auth_tok));
|
array.append(AUTHSYSTEM->checkAuthTimeoutSecs(cur_auth_tok));
|
||||||
@@ -325,25 +325,25 @@ void WebSocket::EvaluateRequest(const RestInputStruct &REQ){
|
|||||||
//Bad Authentication - return error
|
//Bad Authentication - return error
|
||||||
out.CODE = RestOutputStruct::UNAUTHORIZED;
|
out.CODE = RestOutputStruct::UNAUTHORIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
}else if( AUTHSYSTEM->checkAuth(cur_auth_tok) ){ //validate current Authentication token
|
}else if( AUTHSYSTEM->checkAuth(cur_auth_tok) ){ //validate current Authentication token
|
||||||
//Now provide access to the various subsystems
|
//Now provide access to the various subsystems
|
||||||
// First get/set the permissions flag into the input structure
|
// First get/set the permissions flag into the input structure
|
||||||
out.in_struct.fullaccess = AUTHSYSTEM->hasFullAccess(cur_auth_tok);
|
out.in_struct.fullaccess = AUTHSYSTEM->hasFullAccess(cur_auth_tok);
|
||||||
//Pre-set any output fields
|
//Pre-set any output fields
|
||||||
QJsonObject outargs;
|
QJsonObject outargs;
|
||||||
out.CODE = EvaluateBackendRequest(out.in_struct, &outargs);
|
out.CODE = EvaluateBackendRequest(out.in_struct, &outargs);
|
||||||
out.out_args = outargs;
|
out.out_args = outargs;
|
||||||
}else{
|
}else{
|
||||||
//Bad/No authentication
|
//Bad/No authentication
|
||||||
out.CODE = RestOutputStruct::UNAUTHORIZED;
|
out.CODE = RestOutputStruct::UNAUTHORIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
}else if(out.in_struct.namesp.toLower() == "events"){
|
}else if(out.in_struct.namesp.toLower() == "events"){
|
||||||
//qDebug() << "Got Event subsytem request" << out.in_struct.args;
|
//qDebug() << "Got Event subsytem request" << out.in_struct.args;
|
||||||
if( AUTHSYSTEM->checkAuth(cur_auth_tok) ){ //validate current Authentication token
|
if( AUTHSYSTEM->checkAuth(cur_auth_tok) ){ //validate current Authentication token
|
||||||
//Pre-set any output fields
|
//Pre-set any output fields
|
||||||
QJsonObject outargs;
|
QJsonObject outargs;
|
||||||
//Assemble the list of input events
|
//Assemble the list of input events
|
||||||
QStringList evlist;
|
QStringList evlist;
|
||||||
if(out.in_struct.args.isString()){ evlist << JsonValueToString(out.in_struct.args); }
|
if(out.in_struct.args.isString()){ evlist << JsonValueToString(out.in_struct.args); }
|
||||||
@@ -357,14 +357,14 @@ void WebSocket::EvaluateRequest(const RestInputStruct &REQ){
|
|||||||
for(int i=0; i<evlist.length(); i++){
|
for(int i=0; i<evlist.length(); i++){
|
||||||
EventWatcher::EVENT_TYPE type = EventWatcher::typeFromString(evlist[i]);
|
EventWatcher::EVENT_TYPE type = EventWatcher::typeFromString(evlist[i]);
|
||||||
//qDebug() << " - type:" << type;
|
//qDebug() << " - type:" << type;
|
||||||
if(isBridge){
|
if(isBridge){
|
||||||
ForwardEvents.clear();
|
ForwardEvents.clear();
|
||||||
if(!REQ.bridgeID.isEmpty()){ ForwardEvents = BRIDGE[REQ.bridgeID].sendEvents; }
|
if(!REQ.bridgeID.isEmpty()){ ForwardEvents = BRIDGE[REQ.bridgeID].sendEvents; }
|
||||||
}
|
}
|
||||||
if(type==EventWatcher::BADEVENT){ continue; }
|
if(type==EventWatcher::BADEVENT){ continue; }
|
||||||
outargs.insert(out.in_struct.name,QJsonValue(evlist[i]));
|
outargs.insert(out.in_struct.name,QJsonValue(evlist[i]));
|
||||||
if(sub==1){
|
if(sub==1){
|
||||||
ForwardEvents << type;
|
ForwardEvents << type;
|
||||||
EventUpdate(type);
|
EventUpdate(type);
|
||||||
}else{
|
}else{
|
||||||
ForwardEvents.removeAll(type);
|
ForwardEvents.removeAll(type);
|
||||||
@@ -375,7 +375,7 @@ void WebSocket::EvaluateRequest(const RestInputStruct &REQ){
|
|||||||
out.CODE = RestOutputStruct::OK;
|
out.CODE = RestOutputStruct::OK;
|
||||||
}else{
|
}else{
|
||||||
//Bad/No authentication
|
//Bad/No authentication
|
||||||
out.CODE = RestOutputStruct::BADREQUEST;
|
out.CODE = RestOutputStruct::BADREQUEST;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
//Bad/No authentication
|
//Bad/No authentication
|
||||||
@@ -386,7 +386,7 @@ void WebSocket::EvaluateRequest(const RestInputStruct &REQ){
|
|||||||
//qDebug() << "Within special bridge section";
|
//qDebug() << "Within special bridge section";
|
||||||
out.in_struct.fullaccess = false;
|
out.in_struct.fullaccess = false;
|
||||||
//Pre-set any output fields
|
//Pre-set any output fields
|
||||||
QJsonObject outargs;
|
QJsonObject outargs;
|
||||||
out.CODE = EvaluateBackendRequest(out.in_struct, &outargs);
|
out.CODE = EvaluateBackendRequest(out.in_struct, &outargs);
|
||||||
out.out_args = outargs;
|
out.out_args = outargs;
|
||||||
}else if( AUTHSYSTEM->checkAuth(cur_auth_tok) ){ //validate current Authentication token
|
}else if( AUTHSYSTEM->checkAuth(cur_auth_tok) ){ //validate current Authentication token
|
||||||
@@ -395,7 +395,7 @@ void WebSocket::EvaluateRequest(const RestInputStruct &REQ){
|
|||||||
// First get/set the permissions flag into the input structure
|
// First get/set the permissions flag into the input structure
|
||||||
out.in_struct.fullaccess = AUTHSYSTEM->hasFullAccess(cur_auth_tok);
|
out.in_struct.fullaccess = AUTHSYSTEM->hasFullAccess(cur_auth_tok);
|
||||||
//Pre-set any output fields
|
//Pre-set any output fields
|
||||||
QJsonObject outargs;
|
QJsonObject outargs;
|
||||||
out.CODE = EvaluateBackendRequest(out.in_struct, &outargs);
|
out.CODE = EvaluateBackendRequest(out.in_struct, &outargs);
|
||||||
out.out_args = outargs;
|
out.out_args = outargs;
|
||||||
}else{
|
}else{
|
||||||
@@ -413,7 +413,7 @@ void WebSocket::EvaluateRequest(const RestInputStruct &REQ){
|
|||||||
QString msg = out.assembleMessage();
|
QString msg = out.assembleMessage();
|
||||||
if(SOCKET!=0 && !REQ.bridgeID.isEmpty()){
|
if(SOCKET!=0 && !REQ.bridgeID.isEmpty()){
|
||||||
//BRIDGE RELAY - alternate format
|
//BRIDGE RELAY - alternate format
|
||||||
msg = AUTHSYSTEM->encryptString(msg, BRIDGE[REQ.bridgeID].enc_key);
|
msg = AUTHSYSTEM->encryptString(msg, BRIDGE[REQ.bridgeID].enc_key);
|
||||||
//Now add the destination ID
|
//Now add the destination ID
|
||||||
msg.prepend( REQ.bridgeID+"\n");
|
msg.prepend( REQ.bridgeID+"\n");
|
||||||
}
|
}
|
||||||
@@ -421,7 +421,7 @@ void WebSocket::EvaluateRequest(const RestInputStruct &REQ){
|
|||||||
this->sendReply(msg);
|
this->sendReply(msg);
|
||||||
SOCKET->close(QWebSocketProtocol::CloseCodeNormal, "Too Many Authorization Failures - Try again later");
|
SOCKET->close(QWebSocketProtocol::CloseCodeNormal, "Too Many Authorization Failures - Try again later");
|
||||||
}else{
|
}else{
|
||||||
this->emit SendMessage(msg);
|
this->emit SendMessage(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,7 +489,7 @@ QStringList WebSocket::JsonArrayToStringList(QJsonArray array){
|
|||||||
for(int i=0; i<array.count(); i++){
|
for(int i=0; i<array.count(); i++){
|
||||||
out << JsonValueToString(array.at(i));
|
out << JsonValueToString(array.at(i));
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// =====================
|
// =====================
|
||||||
@@ -532,10 +532,10 @@ void WebSocket::checkAuth(){
|
|||||||
|
|
||||||
void WebSocket::SocketClosing(){
|
void WebSocket::SocketClosing(){
|
||||||
LogManager::log(LogManager::HOST,"Connection Closing: "+SockPeerIP);
|
LogManager::log(LogManager::HOST,"Connection Closing: "+SockPeerIP);
|
||||||
if(idletimer->isActive()){
|
if(idletimer->isActive()){
|
||||||
//This means the client deliberately closed the connection - not the idle timer
|
//This means the client deliberately closed the connection - not the idle timer
|
||||||
//qDebug() << " - Client Closed Connection";
|
//qDebug() << " - Client Closed Connection";
|
||||||
idletimer->stop();
|
idletimer->stop();
|
||||||
}else{
|
}else{
|
||||||
//qDebug() << "idleTimer not running";
|
//qDebug() << "idleTimer not running";
|
||||||
}
|
}
|
||||||
@@ -544,23 +544,23 @@ void WebSocket::SocketClosing(){
|
|||||||
//Reset the pointer
|
//Reset the pointer
|
||||||
if(SOCKET!=0){ SOCKET = 0; }
|
if(SOCKET!=0){ SOCKET = 0; }
|
||||||
if(TSOCKET!=0){ TSOCKET = 0; }
|
if(TSOCKET!=0){ TSOCKET = 0; }
|
||||||
|
|
||||||
emit SocketClosed(SockID);
|
emit SocketClosed(SockID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebSocket::EvaluateMessage(const QByteArray &msg){
|
void WebSocket::EvaluateMessage(const QByteArray &msg){
|
||||||
//qDebug() << "New Binary Message:";
|
//qDebug() << "New Binary Message:";
|
||||||
if(idletimer->isActive()){ idletimer->stop(); }
|
if(idletimer->isActive()){ idletimer->stop(); }
|
||||||
idletimer->start();
|
idletimer->start();
|
||||||
EvaluateREST( QString(msg) );
|
EvaluateREST( QString(msg) );
|
||||||
//qDebug() << " - Done with Binary Message";
|
//qDebug() << " - Done with Binary Message";
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebSocket::EvaluateMessage(const QString &msg){
|
void WebSocket::EvaluateMessage(const QString &msg){
|
||||||
//qDebug() << "New Text Message:" << msg;
|
//qDebug() << "New Text Message:" << msg;
|
||||||
if(idletimer->isActive()){ idletimer->stop(); }
|
if(idletimer->isActive()){ idletimer->stop(); }
|
||||||
idletimer->start();
|
idletimer->start();
|
||||||
EvaluateREST(msg);
|
EvaluateREST(msg);
|
||||||
//qDebug() << " - Done with Text Message";
|
//qDebug() << " - Done with Text Message";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -609,8 +609,8 @@ void WebSocket::EvaluateTcpMessage(){
|
|||||||
// Check for JSON in this incoming data
|
// Check for JSON in this incoming data
|
||||||
ParseIncoming();
|
ParseIncoming();
|
||||||
|
|
||||||
idletimer->start();
|
idletimer->start();
|
||||||
//qDebug() << " - Done with TCP Message";
|
//qDebug() << " - Done with TCP Message";
|
||||||
}
|
}
|
||||||
|
|
||||||
//SSL signal handling
|
//SSL signal handling
|
||||||
|
|||||||
@@ -100,6 +100,8 @@ private:
|
|||||||
RestOutputStruct::ExitCode EvaluateSysadmMousedRequest(const QJsonValue in_args, QJsonObject *out);
|
RestOutputStruct::ExitCode EvaluateSysadmMousedRequest(const QJsonValue in_args, QJsonObject *out);
|
||||||
// -- sysadm powerd API
|
// -- sysadm powerd API
|
||||||
RestOutputStruct::ExitCode EvaluateSysadmPowerdRequest(const QJsonValue in_args, QJsonObject *out);
|
RestOutputStruct::ExitCode EvaluateSysadmPowerdRequest(const QJsonValue in_args, QJsonObject *out);
|
||||||
|
// -- sysadm sourcectl API
|
||||||
|
RestOutputStruct::ExitCode EvaluateSysadmSourceCTLRequest(const QJsonValue in_args, QJsonObject *out);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void sendReply(QString msg);
|
void sendReply(QString msg);
|
||||||
|
|||||||
@@ -4,6 +4,11 @@
|
|||||||
// Available under the 3-clause BSD license
|
// Available under the 3-clause BSD license
|
||||||
// See the LICENSE file for full details
|
// See the LICENSE file for full details
|
||||||
//===========================================
|
//===========================================
|
||||||
|
// SysAdm source code for TrueOS
|
||||||
|
// Copyright (c) 2016-2017 TrueOS/iXsystems
|
||||||
|
// Available under the 3-clause BSD license
|
||||||
|
// See the LICENSE file for full details
|
||||||
|
//===========================================
|
||||||
// Note: This was almost entirely written by Tim McCormick in 2009 for
|
// Note: This was almost entirely written by Tim McCormick in 2009 for
|
||||||
// the first PC-BSD library, and copied here by Ken Moore in 2015
|
// the first PC-BSD library, and copied here by Ken Moore in 2015
|
||||||
//===========================================
|
//===========================================
|
||||||
@@ -15,7 +20,7 @@
|
|||||||
using namespace sysadm;
|
using namespace sysadm;
|
||||||
|
|
||||||
//====================
|
//====================
|
||||||
// STATIC LISTING FUNCTION
|
// STATIC LISTING FUNCTION
|
||||||
//====================
|
//====================
|
||||||
QStringList NetDevice::listNetDevices(){
|
QStringList NetDevice::listNetDevices(){
|
||||||
QStringList result;
|
QStringList result;
|
||||||
@@ -28,7 +33,7 @@ QStringList NetDevice::listNetDevices(){
|
|||||||
if (result.contains(ifName) == 0) result += ifName;
|
if (result.contains(ifName) == 0) result += ifName;
|
||||||
ifap = ifap->ifa_next;
|
ifap = ifap->ifa_next;
|
||||||
}
|
}
|
||||||
//Close the
|
//Close the structure
|
||||||
freeifaddrs(ifap);
|
freeifaddrs(ifap);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -57,10 +62,10 @@ QString NetDevice::ipAsString(){
|
|||||||
|
|
||||||
strncpy(ifr.ifr_name, name.toLocal8Bit(), IFNAMSIZ);
|
strncpy(ifr.ifr_name, name.toLocal8Bit(), IFNAMSIZ);
|
||||||
int s = socket(PF_INET, SOCK_DGRAM, 0);
|
int s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
|
|
||||||
ioctl(s, SIOCGIFADDR, &ifr);
|
ioctl(s, SIOCGIFADDR, &ifr);
|
||||||
struct in_addr in = ((sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
struct in_addr in = ((sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||||
|
close(s); //close the file descriptor
|
||||||
return QString(inet_ntoa(in));
|
return QString(inet_ntoa(in));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +91,7 @@ QString NetDevice::ipv6AsString(){
|
|||||||
//Now get the IPv6 address in string form
|
//Now get the IPv6 address in string form
|
||||||
char straddr[INET6_ADDRSTRLEN];
|
char straddr[INET6_ADDRSTRLEN];
|
||||||
int err = getnameinfo(sadd, sadd->sa_len, straddr, sizeof(straddr),NULL, 0, NI_NUMERICHOST);
|
int err = getnameinfo(sadd, sadd->sa_len, straddr, sizeof(straddr),NULL, 0, NI_NUMERICHOST);
|
||||||
if(err!=0){
|
if(err!=0){
|
||||||
qDebug() << "getnameinfo error:" << gai_strerror(err);
|
qDebug() << "getnameinfo error:" << gai_strerror(err);
|
||||||
return "";
|
return "";
|
||||||
}else{
|
}else{
|
||||||
@@ -102,16 +107,28 @@ QString NetDevice::netmaskAsString(){
|
|||||||
|
|
||||||
strncpy(ifr.ifr_name, name.toLocal8Bit(), IFNAMSIZ);
|
strncpy(ifr.ifr_name, name.toLocal8Bit(), IFNAMSIZ);
|
||||||
int s = socket(PF_INET, SOCK_DGRAM, 0);
|
int s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
|
|
||||||
ioctl(s, SIOCGIFNETMASK, &ifr);
|
ioctl(s, SIOCGIFNETMASK, &ifr);
|
||||||
struct in_addr in = ((sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
struct in_addr in = ((sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||||
|
close(s); //close the file descriptor
|
||||||
return QString(inet_ntoa(in));
|
return QString(inet_ntoa(in));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Returns the description string for the device
|
//Returns the description string for the device
|
||||||
QString NetDevice::desc(){
|
QString NetDevice::desc(){
|
||||||
return General::sysctl("dev." + devName() + "." + QString::number(devNum()) + ".%desc");
|
QString name, num, parent;
|
||||||
|
if( isWireless() ){ parent = getWifiParent(); }
|
||||||
|
|
||||||
|
if(!parent.isEmpty()){
|
||||||
|
name = num = parent;
|
||||||
|
uint pos = name.indexOf(QRegExp("[0-9]+$"));
|
||||||
|
name.truncate(pos);
|
||||||
|
num.remove(0,pos);
|
||||||
|
}else{
|
||||||
|
name = devName();
|
||||||
|
num = QString::number(devNum());
|
||||||
|
}
|
||||||
|
return General::sysctl("dev." + name + "." + num + ".%desc");
|
||||||
}
|
}
|
||||||
|
|
||||||
//Fetch the mac address as a QString
|
//Fetch the mac address as a QString
|
||||||
@@ -136,7 +153,7 @@ QString NetDevice::macAsString(){
|
|||||||
|
|
||||||
sdl = (sockaddr_dl *)(((if_msghdr *)buf)+1);
|
sdl = (sockaddr_dl *)(((if_msghdr *)buf)+1);
|
||||||
ptr = (char *) LLADDR(sdl);
|
ptr = (char *) LLADDR(sdl);
|
||||||
|
|
||||||
QString mac;
|
QString mac;
|
||||||
for (uint i=0; i < 6; i++){
|
for (uint i=0; i < 6; i++){
|
||||||
mac += QString::number(*(ptr+i), 16).right(2).rightJustified(2, '0');
|
mac += QString::number(*(ptr+i), 16).right(2).rightJustified(2, '0');
|
||||||
@@ -157,11 +174,6 @@ QString NetDevice::mediaStatusAsString(){
|
|||||||
QString status;
|
QString status;
|
||||||
|
|
||||||
switch (IFM_TYPE(ifm.ifm_active)){
|
switch (IFM_TYPE(ifm.ifm_active)){
|
||||||
case IFM_FDDI:
|
|
||||||
case IFM_TOKEN:
|
|
||||||
if (ifm.ifm_status & IFM_ACTIVE) status = "inserted";
|
|
||||||
else status = "no ring";
|
|
||||||
break;
|
|
||||||
case IFM_IEEE80211:
|
case IFM_IEEE80211:
|
||||||
if (ifm.ifm_status & IFM_ACTIVE) status = "associated";
|
if (ifm.ifm_status & IFM_ACTIVE) status = "associated";
|
||||||
else status = "no carrier";
|
else status = "no carrier";
|
||||||
@@ -170,6 +182,7 @@ QString NetDevice::mediaStatusAsString(){
|
|||||||
if (ifm.ifm_status & IFM_ACTIVE) status = "active";
|
if (ifm.ifm_status & IFM_ACTIVE) status = "active";
|
||||||
else status = "no carrier";
|
else status = "no carrier";
|
||||||
}
|
}
|
||||||
|
close(s); //close the file descriptor
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,8 +203,9 @@ bool NetDevice::isWireless(){
|
|||||||
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
|
||||||
ioctl(s, SIOCGIFMEDIA, &ifm);
|
ioctl(s, SIOCGIFMEDIA, &ifm);
|
||||||
|
bool iswifi = (IFM_TYPE(ifm.ifm_active) == IFM_IEEE80211);
|
||||||
return IFM_TYPE(ifm.ifm_active) == IFM_IEEE80211;
|
close(s); //close the file descriptor
|
||||||
|
return iswifi;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Get the parent device (if this is a wireless wlan)
|
//Get the parent device (if this is a wireless wlan)
|
||||||
@@ -203,7 +217,7 @@ QString NetDevice::getWifiParent(){
|
|||||||
//See if the device is setup to use DHCP
|
//See if the device is setup to use DHCP
|
||||||
bool NetDevice::usesDHCP(){
|
bool NetDevice::usesDHCP(){
|
||||||
//The system does not keep track of how the device's address was assigned
|
//The system does not keep track of how the device's address was assigned
|
||||||
// so the closest we can get to this is to see if the system is setup to use
|
// so the closest we can get to this is to see if the system is setup to use
|
||||||
// DHCP on startup (in /etc/rc.conf) (Ken Moore - 6/24/15)
|
// DHCP on startup (in /etc/rc.conf) (Ken Moore - 6/24/15)
|
||||||
return !Network::readRcConf().filter(name).filter("DHCP").isEmpty();
|
return !Network::readRcConf().filter(name).filter("DHCP").isEmpty();
|
||||||
}
|
}
|
||||||
@@ -217,8 +231,9 @@ bool NetDevice::isUp(){
|
|||||||
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
|
||||||
ioctl(s, SIOCGIFFLAGS, &ifr);
|
ioctl(s, SIOCGIFFLAGS, &ifr);
|
||||||
|
bool isup = (ifr.ifr_flags & IFF_UP);
|
||||||
return (ifr.ifr_flags & IFF_UP) ? 1 : 0;
|
close(s); //close the file descriptor
|
||||||
|
return isup;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Determine the number of packets received by the device
|
//Determine the number of packets received by the device
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ HEADERS += $${PWD}/sysadm-global.h \
|
|||||||
$${PWD}/sysadm-zfs.h \
|
$${PWD}/sysadm-zfs.h \
|
||||||
$${PWD}/sysadm-pkg.h \
|
$${PWD}/sysadm-pkg.h \
|
||||||
$${PWD}/sysadm-moused.h \
|
$${PWD}/sysadm-moused.h \
|
||||||
$${PWD}/sysadm-powerd.h
|
$${PWD}/sysadm-powerd.h \
|
||||||
|
$${PWD}/sysadm-sourcectl.h
|
||||||
|
|
||||||
|
|
||||||
SOURCES += $${PWD}/NetDevice.cpp \
|
SOURCES += $${PWD}/NetDevice.cpp \
|
||||||
$${PWD}/sysadm-general.cpp \
|
$${PWD}/sysadm-general.cpp \
|
||||||
@@ -35,4 +37,5 @@ SOURCES += $${PWD}/NetDevice.cpp \
|
|||||||
$${PWD}/sysadm-zfs.cpp \
|
$${PWD}/sysadm-zfs.cpp \
|
||||||
$${PWD}/sysadm-pkg.cpp \
|
$${PWD}/sysadm-pkg.cpp \
|
||||||
$${PWD}/sysadm-moused.cpp \
|
$${PWD}/sysadm-moused.cpp \
|
||||||
$${PWD}/sysadm-powerd.cpp
|
$${PWD}/sysadm-powerd.cpp \
|
||||||
|
$${PWD}/sysadm-sourcectl.cpp
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ QJsonObject BEADM::listBEs() {
|
|||||||
|
|
||||||
QJsonObject BEADM::renameBE(QJsonObject jsin) {
|
QJsonObject BEADM::renameBE(QJsonObject jsin) {
|
||||||
QJsonObject retObject;
|
QJsonObject retObject;
|
||||||
|
|
||||||
QStringList keys = jsin.keys();
|
QStringList keys = jsin.keys();
|
||||||
if (! keys.contains("source") || ! keys.contains("target") ) {
|
if (! keys.contains("source") || ! keys.contains("target") ) {
|
||||||
retObject.insert("error", "Missing required key(s) 'source / target'");
|
retObject.insert("error", "Missing required key(s) 'source / target'");
|
||||||
@@ -71,7 +71,7 @@ QJsonObject BEADM::listBEs() {
|
|||||||
return retObject;
|
return retObject;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
retObject.insert("source", source);
|
retObject.insert("source", source);
|
||||||
retObject.insert("target", target);
|
retObject.insert("target", target);
|
||||||
return retObject;
|
return retObject;
|
||||||
@@ -191,7 +191,7 @@ QJsonObject BEADM::listBEs() {
|
|||||||
QString mountpoint;
|
QString mountpoint;
|
||||||
if (keys.contains("mountpoint") ) {
|
if (keys.contains("mountpoint") ) {
|
||||||
mountpoint = jsin.value("mountpoint").toString();
|
mountpoint = jsin.value("mountpoint").toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList output = General::RunCommand("beadm mount "+ be + " " + mountpoint).split("\n");
|
QStringList output = General::RunCommand("beadm mount "+ be + " " + mountpoint).split("\n");
|
||||||
|
|
||||||
@@ -209,7 +209,7 @@ QJsonObject BEADM::listBEs() {
|
|||||||
|
|
||||||
return retObject;
|
return retObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmount the given boot environment immediately. Confirmation should be done through the client.
|
// Unmount the given boot environment immediately. Confirmation should be done through the client.
|
||||||
|
|
||||||
QJsonObject BEADM::umountBE(QJsonObject jsin) {
|
QJsonObject BEADM::umountBE(QJsonObject jsin) {
|
||||||
|
|||||||
@@ -10,6 +10,10 @@
|
|||||||
#include "sysadm-global.h"
|
#include "sysadm-global.h"
|
||||||
|
|
||||||
using namespace sysadm;
|
using namespace sysadm;
|
||||||
|
|
||||||
|
#define PREFIX QString("/usr/local")
|
||||||
|
QString TRUEOS_ETCCONF(PREFIX + "/etc/trueos.conf"); // The default trueos.conf file
|
||||||
|
|
||||||
//=================
|
//=================
|
||||||
// RunCommand() variations
|
// RunCommand() variations
|
||||||
//=================
|
//=================
|
||||||
@@ -36,7 +40,10 @@ QString General::RunCommand(bool &success, QString command, QStringList argument
|
|||||||
if(arguments.isEmpty()){ proc.start(command); }
|
if(arguments.isEmpty()){ proc.start(command); }
|
||||||
else{ proc.start(command, arguments); }
|
else{ proc.start(command, arguments); }
|
||||||
//Wait for the process to finish (but don't block the event loop)
|
//Wait for the process to finish (but don't block the event loop)
|
||||||
while( !proc.waitForFinished(500) ){ QCoreApplication::processEvents(); }
|
while( !proc.waitForFinished(500) ){
|
||||||
|
if(proc.state() != QProcess::Running){ break; } //somehow missed the finished signal
|
||||||
|
QCoreApplication::processEvents();
|
||||||
|
}
|
||||||
success = (proc.exitCode()==0); //return success/failure
|
success = (proc.exitCode()==0); //return success/failure
|
||||||
return QString(proc.readAllStandardOutput());
|
return QString(proc.readAllStandardOutput());
|
||||||
}
|
}
|
||||||
@@ -54,6 +61,21 @@ bool General::RunQuickCommand(QString command, QStringList arguments,QString wor
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList General::gitCMD(QString dir, QString cmd, QStringList args){
|
||||||
|
//Run a quick command in the proper dir and return the output
|
||||||
|
QProcess proc;
|
||||||
|
proc.setProcessChannelMode(QProcess::MergedChannels);
|
||||||
|
if( !dir.isEmpty() && QFile::exists(dir) ){ proc.setWorkingDirectory(dir); }
|
||||||
|
if(args.isEmpty()){ proc.start(cmd); }
|
||||||
|
else{ proc.start(cmd, args); }
|
||||||
|
while(!proc.waitForFinished(300)){ QCoreApplication::processEvents(); }
|
||||||
|
QStringList out;
|
||||||
|
while(proc.canReadLine()){
|
||||||
|
out << QString( proc.readLine() );
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
//=================
|
//=================
|
||||||
// TEXT FILE INTERACTION
|
// TEXT FILE INTERACTION
|
||||||
//=================
|
//=================
|
||||||
@@ -170,12 +192,10 @@ bool General::setConfFileValue(QString fileName, QString oldKey, QString newKey,
|
|||||||
|
|
||||||
// Load the old file, find the oldKey, remove it and replace with newKey
|
// Load the old file, find the oldKey, remove it and replace with newKey
|
||||||
QFile file( oFileTmp );
|
QFile file( oFileTmp );
|
||||||
if ( ! file.open( QIODevice::ReadOnly ) )
|
if ( file.open( QIODevice::ReadOnly ) ){
|
||||||
return false;
|
QTextStream stream( &file );
|
||||||
|
QString line;
|
||||||
QTextStream stream( &file );
|
while ( !stream.atEnd() ) {
|
||||||
QString line;
|
|
||||||
while ( !stream.atEnd() ) {
|
|
||||||
line = stream.readLine(); // line of text excluding '\n'
|
line = stream.readLine(); // line of text excluding '\n'
|
||||||
|
|
||||||
// Key is not found at all
|
// Key is not found at all
|
||||||
@@ -214,10 +234,12 @@ bool General::setConfFileValue(QString fileName, QString oldKey, QString newKey,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
}else if(file.exists()){
|
||||||
|
return false; //could not read an existing file - permissions issue?
|
||||||
}
|
}
|
||||||
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
// Didn't find the key? Write it!
|
// Didn't find the key? Write it!
|
||||||
if ( ! newKey.isEmpty() )
|
if ( ! newKey.isEmpty() )
|
||||||
SavedFile << newKey;
|
SavedFile << newKey;
|
||||||
@@ -241,6 +263,30 @@ bool General::setConfFileValue(QString fileName, QString oldKey, QString newKey,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString General::getValFromTrueOSConf(QString key) {
|
||||||
|
return getValFromTOConf(TRUEOS_ETCCONF, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString General::getValFromTOConf(QString conf, QString key) {
|
||||||
|
|
||||||
|
// Load from conf the requested key
|
||||||
|
QFile confFile(conf);
|
||||||
|
if ( confFile.open( QIODevice::ReadOnly ) ) {
|
||||||
|
QTextStream stream( &confFile );
|
||||||
|
stream.setCodec("UTF-8");
|
||||||
|
QString line;
|
||||||
|
while ( !stream.atEnd() ) {
|
||||||
|
line = stream.readLine().simplified();
|
||||||
|
if ( line.indexOf(key + ": ") == 0 ) {
|
||||||
|
confFile.close();
|
||||||
|
return line.replace(key + ": ", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
confFile.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//===========================
|
//===========================
|
||||||
// SYSCTL ACCESS (might require root)
|
// SYSCTL ACCESS (might require root)
|
||||||
//===========================
|
//===========================
|
||||||
@@ -261,3 +307,40 @@ long long General::sysctlAsInt(QString var){
|
|||||||
if(0!=sysctlbyname(var.toLocal8Bit(), &result, &len, NULL, 0) ){ return 0; }
|
if(0!=sysctlbyname(var.toLocal8Bit(), &result, &len, NULL, 0) ){ return 0; }
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===========================
|
||||||
|
// Misc
|
||||||
|
//===========================
|
||||||
|
|
||||||
|
QString General::bytesToHumanReadable(long long bytes)
|
||||||
|
{
|
||||||
|
float num = bytes;
|
||||||
|
QStringList list;
|
||||||
|
list << "KB" << "MB" << "GB" << "TB";
|
||||||
|
|
||||||
|
QStringListIterator i(list);
|
||||||
|
QString unit("bytes");
|
||||||
|
|
||||||
|
while(num >= 1024.0 && i.hasNext())
|
||||||
|
{
|
||||||
|
unit = i.next();
|
||||||
|
num /= 1024.0;
|
||||||
|
}
|
||||||
|
return QString().setNum(num,'f',2)+" "+unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void General::emptyDir(QString dir){
|
||||||
|
QDir d(dir);
|
||||||
|
if(!d.exists()){ return; } //quick check to make sure directory exists first
|
||||||
|
//Remove all the files in this directory
|
||||||
|
QStringList tmp = d.entryList(QDir::Files | QDir::NoDotAndDotDot);
|
||||||
|
for(int i=0; i<tmp.length(); i++){
|
||||||
|
d.remove(tmp[i]);
|
||||||
|
}
|
||||||
|
//Now remove all the directories in this directory (recursive)
|
||||||
|
tmp = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
|
for(int i=0; i<tmp.length(); i++){
|
||||||
|
General::emptyDir(d.absoluteFilePath(tmp[i])); //Empty this directory first
|
||||||
|
d.rmdir(tmp[i]); //Now try to remove it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ public:
|
|||||||
static QString RunCommand(QString command, QStringList arguments = QStringList(), QString workdir = "", QStringList env = QStringList() );
|
static QString RunCommand(QString command, QStringList arguments = QStringList(), QString workdir = "", QStringList env = QStringList() );
|
||||||
// - success output only
|
// - success output only
|
||||||
static bool RunQuickCommand(QString command, QStringList arguments = QStringList(), QString workdir = "", QStringList env = QStringList() );
|
static bool RunQuickCommand(QString command, QStringList arguments = QStringList(), QString workdir = "", QStringList env = QStringList() );
|
||||||
|
static QStringList gitCMD(QString dir, QString cmd, QStringList args = QStringList());
|
||||||
|
static void emptyDir(QString dir);
|
||||||
//File Access Functions
|
//File Access Functions
|
||||||
static QStringList readTextFile(QString filename);
|
static QStringList readTextFile(QString filename);
|
||||||
static bool writeTextFile(QString filename, QStringList contents, bool overwrite = true);
|
static bool writeTextFile(QString filename, QStringList contents, bool overwrite = true);
|
||||||
@@ -55,6 +56,10 @@ public:
|
|||||||
//Retrieve a number-based sysctl
|
//Retrieve a number-based sysctl
|
||||||
static long long sysctlAsInt(QString var);
|
static long long sysctlAsInt(QString var);
|
||||||
|
|
||||||
|
static QString bytesToHumanReadable(long long bytes);
|
||||||
|
static QString getValFromTOConf(QString conf, QString key);
|
||||||
|
static QString getValFromTrueOSConf(QString key);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} //end of pcbsd namespace
|
} //end of pcbsd namespace
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#include "sysadm-iocage.h"
|
#include "sysadm-iocage.h"
|
||||||
#include "sysadm-global.h"
|
#include "sysadm-global.h"
|
||||||
//need access to the global DISPATCHER object
|
//need access to the global DISPATCHER object
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
|
||||||
using namespace sysadm;
|
using namespace sysadm;
|
||||||
|
|
||||||
@@ -17,11 +17,11 @@ using namespace sysadm;
|
|||||||
QJsonObject Iocage::activateStatus(){
|
QJsonObject Iocage::activateStatus(){
|
||||||
QJsonObject retObject;
|
QJsonObject retObject;
|
||||||
bool success = false;
|
bool success = false;
|
||||||
QString output = General::RunCommand(success, "iocage activate --status");
|
QStringList info = General::RunCommand(success, "iocage get -p").split("\n");
|
||||||
retObject.insert("activated", success ? "true" : "false");
|
retObject.insert("activated", success ? "true" : "false");
|
||||||
if(success){
|
if(success){
|
||||||
//Grab the currently activated pool out of the return, and list that
|
//Grab the currently activated pool out of the return, and list that
|
||||||
QString pool = output.simplified();
|
QString pool = info.last().simplified();
|
||||||
retObject.insert("pool", pool);
|
retObject.insert("pool", pool);
|
||||||
}
|
}
|
||||||
return retObject;
|
return retObject;
|
||||||
@@ -87,59 +87,104 @@ QJsonObject Iocage::cleanAll() {
|
|||||||
//================TEMPLATE MANAGEMENT===================
|
//================TEMPLATE MANAGEMENT===================
|
||||||
QJsonObject Iocage::listTemplates(){
|
QJsonObject Iocage::listTemplates(){
|
||||||
QJsonObject retObject;
|
QJsonObject retObject;
|
||||||
QStringList local = General::RunCommand("iocage list -tlh ").split("\n");
|
bool ok = false;
|
||||||
for(int i=0; i<local.length(); i++){
|
QStringList local = General::RunCommand(ok, "iocage list -tlh ").split("\n");
|
||||||
QStringList info = local[i].split("\t"); //the -h flag is for scripting use (tabs as separators)
|
if(ok){
|
||||||
//NOTE ABOUT FORMAT:
|
QJsonObject temp;
|
||||||
// [JID, UUID, BOOT, STATE, TAG, TYPE, IP4, RELEASE, TEMPLATE]
|
for(int i=0; i<local.length(); i++){
|
||||||
if(info.length()!=9){ continue; } //invalid line
|
QStringList info = local[i].split("\t"); //the -h flag is for scripting use (tabs as separators)
|
||||||
QJsonObject obj;
|
//NOTE ABOUT FORMAT:
|
||||||
obj.insert("jid",info[0]);
|
// [JID, UUID, BOOT, STATE, TAG, TYPE, RELEASE, IP4, IP6, TEMPLATE]
|
||||||
obj.insert("uuid",info[1]);
|
if(info.length()!=10){ continue; } //invalid line
|
||||||
obj.insert("boot",info[2]);
|
QJsonObject obj;
|
||||||
obj.insert("state",info[3]);
|
obj.insert("jid",info[0]);
|
||||||
obj.insert("tag",info[4]);
|
obj.insert("uuid",info[1]);
|
||||||
obj.insert("type",info[5]);
|
obj.insert("boot",info[2]);
|
||||||
obj.insert("ip4",info[6]);
|
obj.insert("state",info[3]);
|
||||||
obj.insert("release",info[7]);
|
obj.insert("tag",info[4]);
|
||||||
obj.insert("template",info[8]);
|
obj.insert("type",info[5]);
|
||||||
retObject.insert(info[8], obj);
|
obj.insert("release",info[6]);
|
||||||
|
obj.insert("ip4",info[7]);
|
||||||
|
obj.insert("ip6",info[8]);
|
||||||
|
obj.insert("template",info[9]);
|
||||||
|
temp.insert(info[9], obj);
|
||||||
|
}
|
||||||
|
retObject.insert("templates", temp);
|
||||||
|
}else{
|
||||||
|
retObject.insert("error",local.join("\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return retObject;
|
return retObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject Iocage::listReleases(){
|
QJsonObject Iocage::listReleases(){
|
||||||
QJsonObject retObject;
|
QJsonObject retObject;
|
||||||
// Locally-available releases
|
// Locally-available releases
|
||||||
QStringList local = General::RunCommand("iocage list -rh").split("\n");
|
bool ok = false;
|
||||||
retObject.insert("local", QJsonArray::fromStringList(local) );
|
QStringList local = General::RunCommand(ok, "iocage list -rh").split("\n");
|
||||||
|
if(ok){ retObject.insert("local", QJsonArray::fromStringList(local) ); }
|
||||||
//Remote releases available for download
|
//Remote releases available for download
|
||||||
QStringList remote = General::RunCommand("iocage list -Rh").split("\n");
|
QStringList remote = General::RunCommand(ok, "iocage list -rRh").split("\n");
|
||||||
for(int i=0; i<remote.length(); i++){
|
if(ok){
|
||||||
if(remote[i].startsWith("[")){ remote[i] = remote[i].section("]",1,-1); }
|
for(int i=0; i<remote.length(); i++){
|
||||||
else{ remote.removeAt(i); i--; }
|
if(remote[i].startsWith("[")){ remote[i] = remote[i].section("]",1,-1).simplified(); }
|
||||||
|
else{ remote.removeAt(i); i--; }
|
||||||
|
}
|
||||||
|
retObject.insert("remote", QJsonArray::fromStringList(remote));
|
||||||
}
|
}
|
||||||
retObject.insert("remote", QJsonArray::fromStringList(remote));
|
|
||||||
return retObject;
|
return retObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject Iocage::listPlugins(){
|
QJsonObject Iocage::listPlugins(){
|
||||||
QJsonObject retObject;
|
QJsonObject retObject;
|
||||||
//Not sure about format of this yet (just commited upstream) - just treat it as line-delimited for now. (2/16/17)
|
|
||||||
//locally downloaded plugins
|
|
||||||
QStringList local = General::RunCommand("iocage list -ph ").split("\n");
|
|
||||||
retObject.insert("local", QJsonArray::fromStringList(local) );
|
|
||||||
//Remote plugins available for download/use
|
//Remote plugins available for download/use
|
||||||
QStringList remote = General::RunCommand("iocage list -Ph").split("\n");
|
bool ok = false;
|
||||||
retObject.insert("remote", QJsonArray::fromStringList(remote));
|
QStringList remote = General::RunCommand(ok,"iocage list -PhR").split("\n");
|
||||||
|
QStringList local = General::RunCommand("iocage list -Ph").split("\n");
|
||||||
|
if(!ok && remote.first().startsWith("Traceback")){
|
||||||
|
//older version of iocage - no local browsing (remote uses the local syntax)
|
||||||
|
remote = local;
|
||||||
|
local.clear();
|
||||||
|
}
|
||||||
|
QJsonObject plugins;
|
||||||
|
for(int i=0; i<remote.length(); i++){
|
||||||
|
if(remote[i].startsWith("[")){ remote[i] = remote[i].section("]",1,-1); }
|
||||||
|
else{ remote.removeAt(i); i--; continue; }
|
||||||
|
//Now parse the line and put it into the plugins object
|
||||||
|
QJsonObject obj;
|
||||||
|
obj.insert("name", remote[i].section(" - ",0,0).simplified());
|
||||||
|
obj.insert("description", remote[i].section(" - ",1,-1).section("(",0,-2).simplified());
|
||||||
|
obj.insert("id", remote[i].section("(",-1).section(")",0,0).simplified());
|
||||||
|
plugins.insert(obj.value("id").toString(), obj);
|
||||||
|
}
|
||||||
|
retObject.insert("remote", plugins);
|
||||||
|
//Now do the local plugins
|
||||||
|
plugins = QJsonObject(); //clear it
|
||||||
|
for(int i=0; i<local.length(); i++){
|
||||||
|
QStringList info = local[i].split("\t"); //the -h flag is for scripting use (tabs as separators)
|
||||||
|
//NOTE ABOUT FORMAT:
|
||||||
|
// [JID, UUID, BOOT, STATE, TAG, TYPE, RELEASE, IP4, IP6, TEMPLATE]
|
||||||
|
if(info.length()!=10){ continue; } //invalid line
|
||||||
|
QJsonObject obj;
|
||||||
|
obj.insert("jid",info[0]);
|
||||||
|
obj.insert("uuid",info[1]);
|
||||||
|
obj.insert("boot",info[2]);
|
||||||
|
obj.insert("state",info[3]);
|
||||||
|
obj.insert("tag",info[4]); //name of the plugin used (non-unique)
|
||||||
|
obj.insert("type",info[5]);
|
||||||
|
obj.insert("release",info[6]);
|
||||||
|
obj.insert("ip4",info[7]);
|
||||||
|
obj.insert("ip6",info[8]);
|
||||||
|
obj.insert("template",info[9]);
|
||||||
|
plugins.insert(info[4]+"_"+info[0], obj);
|
||||||
|
}
|
||||||
|
retObject.insert("local",plugins);
|
||||||
return retObject;
|
return retObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject Iocage::fetchReleases(QJsonObject inobj){
|
QJsonObject Iocage::fetchReleases(QJsonObject inobj){
|
||||||
QJsonObject retObject;
|
QJsonObject retObject;
|
||||||
if(!inobj.contains("releases")){ return retObject; } //nothing to do
|
if(!inobj.contains("releases")){ return retObject; } //nothing to do
|
||||||
QStringList releases;
|
QStringList releases;
|
||||||
if(inobj.value("releases").isArray()){ releases = General::JsonArrayToStringList(inobj.value("releases").toArray()); }
|
if(inobj.value("releases").isArray()){ releases = General::JsonArrayToStringList(inobj.value("releases").toArray()); }
|
||||||
else if(inobj.value("releases").isString()){ releases << inobj.value("releases").toString(); }
|
else if(inobj.value("releases").isString()){ releases << inobj.value("releases").toString(); }
|
||||||
//Now start up each of these downloads as appropriate
|
//Now start up each of these downloads as appropriate
|
||||||
@@ -147,7 +192,7 @@ QJsonObject Iocage::fetchReleases(QJsonObject inobj){
|
|||||||
QString jobprefix = "sysadm_iocage_fetch_release_";
|
QString jobprefix = "sysadm_iocage_fetch_release_";
|
||||||
QJsonArray started;
|
QJsonArray started;
|
||||||
for(int i=0; i<releases.length(); i++){
|
for(int i=0; i<releases.length(); i++){
|
||||||
releases[i] = releases[i].section(" ",0,0, QString::SectionSkipEmpty); //all valid releases are a single word - do not allow injection of other commands
|
releases[i] = releases[i].section(" ",0,0, QString::SectionSkipEmpty); //all valid releases are a single word - do not allow injection of other commands (or "(EOL)" tags on end)
|
||||||
if(cids.contains(jobprefix+releases[i]) ){ continue; } //this fetch job is already running - skip it for now
|
if(cids.contains(jobprefix+releases[i]) ){ continue; } //this fetch job is already running - skip it for now
|
||||||
DISPATCHER->queueProcess(jobprefix+releases[i], "iocage fetch --verify -r "+releases[i]);
|
DISPATCHER->queueProcess(jobprefix+releases[i], "iocage fetch --verify -r "+releases[i]);
|
||||||
started << jobprefix+releases[i];
|
started << jobprefix+releases[i];
|
||||||
@@ -156,25 +201,28 @@ QJsonObject Iocage::fetchReleases(QJsonObject inobj){
|
|||||||
return retObject;
|
return retObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject Iocage::fetchPlugins(QJsonObject inobj){
|
QJsonObject Iocage::fetchPlugin(QJsonObject inobj){
|
||||||
QJsonObject retObject;
|
QJsonObject retObject;
|
||||||
if(!inobj.contains("plugins")){ return retObject; } //nothing to do
|
if(!inobj.contains("plugin") || !inobj.contains("net_device") || ! (inobj.contains("ip4") || inobj.contains("ip6")) ){ return retObject; } //nothing to do
|
||||||
QStringList plugins;
|
QString plugin = inobj.value("plugin").toString();
|
||||||
if(inobj.value("plugins").isArray()){ plugins = General::JsonArrayToStringList(inobj.value("plugins").toArray()); }
|
QString dev = inobj.value("net_device").toString();
|
||||||
else if(inobj.value("plugins").isString()){ plugins << inobj.value("plugins").toString(); }
|
QString inet;
|
||||||
|
if(inobj.contains("ip6")){
|
||||||
|
inet = "ip6_addr=\""+dev+"|"+inobj.value("ip6").toString()+"\"";
|
||||||
|
}else{
|
||||||
|
inet = "ip4_addr=\""+dev+"|"+inobj.value("ip4").toString()+"\"";
|
||||||
|
}
|
||||||
|
|
||||||
//Now start up each of these downloads as appropriate
|
//Now start up each of these downloads as appropriate
|
||||||
QStringList cids = DISPATCHER->listJobs().value("no_queue").toObject().keys(); //all currently running/pending jobs
|
QStringList cids = DISPATCHER->listJobs().value("no_queue").toObject().keys(); //all currently running/pending jobs
|
||||||
QString jobprefix = "sysadm_iocage_fetch_plugin_";
|
QString jobprefix = "sysadm_iocage_fetch_plugin_";
|
||||||
QJsonArray started;
|
plugin = plugin.section(" ",0,0, QString::SectionSkipEmpty); //all valid releases are a single word - do not allow injection of other commands
|
||||||
for(int i=0; i<plugins.length(); i++){
|
if(cids.contains(jobprefix+plugin) ){ return QJsonObject(); } //this fetch job is already running
|
||||||
plugins[i] = plugins[i].section(" ",0,0, QString::SectionSkipEmpty); //all valid releases are a single word - do not allow injection of other commands
|
DISPATCHER->queueProcess(jobprefix+plugin, "iocage fetch -P --name "+plugin+" "+inet);
|
||||||
if(cids.contains(jobprefix+plugins[i]) ){ continue; } //this fetch job is already running - skip it for now
|
retObject.insert("started_dispatcher_id", jobprefix+plugin);
|
||||||
DISPATCHER->queueProcess(jobprefix+plugins[i], "iocage fetch --verify -P "+plugins[i]);
|
|
||||||
started << jobprefix+plugins[i];
|
|
||||||
}
|
|
||||||
if(started.count()>0){ retObject.insert("started_dispatcher_id", started); }
|
|
||||||
return retObject;
|
return retObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean all templates on a box
|
// Clean all templates on a box
|
||||||
QJsonObject Iocage::cleanTemplates() {
|
QJsonObject Iocage::cleanTemplates() {
|
||||||
QJsonObject retObject;
|
QJsonObject retObject;
|
||||||
@@ -205,23 +253,31 @@ QJsonObject Iocage::cleanReleases() {
|
|||||||
// List the jails on the box
|
// List the jails on the box
|
||||||
QJsonObject Iocage::listJails() {
|
QJsonObject Iocage::listJails() {
|
||||||
QJsonObject retObject;
|
QJsonObject retObject;
|
||||||
QStringList output = General::RunCommand("iocage list -lh").split("\n");
|
bool ok = false;
|
||||||
for(int i=0; i<output.length(); i++){
|
QStringList local = General::RunCommand(ok, "iocage list -lh").split("\n");
|
||||||
QStringList info = output[i].split("\t");
|
if(ok){
|
||||||
//FORMAT NOTE: (long output: "-l" flag)
|
QJsonObject temp;
|
||||||
// [JID, UUID, BOOT, STATE, TAG, TYPE, IP4, RELEASE, TEMPLATE]
|
for(int i=0; i<local.length(); i++){
|
||||||
if(info.length()!=9){ continue; } //invalid line
|
QStringList info = local[i].split("\t"); //the -h flag is for scripting use (tabs as separators)
|
||||||
QJsonObject obj;
|
//NOTE ABOUT FORMAT:
|
||||||
obj.insert("jid",info[0]);
|
// [JID, UUID, BOOT, STATE, TAG, TYPE, RELEASE, IP4, IP6, TEMPLATE]
|
||||||
obj.insert("uuid",info[1]);
|
if(info.length()!=10){ continue; } //invalid line
|
||||||
obj.insert("boot",info[2]);
|
QJsonObject obj;
|
||||||
obj.insert("state",info[3]);
|
obj.insert("jid",info[0]);
|
||||||
obj.insert("tag",info[4]);
|
obj.insert("uuid",info[1]);
|
||||||
obj.insert("type",info[5]);
|
obj.insert("boot",info[2]);
|
||||||
obj.insert("ip4",info[6]);
|
obj.insert("state",info[3]);
|
||||||
obj.insert("release",info[7]);
|
obj.insert("tag",info[4]);
|
||||||
obj.insert("template",info[8]);
|
obj.insert("type",info[5]);
|
||||||
retObject.insert(info[1], obj); //use uuid as main id tag
|
obj.insert("release",info[6]);
|
||||||
|
obj.insert("ip4",info[7]);
|
||||||
|
obj.insert("ip6",info[8]);
|
||||||
|
obj.insert("template",info[9]);
|
||||||
|
temp.insert(info[0], obj);
|
||||||
|
}
|
||||||
|
retObject.insert("jails", temp);
|
||||||
|
}else{
|
||||||
|
retObject.insert("error",local.join("\n"));
|
||||||
}
|
}
|
||||||
return retObject;
|
return retObject;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public:
|
|||||||
static QJsonObject listReleases();
|
static QJsonObject listReleases();
|
||||||
static QJsonObject listPlugins();
|
static QJsonObject listPlugins();
|
||||||
static QJsonObject fetchReleases(QJsonObject);
|
static QJsonObject fetchReleases(QJsonObject);
|
||||||
static QJsonObject fetchPlugins(QJsonObject);
|
static QJsonObject fetchPlugin(QJsonObject);
|
||||||
static QJsonObject cleanTemplates();
|
static QJsonObject cleanTemplates();
|
||||||
static QJsonObject cleanReleases();
|
static QJsonObject cleanReleases();
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ public:
|
|||||||
static QJsonObject capJail(QJsonObject);
|
static QJsonObject capJail(QJsonObject);
|
||||||
|
|
||||||
static QJsonObject getJailSettings(QJsonObject);
|
static QJsonObject getJailSettings(QJsonObject);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} //end of namespace
|
} //end of namespace
|
||||||
|
|||||||
@@ -7,12 +7,23 @@
|
|||||||
#include "sysadm-general.h"
|
#include "sysadm-general.h"
|
||||||
#include "sysadm-moused.h"
|
#include "sysadm-moused.h"
|
||||||
#include "sysadm-global.h"
|
#include "sysadm-global.h"
|
||||||
|
#include "sysadm-systemmanager.h"
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
|
||||||
#define _MOUSED_CONF QString("/etc/conf.d/moused")
|
#define _MOUSED_CONF QString("/etc/conf.d/moused")
|
||||||
#define _MOUSED_SYS_CONF QString("/etc/rc.conf")
|
#define _MOUSED_SYS_CONF QString("/etc/rc.conf")
|
||||||
#define _MOUSED_DEFAULT_CONF QString("/etc/defaults/rc.conf")
|
#define _MOUSED_DEFAULT_CONF QString("/etc/defaults/rc.conf")
|
||||||
|
|
||||||
|
//Setup the Tap To Click (TTC) sysctl definitions
|
||||||
|
#define _MOUSED_TTC_ENABLED QString("hw.psm.tap_enabled")
|
||||||
|
#define _MOUSED_TTC_NORMAL QString("hw.psm.tap_timeout")
|
||||||
|
#define _MOUSED_TTC_SYNAPTICS QString("hw.psm.synaptics.taphold_timeout")
|
||||||
|
#define _MOUSED_TTC_ENABLE_SYNAPTICS QString("hw.psm.synaptics_support")
|
||||||
|
|
||||||
|
//Additional Synaptics controls
|
||||||
|
#define _MOUSED_SYNAPTICS_TOUCHPAD_OFF QString("hw.psm.synaptics.touchpad_off")
|
||||||
|
#define _MOUSED_SYNAPTICS_TWOFINGER_SCROLL QString("hw.psm.synaptics.two_finger_scroll")
|
||||||
|
|
||||||
using namespace sysadm;
|
using namespace sysadm;
|
||||||
|
|
||||||
QJsonObject moused::listDevices(){
|
QJsonObject moused::listDevices(){
|
||||||
@@ -46,6 +57,7 @@ QJsonObject moused::listOptions(){
|
|||||||
QJsonObject out;
|
QJsonObject out;
|
||||||
out.insert("emulate_button_3", QJsonArray() << "true" << "false");
|
out.insert("emulate_button_3", QJsonArray() << "true" << "false");
|
||||||
out.insert("hand_mode", QJsonArray() << "left" << "right");
|
out.insert("hand_mode", QJsonArray() << "left" << "right");
|
||||||
|
out.insert("mouse_scroll_invert", QJsonArray() << "true" << "false");
|
||||||
out.insert("virtual_scrolling", QJsonArray() << "true" << "false");
|
out.insert("virtual_scrolling", QJsonArray() << "true" << "false");
|
||||||
out.insert("accel_exponential", "float min=1.0 max=2.0");
|
out.insert("accel_exponential", "float min=1.0 max=2.0");
|
||||||
out.insert("accel_linear", "float min=0.01 max=100.00");
|
out.insert("accel_linear", "float min=0.01 max=100.00");
|
||||||
@@ -53,12 +65,12 @@ QJsonObject moused::listOptions(){
|
|||||||
out.insert("terminate_drift_threshold_pixels", "int min=0 max=1000");
|
out.insert("terminate_drift_threshold_pixels", "int min=0 max=1000");
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject moused::readOptions(QJsonObject obj){
|
QJsonObject moused::readOptions(QJsonObject obj){
|
||||||
QString device = obj.value("device").toString();
|
QString device = obj.value("device").toString();
|
||||||
//qDebug() << "Read Options for Device:" << device;
|
//qDebug() << "Read Options for Device:" << device;
|
||||||
if(device.isEmpty()){ return QJsonObject(); } //invalid inputs
|
if(device.isEmpty()){ return QJsonObject(); } //invalid inputs
|
||||||
|
|
||||||
QString val = General::getConfFileValue(_MOUSED_CONF, "moused_args_"+device+"=" );
|
QString val = General::getConfFileValue(_MOUSED_CONF, "moused_args_"+device+"=" );
|
||||||
if(val.isEmpty()){ General::getConfFileValue(_MOUSED_SYS_CONF, "moused_flags=" ); }
|
if(val.isEmpty()){ General::getConfFileValue(_MOUSED_SYS_CONF, "moused_flags=" ); }
|
||||||
if(val.isEmpty()){ General::getConfFileValue(_MOUSED_DEFAULT_CONF, "moused_flags=" ); }
|
if(val.isEmpty()){ General::getConfFileValue(_MOUSED_DEFAULT_CONF, "moused_flags=" ); }
|
||||||
@@ -72,10 +84,13 @@ QJsonObject moused::readOptions(QJsonObject obj){
|
|||||||
out.insert("emulate_button_3", args.contains("-3") ? "true" : "false");
|
out.insert("emulate_button_3", args.contains("-3") ? "true" : "false");
|
||||||
int index = args.indexOf("-m");
|
int index = args.indexOf("-m");
|
||||||
bool righthand = true;
|
bool righthand = true;
|
||||||
|
bool scrollinvert = false;
|
||||||
while(index>=0 && args.length() > (index+1) ){
|
while(index>=0 && args.length() > (index+1) ){
|
||||||
if(args[index+1].startsWith("1=")){ righthand = (args[index+1] == "1=1"); }
|
if(args[index+1].startsWith("1=")){ righthand = (args[index+1] == "1=1"); }
|
||||||
|
else if(args[index+1].startsWith("4=")){ scrollinvert = (args[index+1] == "4=5"); }
|
||||||
index = args.indexOf("-m", index+1);
|
index = args.indexOf("-m", index+1);
|
||||||
}
|
}
|
||||||
|
out.insert("mouse_scroll_invert", scrollinvert ? "true" : "false" );
|
||||||
out.insert("hand_mode", righthand ? "right" : "left");
|
out.insert("hand_mode", righthand ? "right" : "left");
|
||||||
out.insert("virtual_scrolling", args.contains("-V") ? "true" : "false" );
|
out.insert("virtual_scrolling", args.contains("-V") ? "true" : "false" );
|
||||||
|
|
||||||
@@ -122,6 +137,7 @@ QJsonObject moused::setOptions(QJsonObject obj){
|
|||||||
QString val = Cobj.value(keys[i]).toString();
|
QString val = Cobj.value(keys[i]).toString();
|
||||||
if(keys[i]=="emulate_button_3" && val=="true"){ args << "-3"; }
|
if(keys[i]=="emulate_button_3" && val=="true"){ args << "-3"; }
|
||||||
else if(keys[i]=="hand_mode" && val=="left"){ args << "-m" << "1=3" << "-m" << "3=1"; }
|
else if(keys[i]=="hand_mode" && val=="left"){ args << "-m" << "1=3" << "-m" << "3=1"; }
|
||||||
|
else if(keys[i]=="mouse_scroll_invert" && val=="true"){ args << "-m" << "4=5" << "-m" << "5=4"; }
|
||||||
else if(keys[i]=="virtual_scrolling" && val=="true"){ args << "-V" << "-H"; } //Enable both horizontal and vertical virtual scrolling
|
else if(keys[i]=="virtual_scrolling" && val=="true"){ args << "-V" << "-H"; } //Enable both horizontal and vertical virtual scrolling
|
||||||
else if(keys[i]=="accel_exponential" && val!="1.0"){ args << "-A" << val; }
|
else if(keys[i]=="accel_exponential" && val!="1.0"){ args << "-A" << val; }
|
||||||
else if(keys[i]=="accel_linear" && val!="1.0"){ args << "-a" << val; } //both X and Y linear acceleration
|
else if(keys[i]=="accel_linear" && val!="1.0"){ args << "-a" << val; } //both X and Y linear acceleration
|
||||||
@@ -141,8 +157,8 @@ QJsonObject moused::listActiveDevices(){
|
|||||||
QDir dir("/var/run");
|
QDir dir("/var/run");
|
||||||
QJsonObject out;
|
QJsonObject out;
|
||||||
QStringList devsactive = dir.entryList(QStringList() << "moused-*.pid", QDir::Files, QDir::Name);
|
QStringList devsactive = dir.entryList(QStringList() << "moused-*.pid", QDir::Files, QDir::Name);
|
||||||
for(int i=0; i<devsactive.length(); i++){
|
for(int i=0; i<devsactive.length(); i++){
|
||||||
devsactive[i] = devsactive[i].section("-",1,-1).section(".pid",0,0);
|
devsactive[i] = devsactive[i].section("-",1,-1).section(".pid",0,0);
|
||||||
}
|
}
|
||||||
out.insert("active_devices", QJsonArray::fromStringList(devsactive));
|
out.insert("active_devices", QJsonArray::fromStringList(devsactive));
|
||||||
return out;
|
return out;
|
||||||
@@ -167,3 +183,96 @@ QJsonObject moused::disableDevice(QJsonObject obj){
|
|||||||
out.insert("stopped", device);
|
out.insert("stopped", device);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QJsonObject moused::tapToClick(){
|
||||||
|
QJsonObject out;
|
||||||
|
QJsonObject tmp;
|
||||||
|
tmp.insert("sysctl", QJsonArray() << _MOUSED_TTC_NORMAL << _MOUSED_TTC_SYNAPTICS << _MOUSED_TTC_ENABLED << _MOUSED_TTC_ENABLE_SYNAPTICS);
|
||||||
|
tmp = SysMgmt::getSysctl(tmp);
|
||||||
|
bool usesynaptics = false;
|
||||||
|
int timeout = -1;
|
||||||
|
if(tmp.contains(_MOUSED_TTC_ENABLE_SYNAPTICS)){
|
||||||
|
usesynaptics = (tmp.value(_MOUSED_TTC_ENABLE_SYNAPTICS).toString().toInt()==1) && tmp.contains(_MOUSED_TTC_SYNAPTICS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(usesynaptics){
|
||||||
|
QString level = tmp.value(_MOUSED_TTC_SYNAPTICS).toString();
|
||||||
|
if(level.isEmpty()){ level = tmp.value(_MOUSED_TTC_NORMAL).toString(); }
|
||||||
|
out.insert("enabled", level.toInt()>0 ? "true" : "false" );
|
||||||
|
out.insert("timeout", level);
|
||||||
|
}else{
|
||||||
|
int enabled = tmp.value(_MOUSED_TTC_ENABLED).toString().toInt();
|
||||||
|
if(enabled<0){ out.insert("enabled", "unavailable"); }
|
||||||
|
else{ out.insert("enabled", (enabled==1) ? "true" : "false" ); }
|
||||||
|
out.insert("timeout", tmp.value(_MOUSED_TTC_NORMAL).toString() );
|
||||||
|
}
|
||||||
|
out.insert("using_synaptics", usesynaptics ? "true" : "false");
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject moused::setTapToClick(QJsonObject jsin){
|
||||||
|
QJsonObject out;
|
||||||
|
//Check the inputs first
|
||||||
|
if(!jsin.contains("enable") && !jsin.contains("timeout")){
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
//Find out which sysctls need to be set (only some systems have the synaptics option)
|
||||||
|
QJsonObject tmp;
|
||||||
|
tmp.insert("sysctl", QJsonArray() << _MOUSED_TTC_NORMAL << _MOUSED_TTC_SYNAPTICS << _MOUSED_TTC_ENABLED << _MOUSED_TTC_ENABLE_SYNAPTICS);
|
||||||
|
tmp = SysMgmt::getSysctl(tmp); //this will only return valid sysctls - can use it for quick filtering/detection
|
||||||
|
QStringList sysctls = tmp.keys();
|
||||||
|
bool usesynaptics = false;
|
||||||
|
if(tmp.contains(_MOUSED_TTC_ENABLE_SYNAPTICS)){ usesynaptics = (tmp.value(_MOUSED_TTC_ENABLE_SYNAPTICS).toString().toInt()==1) && tmp.contains(_MOUSED_TTC_SYNAPTICS); }
|
||||||
|
bool canenable = (tmp.value(_MOUSED_TTC_ENABLED).toString()!="-1" );
|
||||||
|
//Update the timeout as needed
|
||||||
|
if(jsin.contains("timeout")){
|
||||||
|
int ms = jsin.value("timeout").toInt(-1); //-1 is the default non-valid number
|
||||||
|
if(ms<0){ ms = jsin.value("timeout").toString().toInt(); } //try a string->integer instead
|
||||||
|
if(ms>=0){
|
||||||
|
tmp = QJsonObject(); //clear it for re-use
|
||||||
|
tmp.insert("value",QString::number(ms) );
|
||||||
|
if(sysctls.contains(_MOUSED_TTC_NORMAL)){ tmp.insert("sysctl",_MOUSED_TTC_NORMAL); SysMgmt::setSysctl(tmp); }
|
||||||
|
if(sysctls.contains(_MOUSED_TTC_SYNAPTICS)){ tmp.insert("sysctl",_MOUSED_TTC_SYNAPTICS); SysMgmt::setSysctl(tmp); }
|
||||||
|
out.insert("timeout", QString::number(ms) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Enable/Disable as needed
|
||||||
|
if(jsin.contains("enable") && canenable ){
|
||||||
|
bool enable = (jsin.value("enable").toString().toLower()=="true");
|
||||||
|
tmp = QJsonObject(); //clear it for re-use
|
||||||
|
if(usesynaptics){
|
||||||
|
if(!sysctls.contains("timeout")){ //if we just set this, don't overwrite it
|
||||||
|
tmp.insert("value", enable ? "125000" : "0"); //default values for enable/disable
|
||||||
|
tmp.insert("sysctl", _MOUSED_TTC_SYNAPTICS);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
tmp.insert("value", enable ? "1" : "0");
|
||||||
|
tmp.insert("sysctl", _MOUSED_TTC_ENABLED);
|
||||||
|
}
|
||||||
|
//Now make the actual change
|
||||||
|
if(!tmp.isEmpty()){
|
||||||
|
SysMgmt::setSysctl(tmp);
|
||||||
|
out.insert("enabled", enable ? "true" : "false");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Restart the moused daemon if we made any changes
|
||||||
|
if(!out.isEmpty()){ General::RunQuickCommand("service moused restart"); }
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject moused::synapticsSettings(){
|
||||||
|
QJsonObject tmp;
|
||||||
|
tmp.insert("sysctl", QJsonArray() << _MOUSED_SYNAPTICS_TOUCHPAD_OFF << _MOUSED_SYNAPTICS_TWOFINGER_SCROLL << _MOUSED_TTC_ENABLE_SYNAPTICS);
|
||||||
|
SysMgmt::getSysctl(tmp);
|
||||||
|
bool touch_off = false;
|
||||||
|
bool two_finger_scroll = false;
|
||||||
|
bool enabled = false;
|
||||||
|
if(tmp.contains(_MOUSED_SYNAPTICS_TOUCHPAD_OFF)){ touch_off = (tmp.value(_MOUSED_SYNAPTICS_TOUCHPAD_OFF).toString().toInt()==1); }
|
||||||
|
if(tmp.contains(_MOUSED_SYNAPTICS_TWOFINGER_SCROLL)){ two_finger_scroll = (tmp.value(_MOUSED_SYNAPTICS_TWOFINGER_SCROLL).toString().toInt()==1); }
|
||||||
|
if(tmp.contains(_MOUSED_TTC_ENABLE_SYNAPTICS)){ enabled = (tmp.value(_MOUSED_TTC_ENABLE_SYNAPTICS).toString().toInt()==1); }
|
||||||
|
QJsonObject out;
|
||||||
|
out.insert("disable_touchpad", touch_off ? "true" : "false");
|
||||||
|
out.insert("enable_two_finger_scroll", two_finger_scroll ? "true" : "false");
|
||||||
|
out.insert("enable_synaptics", enabled ? "true" : "false");
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,8 +26,15 @@ public:
|
|||||||
static QJsonObject enableDevice(QJsonObject);
|
static QJsonObject enableDevice(QJsonObject);
|
||||||
static QJsonObject disableDevice(QJsonObject);
|
static QJsonObject disableDevice(QJsonObject);
|
||||||
|
|
||||||
|
//General system input options
|
||||||
|
static QJsonObject tapToClick();
|
||||||
|
static QJsonObject setTapToClick(QJsonObject);
|
||||||
|
|
||||||
|
//Synaptics options
|
||||||
|
static QJsonObject synapticsSettings();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} //end of namespace
|
} //end of namespace
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ using namespace sysadm;
|
|||||||
//Copy over this data into the output structure
|
//Copy over this data into the output structure
|
||||||
NetworkEntry tmp;
|
NetworkEntry tmp;
|
||||||
tmp.name = QString::fromLocal8Bit(entry->n_name);
|
tmp.name = QString::fromLocal8Bit(entry->n_name);
|
||||||
for(int i=0; entry->n_aliases[i] != 0; i++){
|
for(int i=0; entry->n_aliases[i] != 0; i++){
|
||||||
tmp.aliases << QString::fromLocal8Bit(entry->n_aliases[i]);
|
tmp.aliases << QString::fromLocal8Bit(entry->n_aliases[i]);
|
||||||
}
|
}
|
||||||
tmp.netnum = entry->n_net;
|
tmp.netnum = entry->n_net;
|
||||||
@@ -57,8 +57,9 @@ NetDevSettings Network::deviceRCSettings(QString dev){
|
|||||||
if(val.startsWith("\"")){ val = val.remove(1); }
|
if(val.startsWith("\"")){ val = val.remove(1); }
|
||||||
if(val.endsWith("\"")){ val.chop(1); }
|
if(val.endsWith("\"")){ val.chop(1); }
|
||||||
val.prepend(" "); val.append(" "); //just to make additional parsing easier later - each "variable" should have whitespace on both sides
|
val.prepend(" "); val.append(" "); //just to make additional parsing easier later - each "variable" should have whitespace on both sides
|
||||||
if( (var=="vlans_"+dev) || (var=="wlans_"+dev) ){
|
if( val.simplified()==dev && (var.startsWith("vlans_") || var.startsWith("wlans_") )){
|
||||||
set.asDevice = val;
|
set.asDevice = var.section("_",1,-1);
|
||||||
|
if(var.startsWith("wlans_")){ set.wifihost = true; }
|
||||||
}else if(var==("ifconfig_"+dev)){
|
}else if(var==("ifconfig_"+dev)){
|
||||||
QStringList vals = val.split(" ",QString::SkipEmptyParts);
|
QStringList vals = val.split(" ",QString::SkipEmptyParts);
|
||||||
//This is the main settings line: lots of things to look for:
|
//This is the main settings line: lots of things to look for:
|
||||||
@@ -73,13 +74,13 @@ NetDevSettings Network::deviceRCSettings(QString dev){
|
|||||||
//IPv4/6 address can sometimes not have the "inet(6)" identifier - look through the first few values as well
|
//IPv4/6 address can sometimes not have the "inet(6)" identifier - look through the first few values as well
|
||||||
QStringList vals = val.split(" ",QString::SkipEmptyParts);
|
QStringList vals = val.split(" ",QString::SkipEmptyParts);
|
||||||
for(int v=0; v<vals.length(); v++){
|
for(int v=0; v<vals.length(); v++){
|
||||||
|
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
}else{ set.useDHCP=true; } //end of DHCP check
|
}else{ set.useDHCP=true; } //end of DHCP check
|
||||||
//Wifi Checks
|
//Wifi Checks
|
||||||
if(vals.contains("WPA")){ set.wifisecurity=true; }
|
if(vals.contains("WPA")){ set.wifisecurity=true; }
|
||||||
|
|
||||||
} //end variable checks
|
} //end variable checks
|
||||||
} //end loop over rc.conf lines
|
} //end loop over rc.conf lines
|
||||||
return set;
|
return set;
|
||||||
@@ -119,11 +120,53 @@ NetDevSettings Network::deviceRCSettings(QString dev){
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
//--------------------------------------
|
//--------------------------------------
|
||||||
bool NetworkRoot::saveRCSettings(NetDevSettings){
|
bool NetworkRoot::saveRCSettings(NetDevSettings set){
|
||||||
return false;
|
if(!QFile::exists("/dev/"+set.device)){ return false; } //invalid device
|
||||||
|
//Create the lines which need to be put info /etc/rc.conf based on the settings
|
||||||
|
QStringList tags, lines, found;
|
||||||
|
//Related device lines
|
||||||
|
if(!set.asDevice.isEmpty()){
|
||||||
|
if(set.wifihost){ tags << "wlans_"+set.asDevice; lines << "wlans_"+set.asDevice+"=\""+set.device+"\""; }
|
||||||
|
else{ tags << "vlans_"+set.asDevice; lines << "vlans_"+set.asDevice+"=\""+set.device+"\""; }
|
||||||
|
}
|
||||||
|
//Main device line
|
||||||
|
QString tmp = "ifconfig_"+set.device+"=\"";
|
||||||
|
if(set.useDHCP){ tmp.append("DHCP"); }
|
||||||
|
else{
|
||||||
|
if(!set.staticIPv4.isEmpty()){ tmp.append("inet "+set.staticIPv4+" "); }
|
||||||
|
if(!set.staticIPv6.isEmpty()){ tmp.append("inet6 "+set.staticIPv6+" "); }
|
||||||
|
if(!set.staticNetmask.isEmpty()){ tmp.append("netmask "+set.staticNetmask+" "); }
|
||||||
|
if(!set.staticGateway.isEmpty()){ tmp.append("gateway "+set.staticGateway+" "); }
|
||||||
|
tmp = tmp.simplified(); //remove any excess whitespace on end
|
||||||
|
}
|
||||||
|
QString var = "ifconfig_"+set.device;
|
||||||
|
tags << var;
|
||||||
|
if(!tmp.isEmpty()){ lines << var+"=\""+tmp+"\""; }
|
||||||
|
else{ lines << ""; } //delete the line
|
||||||
|
|
||||||
|
//Now read rc.conf and adjust contents as needed
|
||||||
|
QStringList info = Network::readRcConf();
|
||||||
|
for(int i=0; i<info.length(); i++){
|
||||||
|
if(info[i].simplified().isEmpty()){ continue; }
|
||||||
|
QString var = info[i].section("=",0,0).simplified();
|
||||||
|
if( tags.contains(var) ){
|
||||||
|
int index = tags.indexOf(var);
|
||||||
|
info[i] = lines[index];
|
||||||
|
lines.removeAt(index);
|
||||||
|
found << tags.takeAt(index);
|
||||||
|
}else if(found.contains(var)){
|
||||||
|
//Duplicate line - remove this since it was already handled
|
||||||
|
info.removeAt(i); i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Now add any lines which were not already found to the end of the file
|
||||||
|
for(int i=0; i<lines.length(); i++){
|
||||||
|
info << lines[i];
|
||||||
|
}
|
||||||
|
return General::writeTextFile("/etc/rc.conf", info, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------
|
//--------------------------------------
|
||||||
bool NetworkRoot::setIfconfigSettings(NetDevSettings){
|
bool NetworkRoot::setIfconfigSettings(NetDevSettings){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ struct NetDevSettings{
|
|||||||
//General data class for network devices
|
//General data class for network devices
|
||||||
// Note: Sources in NetDevice.cpp
|
// Note: Sources in NetDevice.cpp
|
||||||
class NetDevice{
|
class NetDevice{
|
||||||
private:
|
private:
|
||||||
QString name;
|
QString name;
|
||||||
public:
|
public:
|
||||||
NetDevice(QString devName){ name = devName; }
|
NetDevice(QString devName){ name = devName; }
|
||||||
@@ -61,7 +61,7 @@ public:
|
|||||||
long packetsTx();
|
long packetsTx();
|
||||||
long errorsRx();
|
long errorsRx();
|
||||||
long errorsTx();
|
long errorsTx();
|
||||||
|
|
||||||
//Setting Functions (to make changes - requires root)
|
//Setting Functions (to make changes - requires root)
|
||||||
void setUp(bool up); //Turn device on/off (temporary - not saved globally)
|
void setUp(bool up); //Turn device on/off (temporary - not saved globally)
|
||||||
|
|
||||||
@@ -75,7 +75,6 @@ struct NetWifi{
|
|||||||
QString BSSID, SSID;
|
QString BSSID, SSID;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//The general-purpose class that any user/app can utilitize
|
//The general-purpose class that any user/app can utilitize
|
||||||
class Network{
|
class Network{
|
||||||
public:
|
public:
|
||||||
@@ -88,11 +87,11 @@ public:
|
|||||||
//The class that requires overarching root permissions (usually for changes to system)
|
//The class that requires overarching root permissions (usually for changes to system)
|
||||||
class NetworkRoot{
|
class NetworkRoot{
|
||||||
public:
|
public:
|
||||||
//static bool saveNetworkEntry(NetworkEntry); //**Not implemented yet**
|
//static bool saveNetworkEntry(NetworkEntry); // **Not implemented yet**
|
||||||
static bool saveRCSettings(NetDevSettings); //rc.conf settings (bootup)
|
static bool saveRCSettings(NetDevSettings); //rc.conf settings (bootup)
|
||||||
static bool setIfconfigSettings(NetDevSettings); //ifconfig settings (temporary session)
|
static bool setIfconfigSettings(NetDevSettings); //ifconfig settings (temporary session)
|
||||||
};
|
};
|
||||||
|
|
||||||
} //end of pcbsd namespace
|
} //end of pcbsd namespace
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -14,6 +14,20 @@ using namespace sysadm;
|
|||||||
// ==================
|
// ==================
|
||||||
// INLINE FUNCTIONS
|
// INLINE FUNCTIONS
|
||||||
// ==================
|
// ==================
|
||||||
|
inline QStringList ids_from_origins(QStringList origins, QSqlDatabase DB){
|
||||||
|
QSqlQuery q("SELECT id FROM packages WHERE origin IN ('"+origins.join("', '")+"')",DB);
|
||||||
|
QStringList out;
|
||||||
|
while(q.next()){ out << q.value("id").toString(); }
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QStringList ids_from_names(QStringList names, QSqlDatabase DB){
|
||||||
|
QSqlQuery q("SELECT id FROM packages WHERE name IN ('"+names.join("', '")+"')",DB);
|
||||||
|
QStringList out;
|
||||||
|
while(q.next()){ out << q.value("id").toString(); }
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
//Get annotation variable/values
|
//Get annotation variable/values
|
||||||
inline void annotations_from_ids(QStringList var_ids, QStringList val_ids, QJsonObject *out, QSqlDatabase DB){
|
inline void annotations_from_ids(QStringList var_ids, QStringList val_ids, QJsonObject *out, QSqlDatabase DB){
|
||||||
//Note: Both input lists *must* be the same length (one variable for one value)
|
//Note: Both input lists *must* be the same length (one variable for one value)
|
||||||
@@ -21,16 +35,16 @@ inline void annotations_from_ids(QStringList var_ids, QStringList val_ids, QJson
|
|||||||
tot.removeDuplicates();
|
tot.removeDuplicates();
|
||||||
int index = -1;
|
int index = -1;
|
||||||
QSqlQuery q("SELECT annotation, annotation_id FROM annotation WHERE annotation_id IN ('"+tot.join("', '")+"')",DB);
|
QSqlQuery q("SELECT annotation, annotation_id FROM annotation WHERE annotation_id IN ('"+tot.join("', '")+"')",DB);
|
||||||
while(q.next()){
|
while(q.next()){
|
||||||
//qDebug() << "Got query result:" << q.value("annotation_id").toString() << q.value("annotation").toString();
|
//qDebug() << "Got query result:" << q.value("annotation_id").toString() << q.value("annotation").toString();
|
||||||
index = var_ids.indexOf(q.value("annotation_id").toString());
|
index = var_ids.indexOf(q.value("annotation_id").toString());
|
||||||
while(index>=0){
|
while(index>=0){
|
||||||
var_ids.replace(index, q.value("annotation").toString());
|
var_ids.replace(index, q.value("annotation").toString());
|
||||||
index = var_ids.indexOf(q.value("annotation_id").toString());
|
index = var_ids.indexOf(q.value("annotation_id").toString());
|
||||||
}
|
}
|
||||||
index = val_ids.indexOf(q.value("annotation_id").toString());
|
index = val_ids.indexOf(q.value("annotation_id").toString());
|
||||||
while(index>=0){
|
while(index>=0){
|
||||||
val_ids.replace(index, q.value("annotation").toString());
|
val_ids.replace(index, q.value("annotation").toString());
|
||||||
index = val_ids.indexOf(q.value("annotation_id").toString());
|
index = val_ids.indexOf(q.value("annotation_id").toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,7 +61,7 @@ inline QStringList origins_from_package_ids(QStringList ids, QSqlDatabase DB){
|
|||||||
while(q.next()){ out << q.value("origin").toString(); }
|
while(q.next()){ out << q.value("origin").toString(); }
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
//Generic ID's -> Names function (known databases: users, groups, licenses, shlibs, categories )
|
//Generic ID's -> Names function (known databases: users, groups, licenses, shlibs, categories, packages )
|
||||||
inline QStringList names_from_ids(QStringList ids, QString db, QSqlDatabase DB){
|
inline QStringList names_from_ids(QStringList ids, QString db, QSqlDatabase DB){
|
||||||
QSqlQuery q("SELECT name FROM "+db+" WHERE id IN ('"+ids.join("', '")+"')",DB);
|
QSqlQuery q("SELECT name FROM "+db+" WHERE id IN ('"+ids.join("', '")+"')",DB);
|
||||||
QStringList out;
|
QStringList out;
|
||||||
@@ -68,15 +82,35 @@ inline QStringList requires_from_ids(QStringList ids, QSqlDatabase DB){
|
|||||||
while(q.next()){ out << q.value("require").toString(); }
|
while(q.next()){ out << q.value("require").toString(); }
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//conflict ID's from package ID's
|
||||||
|
inline QStringList conflicts_from_ids(QStringList ids, QSqlDatabase DB){
|
||||||
|
QSqlQuery q("SELECT conflict_id FROM pkg_conflicts WHERE package_id IN ('"+ids.join("', '")+"')", DB);
|
||||||
|
QStringList out;
|
||||||
|
while(q.next()){ out << q.value("conflict_id").toString(); }
|
||||||
|
qDebug() << "Last Conflict detection Error:" << q.lastError().text();
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
//dependencies from package ID's
|
||||||
|
inline QStringList depends_from_ids(QStringList ids, QSqlDatabase DB){
|
||||||
|
//Note: This returns package names, not ID's
|
||||||
|
QSqlQuery q("SELECT name FROM deps WHERE package_id IN ('"+ids.join("', '")+"')", DB);
|
||||||
|
QStringList out;
|
||||||
|
while(q.next()){ out << q.value("name").toString(); }
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline QString getRepoFile(QString repo){
|
inline QString getRepoFile(QString repo){
|
||||||
if(repo=="local"){ return "/var/db/pkg/local.sqlite"; }
|
if(repo=="local"){ return "/var/db/pkg/local.sqlite"; }
|
||||||
else{ return ("/var/db/pkg/repo-"+repo+".sqlite"); }
|
else{ return ("/var/db/pkg/repo-"+repo+".sqlite"); }
|
||||||
}
|
}
|
||||||
inline QString openDB(QString repo){
|
inline QString openDB(QString repo){
|
||||||
//This ensures that each request for a database gets its own unique connection
|
//This ensures that each request for a database gets its own unique connection
|
||||||
// (preventing conflict between concurrent calls)
|
// (preventing conflict between concurrent calls)
|
||||||
QSqlDatabase DB = QSqlDatabase::addDatabase("QSQLITE", repo+QUuid::createUuid().toString());
|
QSqlDatabase DB = QSqlDatabase::addDatabase("QSQLITE", repo+QUuid::createUuid().toString());
|
||||||
DB.setConnectOptions("QSQLITE_OPEN_READONLY=1");
|
DB.setConnectOptions("QSQLITE_OPEN_READONLY=1");
|
||||||
DB.setHostName("localhost");
|
DB.setHostName("localhost");
|
||||||
QString path = getRepoFile(repo);
|
QString path = getRepoFile(repo);
|
||||||
DB.setDatabaseName(path); //path to the database file
|
DB.setDatabaseName(path); //path to the database file
|
||||||
@@ -100,15 +134,15 @@ QJsonObject PKG::pkg_info(QStringList origins, QString repo, QString category, b
|
|||||||
QJsonObject retObj;
|
QJsonObject retObj;
|
||||||
//if(origins.contains("math/R")){ qDebug() << "pkg_info:" << repo << category; }
|
//if(origins.contains("math/R")){ qDebug() << "pkg_info:" << repo << category; }
|
||||||
QString dbconn = openDB(repo);
|
QString dbconn = openDB(repo);
|
||||||
if(!dbconn.isEmpty()){
|
if(!dbconn.isEmpty()){
|
||||||
QSqlDatabase DB = QSqlDatabase::database(dbconn);
|
QSqlDatabase DB = QSqlDatabase::database(dbconn);
|
||||||
if(!DB.isOpen()){ return retObj; } //could not open DB (file missing?)
|
if(!DB.isOpen()){ return retObj; } //could not open DB (file missing?)
|
||||||
//Now do all the pkg info, one pkg origin at a time
|
//Now do all the pkg info, one pkg origin at a time
|
||||||
origins.removeAll("");
|
origins.removeAll("");
|
||||||
origins.removeDuplicates();
|
origins.removeDuplicates();
|
||||||
QString q_string = "SELECT * FROM packages";
|
QString q_string = "SELECT * FROM packages";
|
||||||
if(!origins.isEmpty()){
|
if(!origins.isEmpty()){
|
||||||
q_string.append(" WHERE origin IN ('"+origins.join("', '")+"')");
|
q_string.append(" WHERE name IN ('"+origins.join("', '")+"')");
|
||||||
//Also keep the ordering of the origins preserved
|
//Also keep the ordering of the origins preserved
|
||||||
/*q_string.append(" ORDER BY CASE origins ");
|
/*q_string.append(" ORDER BY CASE origins ");
|
||||||
for(int i=0; i<origins.length(); i++){ q_string.append("WHEN '"+origins[i]+"' THEN '"+QString::number(i+1)+"' "); }
|
for(int i=0; i<origins.length(); i++){ q_string.append("WHEN '"+origins[i]+"' THEN '"+QString::number(i+1)+"' "); }
|
||||||
@@ -119,13 +153,13 @@ QJsonObject PKG::pkg_info(QStringList origins, QString repo, QString category, b
|
|||||||
QSqlQuery query(q_string, DB);
|
QSqlQuery query(q_string, DB);
|
||||||
while(query.next()){
|
while(query.next()){
|
||||||
QString id = query.value("id").toString(); //need this pkg id for later
|
QString id = query.value("id").toString(); //need this pkg id for later
|
||||||
QString origin = query.value("origin").toString(); //need the origin for later
|
QString name = query.value("name").toString(); //need the origin for later
|
||||||
//if(origins.contains("math/R")){ qDebug() << "Found origin:" << origin << id; }
|
//if(origins.contains("math/R")){ qDebug() << "Found origin:" << origin << id; }
|
||||||
if(id.isEmpty() || origin.isEmpty()){ continue; }
|
if(id.isEmpty() || name.isEmpty()){ continue; }
|
||||||
QJsonObject info;
|
QJsonObject info;
|
||||||
//General info
|
//General info
|
||||||
for(int i=0; i<query.record().count(); i++){
|
for(int i=0; i<query.record().count(); i++){
|
||||||
info.insert(query.record().fieldName(i), query.value(i).toString() );
|
info.insert(query.record().fieldName(i), query.value(i).toString() );
|
||||||
}
|
}
|
||||||
//ANNOTATIONS
|
//ANNOTATIONS
|
||||||
QSqlQuery q2("SELECT tag_id, value_id FROM pkg_annotation WHERE package_id = '"+id+"'", DB);
|
QSqlQuery q2("SELECT tag_id, value_id FROM pkg_annotation WHERE package_id = '"+id+"'", DB);
|
||||||
@@ -134,7 +168,7 @@ QJsonObject PKG::pkg_info(QStringList origins, QString repo, QString category, b
|
|||||||
tags << q2.value("tag_id").toString(); vals << q2.value("value_id").toString();
|
tags << q2.value("tag_id").toString(); vals << q2.value("value_id").toString();
|
||||||
}
|
}
|
||||||
if(!tags.isEmpty()){ annotations_from_ids(tags, vals, &info, DB); }
|
if(!tags.isEmpty()){ annotations_from_ids(tags, vals, &info, DB); }
|
||||||
if(!fullresults){ retObj.insert(origin,info); continue; } //skip the rest of the info queries
|
if(!fullresults){ retObj.insert(name,info); continue; } //skip the rest of the info queries
|
||||||
//OPTIONS
|
//OPTIONS
|
||||||
QSqlQuery q3("SELECT value, option FROM pkg_option INNER JOIN option ON pkg_option.option_id = option.option_id WHERE pkg_option.package_id = '"+id+"'", DB);
|
QSqlQuery q3("SELECT value, option FROM pkg_option INNER JOIN option ON pkg_option.option_id = option.option_id WHERE pkg_option.package_id = '"+id+"'", DB);
|
||||||
QJsonObject options;
|
QJsonObject options;
|
||||||
@@ -144,22 +178,29 @@ QJsonObject PKG::pkg_info(QStringList origins, QString repo, QString category, b
|
|||||||
}
|
}
|
||||||
if(!options.isEmpty()){ info.insert("options",options); }
|
if(!options.isEmpty()){ info.insert("options",options); }
|
||||||
//DEPENDENCIES
|
//DEPENDENCIES
|
||||||
QSqlQuery q4("SELECT origin FROM deps WHERE package_id = '"+id+"'", DB);
|
QSqlQuery q4("SELECT origin, name FROM deps WHERE package_id = '"+id+"'", DB);
|
||||||
QStringList tmpList;
|
QStringList tmpList, tmpListN;
|
||||||
while(q4.next()){
|
while(q4.next()){
|
||||||
tmpList << q4.value("origin").toString();
|
tmpList << q4.value("origin").toString();
|
||||||
|
tmpListN << q4.value("name").toString();
|
||||||
} //end deps query
|
} //end deps query
|
||||||
if(!tmpList.isEmpty()){ info.insert("dependencies", QJsonArray::fromStringList(tmpList) ); }
|
if(!tmpList.isEmpty()){
|
||||||
|
//info.insert("dependencies_origins", QJsonArray::fromStringList(tmpList) );
|
||||||
|
info.insert("dependencies", QJsonArray::fromStringList(tmpListN) );
|
||||||
|
}
|
||||||
//FILES
|
//FILES
|
||||||
QSqlQuery q5("SELECT path FROM files WHERE package_id = '"+id+"'", DB);
|
QSqlQuery q5("SELECT path FROM files WHERE package_id = '"+id+"'", DB);
|
||||||
tmpList.clear();
|
tmpList.clear();
|
||||||
while(q5.next()){ tmpList << q5.value("path").toString(); }
|
while(q5.next()){ tmpList << q5.value("path").toString(); }
|
||||||
if(!tmpList.isEmpty()){ info.insert("files", QJsonArray::fromStringList(tmpList) ); }
|
if(!tmpList.isEmpty()){ info.insert("files", QJsonArray::fromStringList(tmpList) ); }
|
||||||
//REVERSE DEPENDENCIES
|
//REVERSE DEPENDENCIES
|
||||||
QSqlQuery q6("SELECT package_id FROM deps WHERE origin = '"+origin+"'", DB);
|
QSqlQuery q6("SELECT package_id FROM deps WHERE name = '"+name+"'", DB);
|
||||||
tmpList.clear();
|
tmpList.clear();
|
||||||
while(q6.next()){ tmpList << q6.value("package_id").toString(); }
|
while(q6.next()){ tmpList << q6.value("package_id").toString(); }
|
||||||
if(!tmpList.isEmpty()){ info.insert("reverse_dependencies", QJsonArray::fromStringList(origins_from_package_ids(tmpList, DB)) ); }
|
if(!tmpList.isEmpty()){
|
||||||
|
//info.insert("reverse_dependencies_origins", QJsonArray::fromStringList(origins_from_package_ids(tmpList, DB)) );
|
||||||
|
info.insert("reverse_dependencies", QJsonArray::fromStringList(names_from_ids(tmpList, "packages", DB)) );
|
||||||
|
}
|
||||||
//USERS
|
//USERS
|
||||||
QSqlQuery q7("SELECT user_id FROM pkg_users WHERE package_id = '"+id+"'", DB);
|
QSqlQuery q7("SELECT user_id FROM pkg_users WHERE package_id = '"+id+"'", DB);
|
||||||
tmpList.clear();
|
tmpList.clear();
|
||||||
@@ -204,9 +245,9 @@ QJsonObject PKG::pkg_info(QStringList origins, QString repo, QString category, b
|
|||||||
QSqlQuery q15("SELECT require_id FROM pkg_requires WHERE package_id = '"+id+"'", DB);
|
QSqlQuery q15("SELECT require_id FROM pkg_requires WHERE package_id = '"+id+"'", DB);
|
||||||
tmpList.clear();
|
tmpList.clear();
|
||||||
while(q15.next()){ tmpList << q15.value("require_id").toString(); }
|
while(q15.next()){ tmpList << q15.value("require_id").toString(); }
|
||||||
if(!tmpList.isEmpty()){ info.insert("requires", QJsonArray::fromStringList(requires_from_ids(tmpList, DB)) ); }
|
if(!tmpList.isEmpty()){ info.insert("requires", QJsonArray::fromStringList(requires_from_ids(tmpList, DB)) ); }\
|
||||||
//Now insert this information into the main object
|
//Now insert this information into the main object
|
||||||
retObj.insert(origin,info);
|
retObj.insert(name,info);
|
||||||
} //end loop over pkg matches
|
} //end loop over pkg matches
|
||||||
DB.close();
|
DB.close();
|
||||||
}//end if dbconn exists (force DB out of scope now)
|
}//end if dbconn exists (force DB out of scope now)
|
||||||
@@ -218,67 +259,67 @@ QJsonObject PKG::pkg_info(QStringList origins, QString repo, QString category, b
|
|||||||
QStringList PKG::pkg_search(QString repo, QString searchterm, QStringList searchexcludes, QString category){
|
QStringList PKG::pkg_search(QString repo, QString searchterm, QStringList searchexcludes, QString category){
|
||||||
QString dbconn = openDB(repo);
|
QString dbconn = openDB(repo);
|
||||||
QStringList found;
|
QStringList found;
|
||||||
if(!dbconn.isEmpty()){
|
if(!dbconn.isEmpty()){
|
||||||
QSqlDatabase DB = QSqlDatabase::database(dbconn);
|
QSqlDatabase DB = QSqlDatabase::database(dbconn);
|
||||||
if(!DB.isOpen()){ return QStringList(); } //could not open DB (file missing?)
|
if(!DB.isOpen()){ return QStringList(); } //could not open DB (file missing?)
|
||||||
|
|
||||||
QStringList terms = searchterm.split(" ",QString::SkipEmptyParts);
|
QStringList terms = searchterm.split(" ",QString::SkipEmptyParts);
|
||||||
searchexcludes.removeAll("");
|
searchexcludes.removeAll("");
|
||||||
QString q_string;
|
QString q_string;
|
||||||
int numtry = 0;
|
int numtry = 0;
|
||||||
while(found.isEmpty() && numtry<2){
|
while(found.isEmpty() && numtry<2){
|
||||||
if(numtry<1 && !searchterm.contains(" ")){ //single-word-search (exact names never have multiple words)
|
if(numtry<1 && !searchterm.contains(" ")){ //single-word-search (exact names never have multiple words)
|
||||||
q_string = "SELECT origin FROM packages WHERE name = '"+searchterm+"' OR origin LIKE '%/"+searchterm+"'";
|
q_string = "SELECT name FROM packages WHERE name = '"+searchterm+"' OR origin LIKE '%/"+searchterm+"'";
|
||||||
if(!category.isEmpty()){ q_string.append(" AND origin LIKE '"+category+"/%'"); }
|
if(!category.isEmpty()){ q_string.append(" AND origin LIKE '"+category+"/%'"); }
|
||||||
if(!searchexcludes.isEmpty()){ q_string.append(" AND name NOT LIKE '%"+searchexcludes.join("%' AND name NOT LIKE '%")+"%'"); }
|
if(!searchexcludes.isEmpty()){ q_string.append(" AND name NOT LIKE '%"+searchexcludes.join("%' AND name NOT LIKE '%")+"%'"); }
|
||||||
q_string.append(" COLLATE NOCASE"); // Case insensitive
|
q_string.append(" COLLATE NOCASE"); // Case insensitive
|
||||||
QSqlQuery query(q_string, DB);
|
QSqlQuery query(q_string, DB);
|
||||||
while(query.next()){
|
while(query.next()){
|
||||||
found << query.value("origin").toString(); //need the origin for later
|
found << query.value("name").toString(); //need the origin for later
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(found.length()<60 && numtry<1){
|
if(found.length()<60 && numtry<1){
|
||||||
//Expand the search to names containing the term
|
//Expand the search to names containing the term
|
||||||
q_string = "SELECT origin FROM packages WHERE name LIKE '"+searchterm+"%'";
|
q_string = "SELECT name FROM packages WHERE name LIKE '"+searchterm+"%'";
|
||||||
if(!category.isEmpty()){ q_string.append(" AND origin LIKE '"+category+"/%'"); }
|
if(!category.isEmpty()){ q_string.append(" AND origin LIKE '"+category+"/%'"); }
|
||||||
if(!searchexcludes.isEmpty()){ q_string.append(" AND name NOT LIKE '%"+searchexcludes.join("%' AND name NOT LIKE '%")+"%'"); }
|
if(!searchexcludes.isEmpty()){ q_string.append(" AND name NOT LIKE '%"+searchexcludes.join("%' AND name NOT LIKE '%")+"%'"); }
|
||||||
QSqlQuery q2(q_string, DB);
|
QSqlQuery q2(q_string, DB);
|
||||||
while(q2.next()){
|
while(q2.next()){
|
||||||
found << q2.value("origin").toString(); //need the origin for later
|
found << q2.value("name").toString(); //need the origin for later
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(found.length()<60 && numtry<1){
|
if(found.length()<60 && numtry<1){
|
||||||
//Expand the search to names containing the term
|
//Expand the search to names containing the term
|
||||||
q_string = "SELECT origin FROM packages WHERE name LIKE '%"+searchterm+"%'";
|
q_string = "SELECT name FROM packages WHERE name LIKE '%"+searchterm+"%'";
|
||||||
if(!category.isEmpty()){ q_string.append(" AND origin LIKE '"+category+"/%'"); }
|
if(!category.isEmpty()){ q_string.append(" AND origin LIKE '"+category+"/%'"); }
|
||||||
if(!searchexcludes.isEmpty()){ q_string.append(" AND name NOT LIKE '%"+searchexcludes.join("%' AND name NOT LIKE '%")+"%'"); }
|
if(!searchexcludes.isEmpty()){ q_string.append(" AND name NOT LIKE '%"+searchexcludes.join("%' AND name NOT LIKE '%")+"%'"); }
|
||||||
QSqlQuery q2(q_string, DB);
|
QSqlQuery q2(q_string, DB);
|
||||||
while(q2.next()){
|
while(q2.next()){
|
||||||
found << q2.value("origin").toString(); //need the origin for later
|
found << q2.value("name").toString(); //need the origin for later
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(found.length()<60){
|
if(found.length()<60){
|
||||||
//Expand the search to comments
|
//Expand the search to comments
|
||||||
if(terms.length()<2){ q_string = "SELECT origin FROM packages WHERE comment LIKE '%"+searchterm+"%'"; }
|
if(terms.length()<2){ q_string = "SELECT nameFROM packages WHERE comment LIKE '%"+searchterm+"%'"; }
|
||||||
else if(numtry==0){ q_string = "SELECT origin FROM packages WHERE comment LIKE '%"+terms.join("%' AND comment LIKE '%")+"%'"; }
|
else if(numtry==0){ q_string = "SELECT name FROM packages WHERE comment LIKE '%"+terms.join("%' AND comment LIKE '%")+"%'"; }
|
||||||
else if(numtry==1){ q_string = "SELECT origin FROM packages WHERE comment LIKE '%"+terms.join("%' OR comment LIKE '%")+"%'"; }
|
else if(numtry==1){ q_string = "SELECT name FROM packages WHERE comment LIKE '%"+terms.join("%' OR comment LIKE '%")+"%'"; }
|
||||||
if(!category.isEmpty()){ q_string.append(" AND origin LIKE '"+category+"/%'"); }
|
if(!category.isEmpty()){ q_string.append(" AND origin LIKE '"+category+"/%'"); }
|
||||||
if(!searchexcludes.isEmpty()){ q_string.append(" AND comment NOT LIKE '%"+searchexcludes.join("%' AND comment NOT LIKE '%")+"%'"); }
|
if(!searchexcludes.isEmpty()){ q_string.append(" AND comment NOT LIKE '%"+searchexcludes.join("%' AND comment NOT LIKE '%")+"%'"); }
|
||||||
QSqlQuery q2(q_string, DB);
|
QSqlQuery q2(q_string, DB);
|
||||||
while(q2.next()){
|
while(q2.next()){
|
||||||
found << q2.value("origin").toString(); //need the origin for later
|
found << q2.value("name").toString(); //need the origin for later
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(found.length()<100){
|
if(found.length()<100){
|
||||||
//Expand the search to full descriptions
|
//Expand the search to full descriptions
|
||||||
if(terms.length()<2){ q_string = "SELECT origin FROM packages WHERE desc LIKE '%"+searchterm+"%'"; }
|
if(terms.length()<2){ q_string = "SELECT name FROM packages WHERE desc LIKE '%"+searchterm+"%'"; }
|
||||||
else if(numtry==0){ q_string = "SELECT origin FROM packages WHERE desc LIKE '%"+terms.join("%' AND desc LIKE '%")+"%'"; }
|
else if(numtry==0){ q_string = "SELECT name FROM packages WHERE desc LIKE '%"+terms.join("%' AND desc LIKE '%")+"%'"; }
|
||||||
else if(numtry==1){ q_string = "SELECT origin FROM packages WHERE desc LIKE '%"+terms.join("%' OR desc LIKE '%")+"%'"; }
|
else if(numtry==1){ q_string = "SELECT name FROM packages WHERE desc LIKE '%"+terms.join("%' OR desc LIKE '%")+"%'"; }
|
||||||
if(!category.isEmpty()){ q_string.append(" AND origin LIKE '"+category+"/%'"); }
|
if(!category.isEmpty()){ q_string.append(" AND origin LIKE '"+category+"/%'"); }
|
||||||
if(!searchexcludes.isEmpty()){ q_string.append(" AND desc NOT LIKE '%"+searchexcludes.join("%' AND desc NOT LIKE '%")+"%'"); }
|
if(!searchexcludes.isEmpty()){ q_string.append(" AND desc NOT LIKE '%"+searchexcludes.join("%' AND desc NOT LIKE '%")+"%'"); }
|
||||||
QSqlQuery q2(q_string, DB);
|
QSqlQuery q2(q_string, DB);
|
||||||
while(q2.next()){
|
while(q2.next()){
|
||||||
found << q2.value("origin").toString(); //need the origin for later
|
found << q2.value("name").toString(); //need the origin for later
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Now bump the try count
|
//Now bump the try count
|
||||||
@@ -297,7 +338,7 @@ while(found.isEmpty() && numtry<2){
|
|||||||
QJsonArray PKG::list_categories(QString repo){
|
QJsonArray PKG::list_categories(QString repo){
|
||||||
QString dbconn = openDB(repo);
|
QString dbconn = openDB(repo);
|
||||||
QStringList found;
|
QStringList found;
|
||||||
if(!dbconn.isEmpty()){
|
if(!dbconn.isEmpty()){
|
||||||
QSqlDatabase DB = QSqlDatabase::database(dbconn);
|
QSqlDatabase DB = QSqlDatabase::database(dbconn);
|
||||||
if(!DB.isOpen()){ return QJsonArray(); } //could not open DB (file missing?)
|
if(!DB.isOpen()){ return QJsonArray(); } //could not open DB (file missing?)
|
||||||
|
|
||||||
@@ -313,7 +354,7 @@ QJsonArray PKG::list_categories(QString repo){
|
|||||||
while(query.next()){
|
while(query.next()){
|
||||||
found << query.value("name").toString(); //need the origin for later
|
found << query.value("name").toString(); //need the origin for later
|
||||||
}
|
}
|
||||||
|
|
||||||
//Now check all the categories to ensure that pkgs exist within it
|
//Now check all the categories to ensure that pkgs exist within it
|
||||||
for(int i=0; i<found.length(); i++){
|
for(int i=0; i<found.length(); i++){
|
||||||
if(origins.filter(found[i]+"/").isEmpty()){ found.removeAt(i); i--; }
|
if(origins.filter(found[i]+"/").isEmpty()){ found.removeAt(i); i--; }
|
||||||
@@ -330,25 +371,114 @@ QJsonArray PKG::list_categories(QString repo){
|
|||||||
|
|
||||||
QJsonArray PKG::list_repos(bool updated){
|
QJsonArray PKG::list_repos(bool updated){
|
||||||
QString dbdir = "/var/db/pkg/repo-%1.sqlite";
|
QString dbdir = "/var/db/pkg/repo-%1.sqlite";
|
||||||
QDir confdir("/usr/local/etc/pkg/repos");
|
QStringList repodirs; repodirs << "/etc/pkg" << "/etc/pkg/repos" << "/usr/local/etc/pkg" << "/usr/local/etc/pkg/repos";
|
||||||
QStringList confs = confdir.entryList(QStringList() << "*.conf", QDir::Files);
|
|
||||||
QStringList found;
|
QStringList found;
|
||||||
found << "local"; //There is always a local database (for installed pkgs)
|
found << "local"; //There is always a local database (for installed pkgs)
|
||||||
for(int i=0; i<confs.length(); i++){
|
for(int d=0; d<repodirs.length(); d++){
|
||||||
QStringList repoinfo = General::readTextFile(confdir.absoluteFilePath(confs[i])).join("\n").split("}");
|
if(!QFile::exists(repodirs[d])){ continue; }
|
||||||
for(int j=0; j<repoinfo.length(); j++){
|
QDir confdir(repodirs[d]);
|
||||||
QString repo = repoinfo[j].section(":",0,0).simplified();
|
QStringList confs = confdir.entryList(QStringList() << "*.conf", QDir::Files);
|
||||||
if(QFile::exists(dbdir.arg(repo)) && repoinfo[j].section("enabled:",1,-1).section(":",0,0).contains("true")){ found << repo; }
|
for(int i=0; i<confs.length(); i++){
|
||||||
}
|
QStringList contents = General::readTextFile(confdir.absoluteFilePath(confs[i]));
|
||||||
}
|
//Scan for any comments on the top of the file and remove them
|
||||||
|
for(int l=0; l<contents.length(); l++){
|
||||||
|
if(contents[l].isEmpty() || contents[l].startsWith("#")){ contents.removeAt(l); l--; }
|
||||||
|
else{ break; }
|
||||||
|
}
|
||||||
|
QStringList repoinfo = contents.join("\n").split("\n}");
|
||||||
|
for(int j=0; j<repoinfo.length(); j++){
|
||||||
|
qDebug() << "Repoinfo:" << repoinfo[j];
|
||||||
|
QString repo = repoinfo[j].section(":",0,0).simplified();
|
||||||
|
QString enabled = repoinfo[j].section("enabled:",1,-1).section(":",0,0).toLower();
|
||||||
|
bool isEnabled = true;
|
||||||
|
if(enabled.contains("no") || enabled.contains("false")){ isEnabled = false; }
|
||||||
|
qDebug() << "Checking Repo:" << repo << enabled << isEnabled;
|
||||||
|
if(QFile::exists(dbdir.arg(repo)) && isEnabled){ found << repo; }
|
||||||
|
} //loop over repos listed in conf
|
||||||
|
} //loop over confs in repodir
|
||||||
|
} //loop over repodirs
|
||||||
if(found.length()<2 && !updated){
|
if(found.length()<2 && !updated){
|
||||||
//Only the local repo could be found - update the package repos and try again
|
//Only the local repo could be found - update the package repos and try again
|
||||||
QProcess::execute("pkg update");
|
DProcess* proc = DISPATCHER->queueProcess(Dispatcher::PKG_QUEUE, "internal_sysadm_pkg_repo_update_sync", "pkg update");
|
||||||
|
proc->waitForFinished();
|
||||||
return list_repos(true); //try again recursively (will not try to update again)
|
return list_repos(true); //try again recursively (will not try to update again)
|
||||||
}
|
}
|
||||||
return QJsonArray::fromStringList(found);
|
return QJsonArray::fromStringList(found);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QJsonObject PKG::evaluateInstall(QStringList origins, QString repo){
|
||||||
|
//qDebug() << "Verify Install:" << origins << repo;
|
||||||
|
QJsonObject out;
|
||||||
|
out.insert("install_origins", QJsonArray::fromStringList(origins) );
|
||||||
|
out.insert("repo", repo);
|
||||||
|
if(repo=="local" || origins.isEmpty()){ return out; } //nothing to do
|
||||||
|
QString dbconn = openDB(repo);
|
||||||
|
QString ldbconn = openDB("local");
|
||||||
|
if(!dbconn.isEmpty()){
|
||||||
|
QSqlDatabase DB = QSqlDatabase::database(dbconn);
|
||||||
|
QSqlDatabase LDB = QSqlDatabase::database(ldbconn);
|
||||||
|
if(!DB.isOpen() || !LDB.isOpen()){ return out; } //could not open DB (file missing?)
|
||||||
|
|
||||||
|
//First get the list of all packages which need to be installed (ID's) from the remote database
|
||||||
|
QStringList toInstall_id;
|
||||||
|
QStringList tmp;
|
||||||
|
if(origins.first().contains("/")){ tmp = names_from_ids( ids_from_origins(origins, DB), "packages", DB); }
|
||||||
|
else{ tmp = origins; } //already given names
|
||||||
|
//qDebug() << " - Initial names:" << tmp;
|
||||||
|
while(!tmp.isEmpty()){
|
||||||
|
QStringList ids = ids_from_names(tmp, DB);
|
||||||
|
for(int i=0; i<ids.length(); i++){
|
||||||
|
if(toInstall_id.contains(ids[i])){ ids.removeAt(i); i--; } //remove any duplicate/evaluated ID's
|
||||||
|
}
|
||||||
|
if(ids.isEmpty()){ break; } //stop the loop - found the last round of dependencies
|
||||||
|
toInstall_id << ids; //add these to the list which are going to get installed
|
||||||
|
tmp = depends_from_ids(ids, DB); //now get the depdendencies of these packages
|
||||||
|
//qDebug() << " - Iteration names:" << tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Now go through and remove any packages from the list which are already installed locally
|
||||||
|
QStringList names = names_from_ids(toInstall_id, "packages", DB); //same order
|
||||||
|
//qDebug() << " - Total Names:" << names;
|
||||||
|
QStringList local_names = names_from_ids( ids_from_names(names, LDB), "packages", LDB);
|
||||||
|
//qDebug() << " - Local Names:" << local_names;
|
||||||
|
for(int i=0; i<local_names.length(); i++){
|
||||||
|
names.removeAll(local_names[i]);
|
||||||
|
}
|
||||||
|
//qDebug() << " - Filtered Names:" << names;
|
||||||
|
toInstall_id = ids_from_names(names, DB); //now get the shorter/filtered list of ID's (remote)
|
||||||
|
//qDebug() << " - Filtered ID's:" << toInstall_id;
|
||||||
|
//Get the list of conflicting packages which are already installed
|
||||||
|
QStringList conflict_ids = conflicts_from_ids(toInstall_id, DB); //also get the list of any conflicts for these packages
|
||||||
|
conflict_ids.removeDuplicates();
|
||||||
|
QStringList conflict_names = names_from_ids(conflict_ids, "packages", DB);
|
||||||
|
//qDebug() << " - Conflicts (remote):" << conflict_ids << conflict_names;
|
||||||
|
out.insert("conflicts", QJsonArray::fromStringList(names_from_ids( ids_from_names(conflict_names, LDB), "packages", LDB) ) );
|
||||||
|
//Now assemble all the information about the packages (remote database)
|
||||||
|
QJsonObject install;
|
||||||
|
//qDebug() << "Perform Query";
|
||||||
|
QSqlQuery qi("SELECT * FROM packages WHERE id IN ('"+toInstall_id.join("', '")+"')", DB);
|
||||||
|
while(qi.next()){
|
||||||
|
QJsonObject obj;
|
||||||
|
obj.insert( "name", qi.value("name").toString());
|
||||||
|
obj.insert( "origin", qi.value("origin").toString());
|
||||||
|
obj.insert( "pkgsize", qi.value("pkgsize").toString());
|
||||||
|
obj.insert( "flatsize", qi.value("flatsize").toString());
|
||||||
|
obj.insert( "version", qi.value("version").toString());
|
||||||
|
obj.insert( "comment", qi.value("comment").toString());
|
||||||
|
install.insert(qi.value("name").toString(), obj);
|
||||||
|
}
|
||||||
|
//qDebug() << "Final Install Object:" << install;
|
||||||
|
//qDebug() << "Last Query Error:" << qi.lastError().text();
|
||||||
|
//Add the info to the output object and close the databases
|
||||||
|
out.insert("install", install);
|
||||||
|
DB.close();
|
||||||
|
LDB.close();
|
||||||
|
} //force DB out of scope
|
||||||
|
QSqlDatabase::removeDatabase(dbconn);
|
||||||
|
QSqlDatabase::removeDatabase(ldbconn);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
//=================
|
//=================
|
||||||
//pkg modification routines (dispatcher events for notifications)
|
//pkg modification routines (dispatcher events for notifications)
|
||||||
//=================
|
//=================
|
||||||
@@ -381,7 +511,7 @@ QJsonObject PKG::pkg_remove(QStringList origins, bool recursive){
|
|||||||
obj.insert("status", "pending");
|
obj.insert("status", "pending");
|
||||||
obj.insert("proc_cmd",cmd);
|
obj.insert("proc_cmd",cmd);
|
||||||
obj.insert("proc_id",ID);
|
obj.insert("proc_id",ID);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject PKG::pkg_lock(QStringList origins){
|
QJsonObject PKG::pkg_lock(QStringList origins){
|
||||||
@@ -396,7 +526,7 @@ QJsonObject PKG::pkg_lock(QStringList origins){
|
|||||||
obj.insert("status", "pending");
|
obj.insert("status", "pending");
|
||||||
obj.insert("proc_cmd",cmd);
|
obj.insert("proc_cmd",cmd);
|
||||||
obj.insert("proc_id",ID);
|
obj.insert("proc_id",ID);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject PKG::pkg_unlock(QStringList origins){
|
QJsonObject PKG::pkg_unlock(QStringList origins){
|
||||||
@@ -411,7 +541,7 @@ QJsonObject PKG::pkg_unlock(QStringList origins){
|
|||||||
obj.insert("status", "pending");
|
obj.insert("status", "pending");
|
||||||
obj.insert("proc_cmd",cmd);
|
obj.insert("proc_cmd",cmd);
|
||||||
obj.insert("proc_id",ID);
|
obj.insert("proc_id",ID);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================
|
//==================
|
||||||
@@ -429,7 +559,7 @@ QJsonObject PKG::pkg_update(bool force){
|
|||||||
obj.insert("status", "pending");
|
obj.insert("status", "pending");
|
||||||
obj.insert("proc_cmd",cmd);
|
obj.insert("proc_cmd",cmd);
|
||||||
obj.insert("proc_id",ID);
|
obj.insert("proc_id",ID);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject PKG::pkg_check_upgrade(){
|
QJsonObject PKG::pkg_check_upgrade(){
|
||||||
@@ -443,7 +573,7 @@ QJsonObject PKG::pkg_check_upgrade(){
|
|||||||
obj.insert("status", "pending");
|
obj.insert("status", "pending");
|
||||||
obj.insert("proc_cmd",cmd);
|
obj.insert("proc_cmd",cmd);
|
||||||
obj.insert("proc_id",ID);
|
obj.insert("proc_id",ID);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject PKG::pkg_upgrade(){
|
QJsonObject PKG::pkg_upgrade(){
|
||||||
@@ -471,7 +601,7 @@ QJsonObject PKG::pkg_audit(){
|
|||||||
obj.insert("status", "pending");
|
obj.insert("status", "pending");
|
||||||
obj.insert("proc_cmd",cmd);
|
obj.insert("proc_cmd",cmd);
|
||||||
obj.insert("proc_id",ID);
|
obj.insert("proc_id",ID);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject PKG::pkg_autoremove(){
|
QJsonObject PKG::pkg_autoremove(){
|
||||||
@@ -485,5 +615,5 @@ QJsonObject PKG::pkg_autoremove(){
|
|||||||
obj.insert("status", "pending");
|
obj.insert("status", "pending");
|
||||||
obj.insert("proc_cmd",cmd);
|
obj.insert("proc_cmd",cmd);
|
||||||
obj.insert("proc_id",ID);
|
obj.insert("proc_id",ID);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ public:
|
|||||||
static QStringList pkg_search(QString repo, QString searchterm, QStringList searchexcludes, QString category = "");
|
static QStringList pkg_search(QString repo, QString searchterm, QStringList searchexcludes, QString category = "");
|
||||||
static QJsonArray list_categories(QString repo);
|
static QJsonArray list_categories(QString repo);
|
||||||
static QJsonArray list_repos(bool updated = false);
|
static QJsonArray list_repos(bool updated = false);
|
||||||
|
static QJsonObject evaluateInstall(QStringList origins, QString repo); //evaluate what will be done if these packages are installed
|
||||||
|
|
||||||
|
|
||||||
//pkg modification routines (dispatcher events for notifications)
|
//pkg modification routines (dispatcher events for notifications)
|
||||||
static QJsonObject pkg_install(QStringList origins, QString repo);
|
static QJsonObject pkg_install(QStringList origins, QString repo);
|
||||||
@@ -37,9 +39,9 @@ public:
|
|||||||
static QJsonObject pkg_upgrade(); //upgrade all pkgs (use sysadm/updates if possible instead)
|
static QJsonObject pkg_upgrade(); //upgrade all pkgs (use sysadm/updates if possible instead)
|
||||||
static QJsonObject pkg_audit(); //List details of vulnerable packages
|
static QJsonObject pkg_audit(); //List details of vulnerable packages
|
||||||
static QJsonObject pkg_autoremove(); //Autoremove orphaned packages
|
static QJsonObject pkg_autoremove(); //Autoremove orphaned packages
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} //end of sysadm namespace
|
} //end of sysadm namespace
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ ServiceManager::ServiceManager(QString chroot, QString ip)
|
|||||||
{
|
{
|
||||||
this->chroot = chroot;
|
this->chroot = chroot;
|
||||||
this->ip = ip;
|
this->ip = ip;
|
||||||
loadRCdata();
|
usingOpenRC = QFile::exists(chroot+"/sbin/rc-update");
|
||||||
|
loadRCdata();
|
||||||
//loadServices();
|
//loadServices();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,14 +76,14 @@ bool ServiceManager::Start(Service service)
|
|||||||
// Start the process
|
// Start the process
|
||||||
QString prog;
|
QString prog;
|
||||||
QStringList args;
|
QStringList args;
|
||||||
bool once = !isEnabled(service);
|
bool once = !isEnabled(service) && !usingOpenRC;
|
||||||
if ( chroot.isEmpty() ) {
|
if ( chroot.isEmpty() ) {
|
||||||
prog = "service";
|
prog = "service";
|
||||||
args << service.Directory;
|
args << service.Directory;
|
||||||
args << "start";
|
args << (once ? "onestart" : "start") ;
|
||||||
} else {
|
} else {
|
||||||
prog = "warden";
|
prog = "warden";
|
||||||
args << "chroot" << ip << "service" << service.Directory << (once ? "one" : "" )+QString("start");
|
args << "chroot" << ip << "service" << service.Directory << (once ? "onestart" : "start" );
|
||||||
}
|
}
|
||||||
return General::RunQuickCommand(prog,args);
|
return General::RunQuickCommand(prog,args);
|
||||||
}
|
}
|
||||||
@@ -94,14 +95,14 @@ bool ServiceManager::Stop(Service service)
|
|||||||
// Start the process
|
// Start the process
|
||||||
QString prog;
|
QString prog;
|
||||||
QStringList args;
|
QStringList args;
|
||||||
bool once = !isEnabled(service);
|
bool once = !isEnabled(service) && !usingOpenRC;
|
||||||
if ( chroot.isEmpty() ) {
|
if ( chroot.isEmpty() ) {
|
||||||
prog = "service";
|
prog = "service";
|
||||||
args << service.Directory;
|
args << service.Directory;
|
||||||
args << "stop";
|
args << (once ? "onestop" : "stop") ;
|
||||||
} else {
|
} else {
|
||||||
prog = "warden";
|
prog = "warden";
|
||||||
args << "chroot" << ip << "service" << service.Directory << (once ? "one" : "" )+QString("stop");
|
args << "chroot" << ip << "service" << service.Directory << (once ? "onestop" : "stop" );
|
||||||
}
|
}
|
||||||
return General::RunQuickCommand(prog,args);
|
return General::RunQuickCommand(prog,args);
|
||||||
}
|
}
|
||||||
@@ -111,7 +112,7 @@ bool ServiceManager::Restart(Service service)
|
|||||||
if(service.Directory.isEmpty()){ return false; }
|
if(service.Directory.isEmpty()){ return false; }
|
||||||
QString prog;
|
QString prog;
|
||||||
QStringList args;
|
QStringList args;
|
||||||
bool once = !isEnabled(service);
|
bool once = !isEnabled(service) && !usingOpenRC;
|
||||||
if ( chroot.isEmpty() ) {
|
if ( chroot.isEmpty() ) {
|
||||||
prog = "service";
|
prog = "service";
|
||||||
args << service.Directory;
|
args << service.Directory;
|
||||||
@@ -152,7 +153,13 @@ Service ServiceManager::loadServices(QString name)
|
|||||||
|
|
||||||
// OpenRC directories are /etc/init.d and /usr/local/etc/init.d
|
// OpenRC directories are /etc/init.d and /usr/local/etc/init.d
|
||||||
QStringList stringDirs;
|
QStringList stringDirs;
|
||||||
stringDirs << chroot + "/etc/init.d" << chroot + "/usr/local/etc/init.d";
|
if(usingOpenRC){
|
||||||
|
//OpenRC
|
||||||
|
stringDirs << chroot + "/etc/init.d" << chroot + "/usr/local/etc/init.d";
|
||||||
|
}else{
|
||||||
|
//FreeBSD rc.d
|
||||||
|
stringDirs << chroot + "/etc/rc.d" << chroot + "/usr/local/etc/rc.d";
|
||||||
|
}
|
||||||
|
|
||||||
for ( QString dir: stringDirs)
|
for ( QString dir: stringDirs)
|
||||||
{
|
{
|
||||||
@@ -186,7 +193,7 @@ Service ServiceManager::loadServices(QString name)
|
|||||||
|
|
||||||
if (line.simplified().startsWith("description=") ||
|
if (line.simplified().startsWith("description=") ||
|
||||||
line.simplified().startsWith("desc=") ||
|
line.simplified().startsWith("desc=") ||
|
||||||
line.simplified().startsWith("name=")) {
|
(line.simplified().startsWith("name=") && service.Description.isEmpty()) ) {
|
||||||
service.Description = line.section("=\"",1,-1).section("\"",0,0);
|
service.Description = line.section("=\"",1,-1).section("\"",0,0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,6 +252,7 @@ void ServiceManager::loadUnusedData() {
|
|||||||
|
|
||||||
// get the services enabled for all runlevels so we can update services
|
// get the services enabled for all runlevels so we can update services
|
||||||
void ServiceManager::loadRunlevels() {
|
void ServiceManager::loadRunlevels() {
|
||||||
|
if(!usingOpenRC){ return; }
|
||||||
QStringList info = sysadm::General::RunCommand("rc-status --nocolor --all").split("\n");
|
QStringList info = sysadm::General::RunCommand("rc-status --nocolor --all").split("\n");
|
||||||
QString runlevel = "default";
|
QString runlevel = "default";
|
||||||
for (int i=0; i<info.length(); i++) {
|
for (int i=0; i<info.length(); i++) {
|
||||||
@@ -264,19 +272,17 @@ void ServiceManager::loadRunlevels() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ServiceManager::enableDisableService(QString name, bool enable) {
|
bool ServiceManager::enableDisableService(QString name, bool enable) {
|
||||||
QString runlevel = "default";
|
|
||||||
// look in services for name, see if there is a runlevel set
|
|
||||||
// if not, use default
|
// if not, use default
|
||||||
QString prog = "rc-update";
|
QString prog = usingOpenRC ? "rc-update" : "sysrc";
|
||||||
QStringList args;
|
QStringList args;
|
||||||
if (enable)
|
if(usingOpenRC){
|
||||||
args << "add";
|
if (enable){ args << "add"; }
|
||||||
else
|
else{ args << "delete"; }
|
||||||
args << "delete";
|
args << name;
|
||||||
|
}else{
|
||||||
args << name;
|
args << name+"_enable=\""+ (enable ? "YES" : "NO") + "\"";
|
||||||
args << runlevel;
|
}
|
||||||
qDebug() << prog << " " << args;
|
//qDebug() << prog << " " << args;
|
||||||
bool ret = sysadm::General::RunQuickCommand(prog,args);
|
bool ret = sysadm::General::RunQuickCommand(prog,args);
|
||||||
loadUnusedData();
|
loadUnusedData();
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -92,9 +92,10 @@ private:
|
|||||||
void loadRunlevels();
|
void loadRunlevels();
|
||||||
|
|
||||||
bool enableDisableService(QString name, bool enable=false);
|
bool enableDisableService(QString name, bool enable=false);
|
||||||
|
|
||||||
QString chroot;
|
QString chroot;
|
||||||
QString ip;
|
QString ip;
|
||||||
|
bool usingOpenRC;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif // SERVICEMANAGER_H
|
#endif // SERVICEMANAGER_H
|
||||||
|
|||||||
209
src/server/library/sysadm-sourcectl.cpp
Normal file
209
src/server/library/sysadm-sourcectl.cpp
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
//===========================================
|
||||||
|
// TrueOS source code
|
||||||
|
// Copyright (c) 2017, JT (q5sys)
|
||||||
|
// Available under the 3-clause BSD license
|
||||||
|
// See the LICENSE file for full details
|
||||||
|
//===========================================
|
||||||
|
#include "sysadm-general.h"
|
||||||
|
#include "sysadm-sourcectl.h"
|
||||||
|
#include "sysadm-global.h"
|
||||||
|
#include "globals.h"
|
||||||
|
|
||||||
|
#include <QUuid>
|
||||||
|
#include "sysadm-general.h"
|
||||||
|
#include "sysadm-update.h"
|
||||||
|
#include "sysadm-global.h"
|
||||||
|
#include "globals.h"
|
||||||
|
|
||||||
|
using namespace sysadm;
|
||||||
|
|
||||||
|
// ==================
|
||||||
|
// INLINE FUNCTIONS
|
||||||
|
// ==================
|
||||||
|
|
||||||
|
// =================
|
||||||
|
// MAIN FUNCTIONS
|
||||||
|
// =================
|
||||||
|
|
||||||
|
QJsonObject sourcectl::downloadsource(){
|
||||||
|
// cmd that will be run = git clone https://github.com/trueos/freebsd.git /usr/src
|
||||||
|
QJsonObject retObject;
|
||||||
|
QString ID = QUuid::createUuid().toString(); // Create a unique ID for this queued action
|
||||||
|
// Queue the update action
|
||||||
|
QString cmd;
|
||||||
|
cmd = "git clone https://github.com/trueos/freebsd.git /usr/src";
|
||||||
|
DISPATCHER->queueProcess("sysadm_sourcectl_downloadsource::"+ID, cmd);
|
||||||
|
|
||||||
|
// Return some details to user that the action was queued
|
||||||
|
retObject.insert("command", "Downloading TrueOS Source Tree");
|
||||||
|
retObject.insert("comment", "Task Queued");
|
||||||
|
retObject.insert("queueid", ID);
|
||||||
|
return retObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject sourcectl::updatesource(){
|
||||||
|
// cmd that will be run = git reset --hard && git pull
|
||||||
|
QJsonObject retObject;
|
||||||
|
QString ID = QUuid::createUuid().toString(); // Create a unique ID for this queued action
|
||||||
|
// Queue the update action
|
||||||
|
QStringList cmds;
|
||||||
|
cmds << "git reset --hard" << "git pull";
|
||||||
|
DISPATCHER->queueProcess("sysadm_sourcectl_updatesource::"+ID, cmds, "/usr/src/");
|
||||||
|
|
||||||
|
// Return some details to user that the action was queued
|
||||||
|
retObject.insert("command", "Updating TrueOS Source Tree");
|
||||||
|
retObject.insert("comment", "Task Queued");
|
||||||
|
retObject.insert("queueid", ID);
|
||||||
|
return retObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject sourcectl::deletesource(){
|
||||||
|
// cmd that will be run = rm -rf /usr/src/
|
||||||
|
QJsonObject retObject;
|
||||||
|
QString ID = QUuid::createUuid().toString(); // Create a unique ID for this queued action
|
||||||
|
// Queue the update action
|
||||||
|
QString cmd;
|
||||||
|
cmd = "rm -rf /usr/src/";
|
||||||
|
DISPATCHER->queueProcess("sysadm_sourcectl_deletesource::"+ID, cmd);
|
||||||
|
|
||||||
|
// Return some details to user that the action was queued
|
||||||
|
retObject.insert("command", "Deleting TrueOS Source Tree");
|
||||||
|
retObject.insert("comment", "Task Queued");
|
||||||
|
retObject.insert("queueid", ID);
|
||||||
|
return retObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject sourcectl::stopsource(){}
|
||||||
|
|
||||||
|
QJsonObject sourcectl::downloadports(){
|
||||||
|
// cmd that will be run = git clone https://github.com/trueos/freebsd-ports.git /usr/ports
|
||||||
|
QJsonObject retObject;
|
||||||
|
QString ID = QUuid::createUuid().toString(); // Create a unique ID for this queued action
|
||||||
|
// Queue the update action
|
||||||
|
QString cmd;
|
||||||
|
cmd = "git clone https://github.com/trueos/freebsd-ports.git /usr/ports";
|
||||||
|
DISPATCHER->queueProcess("sysadm_sourcectl_downloadports::"+ID, cmd);
|
||||||
|
|
||||||
|
// Return some details to user that the action was queued
|
||||||
|
retObject.insert("command", "Downloading TrueOS PortsTree");
|
||||||
|
retObject.insert("comment", "Task Queued");
|
||||||
|
retObject.insert("queueid", ID);
|
||||||
|
return retObject;
|
||||||
|
}
|
||||||
|
QJsonObject sourcectl::updateports(){
|
||||||
|
// cmd that will be run = git reset --hard && git pull
|
||||||
|
QJsonObject retObject;
|
||||||
|
QString ID = QUuid::createUuid().toString(); // Create a unique ID for this queued action
|
||||||
|
// Queue the update action
|
||||||
|
QStringList cmds;
|
||||||
|
cmds << "git reset --hard" << "git pull";
|
||||||
|
DISPATCHER->queueProcess("sysadm_sourcectl_updateports::"+ID, cmds, "/usr/ports/");
|
||||||
|
|
||||||
|
// Return some details to user that the action was queued
|
||||||
|
retObject.insert("command", "Updating TrueOS PortsTree");
|
||||||
|
retObject.insert("comment", "Task Queued");
|
||||||
|
retObject.insert("queueid", ID);
|
||||||
|
return retObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QJsonObject sourcectl::deleteports(){
|
||||||
|
// cmd that will be run = rm -rf /usr/ports/
|
||||||
|
QJsonObject retObject;
|
||||||
|
QString ID = QUuid::createUuid().toString(); // Create a unique ID for this queued action
|
||||||
|
// Queue the update action
|
||||||
|
QString cmd;
|
||||||
|
cmd = "rm -rf /usr/ports/";
|
||||||
|
DISPATCHER->queueProcess("sysadm_sourcectl_deleteports::"+ID, cmd);
|
||||||
|
|
||||||
|
// Return some details to user that the action was queued
|
||||||
|
retObject.insert("command", "Deleting TrueOS PortsTree");
|
||||||
|
retObject.insert("comment", "Task Queued");
|
||||||
|
retObject.insert("queueid", ID);
|
||||||
|
return retObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject sourcectl::stopports(){}
|
||||||
|
|
||||||
|
|
||||||
|
void sourcectl::saveSourceLog(QString){}
|
||||||
|
void sourcectl::savePortsLog(QString){}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
git clone https://github.com/trueos/freebsd.git /usr/src
|
||||||
|
git clone https://github.com/trueos/freebsd-ports.git /usr/ports
|
||||||
|
|
||||||
|
git reset --hard && git pull
|
||||||
|
|
||||||
|
|
||||||
|
rm -rf /usr/src/
|
||||||
|
rm -rf /usr/ports/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
QJsonObject SysMgmt::fetchPortsTree(QString altDir){
|
||||||
|
//void SysMgmt::fetchPortsTree(QStringList &cmds, QStringList &dirs){
|
||||||
|
QJsonObject out;
|
||||||
|
if(altDir.isEmpty()){ altDir = "/usr/ports"; }
|
||||||
|
//Does Ports tree exist? If not create it.
|
||||||
|
if(!QFile::exists(altDir)){
|
||||||
|
QDir dir;
|
||||||
|
if(!dir.mkpath(altDir) ){
|
||||||
|
out.insert("error","Could not create directory: "+altDir);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Does a local git repo exist? If not create it.
|
||||||
|
QString URL = "https://www.github.com/trueos/freebsd-ports.git";
|
||||||
|
if(QFile::exists(altDir+"/.git")){
|
||||||
|
//Check if the remote URL is correct
|
||||||
|
QString origin = General::gitCMD(altDir, "git remote show -n origin").filter("Fetch URL:").join("").section("URL:",1,30).simplified();
|
||||||
|
if(origin != URL){
|
||||||
|
General::gitCMD(altDir,"git",QStringList() << "remote" << "remove" << "origin");
|
||||||
|
General::gitCMD(altDir,"git", QStringList() << "remote" << "add" << "origin" << URL);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
//new GIT setup
|
||||||
|
General::emptyDir(altDir);
|
||||||
|
General::gitCMD(altDir, "git", QStringList() << "init" << altDir );
|
||||||
|
General::gitCMD(altDir, "git", QStringList() << "remote" << "add" << "origin" << URL );
|
||||||
|
}
|
||||||
|
//Now update the tree with git
|
||||||
|
QString ID = "system_fetch_ports_tree";
|
||||||
|
DISPATCHER->queueProcess(ID, "git pull origin", altDir );
|
||||||
|
out.insert("result","process_started");
|
||||||
|
out.insert("process_id",ID);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*void SysMgmt::fetchSourceTree(QString branch, QStringList &cmds, QStringList &dirs, QStringList &info){
|
||||||
|
//Clear the output variables
|
||||||
|
cmds.clear(); dirs.clear();
|
||||||
|
//Check if the source directory even exists
|
||||||
|
if(!QFile::exists("/usr/src")){
|
||||||
|
cmds << "mkdir /usr/src"; dirs << ""; //Create the ports tree
|
||||||
|
}
|
||||||
|
//Now check if the git directory exists
|
||||||
|
QString URL = "https://www.github.com/pcbsd/freebsd.git";
|
||||||
|
if(QFile::exists("/usr/src/.git")){
|
||||||
|
//Check if the remote URL is correct
|
||||||
|
QString origin = General::gitCMD("/usr/src", "git remote show -n origin").filter("Fetch URL:").join("").section("URL:",1,30).simplified();
|
||||||
|
if(origin != URL){
|
||||||
|
cmds << "git remote remove origin"; dirs <<"/usr/src";
|
||||||
|
cmds << "git remote add origin "+URL; dirs << "/usr/src/.git"; //setup PC-BSD git repo
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
//new GIT setup
|
||||||
|
General::emptyDir("/usr/src");
|
||||||
|
cmds << "git init"; dirs << "/usr/src"; //setup git
|
||||||
|
cmds << "git remote add origin "+URL; dirs << "/usr/src/.git"; //setup PC-BSD git repo
|
||||||
|
}
|
||||||
|
//Now update the tree with git
|
||||||
|
cmds << "git fetch --depth=1"; dirs << "/usr/src/.git";
|
||||||
|
cmds << "git checkout "+branch; dirs << "/usr/src";
|
||||||
|
}
|
||||||
|
*/
|
||||||
34
src/server/library/sysadm-sourcectl.h
Normal file
34
src/server/library/sysadm-sourcectl.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
//===========================================
|
||||||
|
// TrueOS source code
|
||||||
|
// Copyright (c) 2017, JT (q5sys)
|
||||||
|
// Available under the 3-clause BSD license
|
||||||
|
// See the LICENSE file for full details
|
||||||
|
//===========================================
|
||||||
|
#ifndef __PCBSD_LIB_UTILS_SOURCECTL_H
|
||||||
|
#define __PCBSD_LIB_UTILS_SOURCECTL_H
|
||||||
|
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include "sysadm-global.h"
|
||||||
|
|
||||||
|
namespace sysadm{
|
||||||
|
|
||||||
|
class sourcectl{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static QJsonObject downloadports();
|
||||||
|
static QJsonObject updateports();
|
||||||
|
static QJsonObject deleteports();
|
||||||
|
static QJsonObject stopports();
|
||||||
|
static QJsonObject downloadsource();
|
||||||
|
static QJsonObject updatesource();
|
||||||
|
static QJsonObject deletesource();
|
||||||
|
static QJsonObject stopsource();
|
||||||
|
|
||||||
|
static void saveSourceLog(QString);
|
||||||
|
static void savePortsLog(QString);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} //end of sysadm namespace
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -7,33 +7,29 @@
|
|||||||
#include "sysadm-general.h"
|
#include "sysadm-general.h"
|
||||||
#include "sysadm-systemmanager.h"
|
#include "sysadm-systemmanager.h"
|
||||||
#include "sysadm-global.h"
|
#include "sysadm-global.h"
|
||||||
|
//need access to the global DISPATCHER object
|
||||||
|
#include "globals.h"
|
||||||
|
|
||||||
using namespace sysadm;
|
using namespace sysadm;
|
||||||
|
|
||||||
//PLEASE: Keep the functions in the same order as listed in pcbsd-general.h
|
|
||||||
|
|
||||||
|
|
||||||
//Battery Availability
|
//Battery Availability
|
||||||
QJsonObject SysMgmt::batteryInfo(){
|
QJsonObject SysMgmt::batteryInfo(){
|
||||||
QJsonObject retObject;
|
QJsonObject retObject;
|
||||||
bool ok;
|
bool ok;
|
||||||
|
QString tmp; //temporary string for use later
|
||||||
|
|
||||||
int val = General::RunCommand("apm -l").toInt(&ok);
|
//Battery Charging State
|
||||||
if ( ok && (val >= 0 && val <= 100) ) {
|
QStringList vals = General::RunCommand("apm -alt").split("\n");
|
||||||
retObject.insert("battery", "true");
|
int state =-1;
|
||||||
} else {
|
if(vals.length()>=1){ state = vals[0].toInt(&ok); }
|
||||||
|
//Battery Charge State is 255 if no battery available
|
||||||
|
if (ok && state == 255 ){
|
||||||
retObject.insert("battery", "false");
|
retObject.insert("battery", "false");
|
||||||
return retObject;
|
return retObject;
|
||||||
}
|
}
|
||||||
|
retObject.insert("battery", "true");
|
||||||
// We have a battery, return info about it
|
// Charging state
|
||||||
//Battery Charge Level
|
|
||||||
QString tmp;
|
|
||||||
tmp.setNum(val);
|
|
||||||
retObject.insert("level", tmp);
|
|
||||||
|
|
||||||
//Battery Charging State
|
|
||||||
int state = General::RunCommand("apm -a").toInt(&ok);
|
|
||||||
if ( ok && state == 0 )
|
if ( ok && state == 0 )
|
||||||
retObject.insert("status", "offline");
|
retObject.insert("status", "offline");
|
||||||
else if ( ok && state == 1 )
|
else if ( ok && state == 1 )
|
||||||
@@ -42,8 +38,20 @@ QJsonObject SysMgmt::batteryInfo(){
|
|||||||
retObject.insert("status", "backup");
|
retObject.insert("status", "backup");
|
||||||
else
|
else
|
||||||
retObject.insert("status", "unknown");
|
retObject.insert("status", "unknown");
|
||||||
|
// Charging Level
|
||||||
int timeleft = General::RunCommand("apm -t").toInt(&ok);
|
int level = -1;
|
||||||
|
ok = false;
|
||||||
|
if(vals.length()>=2){ level = vals[1].toInt(&ok); }
|
||||||
|
if ( ok ) {
|
||||||
|
tmp.setNum(level);
|
||||||
|
retObject.insert("level", tmp);
|
||||||
|
} else {
|
||||||
|
retObject.insert("level", "-1");
|
||||||
|
}
|
||||||
|
// Time Left (seconds)
|
||||||
|
int timeleft = -1;
|
||||||
|
ok = false;
|
||||||
|
if(vals.length()>=3){ timeleft= vals[2].toInt(&ok); }
|
||||||
if ( ok ) {
|
if ( ok ) {
|
||||||
tmp.setNum(timeleft);
|
tmp.setNum(timeleft);
|
||||||
retObject.insert("timeleft", tmp);
|
retObject.insert("timeleft", tmp);
|
||||||
@@ -65,7 +73,7 @@ QJsonObject SysMgmt::cpuPercentage() {
|
|||||||
QStringList result = General::RunCommand("sysctl -n kern.cp_times").split(" ");
|
QStringList result = General::RunCommand("sysctl -n kern.cp_times").split(" ");
|
||||||
static QStringList last = QStringList();
|
static QStringList last = QStringList();
|
||||||
if(last.isEmpty()){
|
if(last.isEmpty()){
|
||||||
//need two ticks before it works properly
|
//need two ticks before it works properly
|
||||||
sleep(1);
|
sleep(1);
|
||||||
last = result;
|
last = result;
|
||||||
result = General::RunCommand("sysctl -n kern.cp_times").split(" ");
|
result = General::RunCommand("sysctl -n kern.cp_times").split(" ");
|
||||||
@@ -81,7 +89,7 @@ QJsonObject SysMgmt::cpuPercentage() {
|
|||||||
//Adjust/all the data to correspond to diffs from the previous check
|
//Adjust/all the data to correspond to diffs from the previous check
|
||||||
for(int j=0; j<5; j++){
|
for(int j=0; j<5; j++){
|
||||||
QString tmp = result[i-j];
|
QString tmp = result[i-j];
|
||||||
result[i-j] = QString::number(result[i-j].toLong()-last[i-j].toLong());
|
result[i-j] = QString::number(result[i-j].toLong()-last[i-j].toLong());
|
||||||
//need the difference between last run and this one
|
//need the difference between last run and this one
|
||||||
sum += result[i-j].toLong();
|
sum += result[i-j].toLong();
|
||||||
last[i-j] = tmp; //make sure to keep the original value around for the next run
|
last[i-j] = tmp; //make sure to keep the original value around for the next run
|
||||||
@@ -211,7 +219,7 @@ QJsonObject SysMgmt::memoryStats() {
|
|||||||
QString tmp;
|
QString tmp;
|
||||||
long pageSize;
|
long pageSize;
|
||||||
bool ok;
|
bool ok;
|
||||||
|
|
||||||
// Get the page size
|
// Get the page size
|
||||||
tmp = General::RunCommand("sysctl -n vm.stats.vm.v_page_size").simplified();
|
tmp = General::RunCommand("sysctl -n vm.stats.vm.v_page_size").simplified();
|
||||||
tmp.toLong(&ok);
|
tmp.toLong(&ok);
|
||||||
@@ -262,7 +270,7 @@ QJsonObject SysMgmt::procInfo() {
|
|||||||
for(int i=0; i<output.length(); i++){
|
for(int i=0; i<output.length(); i++){
|
||||||
if (output.at(i).contains("PID") && output.at(i).contains("USERNAME")){
|
if (output.at(i).contains("PID") && output.at(i).contains("USERNAME")){
|
||||||
inSection = true;
|
inSection = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!inSection)
|
if (!inSection)
|
||||||
continue;
|
continue;
|
||||||
@@ -291,6 +299,26 @@ QJsonObject SysMgmt::procInfo() {
|
|||||||
return retObject;
|
return retObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get a sysctl
|
||||||
|
QJsonObject SysMgmt::getSysctl(QJsonObject jsin) {
|
||||||
|
QJsonObject retObject;
|
||||||
|
|
||||||
|
QStringList sysctl;
|
||||||
|
if(jsin.value("sysctl").isArray()){ sysctl = General::JsonArrayToStringList(jsin.value("sysctl").toArray()); }
|
||||||
|
else if(jsin.value("sysctl").isString()){ sysctl << jsin.value("sysctl").toString(); }
|
||||||
|
if ( sysctl.isEmpty() ) {
|
||||||
|
retObject.insert("error", "Missing required key 'sysctl'");
|
||||||
|
return retObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList output = General::RunCommand("sysctl", sysctl).split("\n");
|
||||||
|
for(int i=0; i<output.length(); i++){
|
||||||
|
if( !output[i].contains(":") || output[i].contains("unknown oid") ){ continue; }
|
||||||
|
retObject.insert(output[i].section(":",0,0), output[i].section(":",1,-1).simplified());
|
||||||
|
}
|
||||||
|
return retObject;
|
||||||
|
}
|
||||||
|
|
||||||
// Set a sysctl
|
// Set a sysctl
|
||||||
QJsonObject SysMgmt::setSysctl(QJsonObject jsin) {
|
QJsonObject SysMgmt::setSysctl(QJsonObject jsin) {
|
||||||
QJsonObject retObject;
|
QJsonObject retObject;
|
||||||
@@ -317,18 +345,29 @@ QJsonObject SysMgmt::sysctlList() {
|
|||||||
QJsonObject retObject;
|
QJsonObject retObject;
|
||||||
|
|
||||||
// This can be cleaned up and not use CLI
|
// This can be cleaned up and not use CLI
|
||||||
QStringList output = General::RunCommand("sysctl -W -a").split("\n");
|
QStringList output = General::RunCommand("sysctl -aW").split("\n");
|
||||||
|
QStringList details = General::RunCommand("sysctl -aWdt").split("\n");
|
||||||
|
|
||||||
QString sysctl, value;
|
QString sysctl, type, description;
|
||||||
for(int i=0; i<output.length(); i++){
|
for(int i=0; i<output.length(); i++){
|
||||||
if ( output.at(i).isEmpty())
|
if ( output.at(i).isEmpty()){ continue; }
|
||||||
continue;
|
QJsonObject tmp;
|
||||||
|
|
||||||
sysctl = output.at(i).section(":", 0, 0);
|
sysctl = output.at(i).section(":", 0, 0);
|
||||||
value = output.at(i).section(":", 1, -1).simplified();
|
tmp.insert("value", output.at(i).section(":", 1, -1).simplified() );
|
||||||
retObject.insert(sysctl, value);
|
retObject.insert(sysctl, tmp);
|
||||||
|
}
|
||||||
|
for(int i=0; i<details.length(); i++){
|
||||||
|
if ( details.at(i).isEmpty() ){ continue; }
|
||||||
|
sysctl = details[i].section(":",0,0);
|
||||||
|
type = details[i].section(":",1,1).simplified();
|
||||||
|
description = details[i].section(":",2,-1).simplified();
|
||||||
|
if(retObject.contains(sysctl)){
|
||||||
|
QJsonObject tmp = retObject.value(sysctl).toObject();
|
||||||
|
tmp.insert("type", type);
|
||||||
|
if(!description.isEmpty()){ tmp.insert("description", description); }
|
||||||
|
retObject.insert(sysctl, tmp); //replace the sysctl object into the output object
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return retObject;
|
return retObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,3 +430,28 @@ QJsonObject SysMgmt::systemReboot() {
|
|||||||
|
|
||||||
return retObject;
|
return retObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get all device information about the system
|
||||||
|
QJsonObject SysMgmt::systemDevices(){
|
||||||
|
QJsonObject pciconf_info;
|
||||||
|
QStringList lines = General::RunCommand("pciconf -lv").split("\n");
|
||||||
|
//qDebug() << "Raw pciconf:" << lines;
|
||||||
|
QJsonObject cobj; QString cid;
|
||||||
|
for(int i=0; i<lines.length(); i++){
|
||||||
|
if(!lines[i].contains(" = ") && !cid.isEmpty()){ pciconf_info.insert(cid,cobj); cid.clear(); cobj = QJsonObject(); }
|
||||||
|
if(lines[i].contains(" = ")){
|
||||||
|
QString var = lines[i].section("=",0,0).simplified();
|
||||||
|
QString val = lines[i].section("=",1,-1).simplified();
|
||||||
|
if(val.startsWith("\'") && val.endsWith("\'")){ val.chop(1); val = val.remove(0,1); }
|
||||||
|
//qDebug() << "PCICONF LINE:" << lines[i];
|
||||||
|
//qDebug() << "\t\t" << var << val;
|
||||||
|
cobj.insert(var,val);
|
||||||
|
}else{
|
||||||
|
//New device section
|
||||||
|
cid = lines[i].section("@",0,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!cid.isEmpty() && cobj.keys().isEmpty()){ pciconf_info.insert(cid,cobj); }
|
||||||
|
return pciconf_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include "sysadm-global.h"
|
#include "sysadm-global.h"
|
||||||
|
|
||||||
|
|
||||||
namespace sysadm{
|
namespace sysadm{
|
||||||
|
|
||||||
class SysMgmt{
|
class SysMgmt{
|
||||||
@@ -21,13 +22,21 @@ public:
|
|||||||
static QJsonObject killProc(QJsonObject);
|
static QJsonObject killProc(QJsonObject);
|
||||||
static QJsonObject memoryStats();
|
static QJsonObject memoryStats();
|
||||||
static QJsonObject procInfo();
|
static QJsonObject procInfo();
|
||||||
|
|
||||||
|
//sysctl management
|
||||||
|
static QJsonObject getSysctl(QJsonObject);
|
||||||
static QJsonObject setSysctl(QJsonObject);
|
static QJsonObject setSysctl(QJsonObject);
|
||||||
static QJsonObject sysctlList();
|
static QJsonObject sysctlList();
|
||||||
|
|
||||||
static QJsonObject systemInfo();
|
static QJsonObject systemInfo();
|
||||||
static QJsonObject systemReboot();
|
static QJsonObject systemReboot();
|
||||||
static QJsonObject systemHalt();
|
static QJsonObject systemHalt();
|
||||||
|
|
||||||
|
static QJsonObject systemDevices();
|
||||||
|
static QJsonObject fetchPortsTree(QString altDir = ""); //QStringList &cmds, QStringList &dirs);
|
||||||
|
//static QJsonObject fetchSourceTree(QString branch, QStringList &cmds, QStringList &dirs); // This is not ready yet
|
||||||
};
|
};
|
||||||
|
|
||||||
} //end of pcbsd namespace
|
} //end of namespace
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -11,8 +11,9 @@
|
|||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
|
||||||
#define UP_PIDFILE "/tmp/.updateInProgress"
|
#define UP_PIDFILE "/tmp/.updateInProgress"
|
||||||
#define UP_RBFILE "/tmp/.rebootRequired"
|
#define UP_RBFILE "/tmp/.trueos-update-staged"
|
||||||
#define UP_UPFILE "/tmp/.updatesAvailable"
|
#define UP_UPFILE "/tmp/.updatesAvailable"
|
||||||
|
#define UP_UPFILE_ERR "/tmp/.updateCheckError"
|
||||||
|
|
||||||
#define UP_CONFFILE "/usr/local/etc/trueos.conf"
|
#define UP_CONFFILE "/usr/local/etc/trueos.conf"
|
||||||
|
|
||||||
@@ -34,15 +35,23 @@ QDateTime Update::rebootRequiredSince(){
|
|||||||
QJsonObject Update::checkUpdates(bool fast) {
|
QJsonObject Update::checkUpdates(bool fast) {
|
||||||
//NOTE: The "fast" option should only be used for automated/timed checks (to prevent doing this long check too frequently)
|
//NOTE: The "fast" option should only be used for automated/timed checks (to prevent doing this long check too frequently)
|
||||||
QJsonObject retObject;
|
QJsonObject retObject;
|
||||||
qDebug() << "Check for updates: fast=" << fast;
|
//qDebug() << "Check for updates: fast=" << fast;
|
||||||
//Quick check to ensure the tool is available
|
//Quick check to ensure the tool is available
|
||||||
if(!QFile::exists("/usr/local/bin/pc-updatemanager")){
|
QString tool = "/usr/local/bin/pc-updatemanager";
|
||||||
|
if(!QFile::exists(tool)){
|
||||||
|
return retObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
//See if the check for updates is currently running - just return nothing at the moment for that
|
||||||
|
if(DISPATCHER->isJobActive("sysadm_update_checkupdates")){
|
||||||
|
retObject.insert("status", "checkingforupdates");
|
||||||
return retObject;
|
return retObject;
|
||||||
}
|
}
|
||||||
//Check if the system is waiting to reboot
|
//Check if the system is waiting to reboot
|
||||||
if(QFile::exists(UP_RBFILE)){
|
if(QFile::exists(UP_RBFILE)){
|
||||||
retObject.insert("status","rebootrequired");
|
retObject.insert("status","rebootrequired");
|
||||||
if(QFile::exists(UP_UPFILE)){ QFile::remove(UP_UPFILE); } //ensure the next fast update does a full check
|
if(QFile::exists(UP_UPFILE)){ QFile::remove(UP_UPFILE); } //ensure the next fast update does a full check
|
||||||
|
if(QFile::exists(UP_UPFILE_ERR)){ QFile::remove(UP_UPFILE_ERR); } //ensure the next fast update does a full check
|
||||||
//Also add the information on what updates are pending
|
//Also add the information on what updates are pending
|
||||||
retObject.insert("details", sysadm::General::readTextFile(UP_RBFILE).join("\n") );
|
retObject.insert("details", sysadm::General::readTextFile(UP_RBFILE).join("\n") );
|
||||||
return retObject;
|
return retObject;
|
||||||
@@ -57,36 +66,44 @@ QJsonObject Update::checkUpdates(bool fast) {
|
|||||||
return retObject;
|
return retObject;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Get the list of deatils from the update checks (fast/full)
|
//Get the list of details from the update checks (fast/full)
|
||||||
QStringList output;
|
QStringList output;
|
||||||
QDateTime cdt = QDateTime::currentDateTime();
|
QDateTime cdt = QDateTime::currentDateTime();
|
||||||
QDateTime fdt = cdt.addDays(-1); //just enough to trip the checks below if needed
|
QDateTime fdt = cdt.addDays(-1); //just enough to trip the checks below if needed
|
||||||
|
bool lasterr = false;
|
||||||
if(QFile::exists(UP_UPFILE)){ fdt = QFileInfo(UP_UPFILE).lastModified(); }
|
if(QFile::exists(UP_UPFILE)){ fdt = QFileInfo(UP_UPFILE).lastModified(); }
|
||||||
|
else if(QFile::exists(UP_UPFILE_ERR)){ fdt = QFileInfo(UP_UPFILE_ERR).lastModified(); lasterr = true; }
|
||||||
//qDebug() << "Time Stamps (now/file):" << cdt << fdt;
|
//qDebug() << "Time Stamps (now/file):" << cdt << fdt;
|
||||||
//qDebug() << " - File earlier than now:" << (fdt<cdt);
|
//qDebug() << " - File earlier than now:" << (fdt<cdt);
|
||||||
//qDebug() << " - File +1 day earlier than now (+day):" << (fdt.addDays(1)<cdt);
|
//qDebug() << " - File +1 day earlier than now (+day):" << (fdt.addDays(1)<cdt);
|
||||||
//qDebug() << " - File +1 day earlier than now (+secs):" << (fdt.addSecs(24*60)<cdt);
|
//qDebug() << " - File +1 day earlier than now (+secs):" << (fdt.addSecs(24*60)<cdt);
|
||||||
//qDebug() << " - Seconds from File->Day time:" << fdt.secsTo(cdt);
|
//qDebug() << " - Seconds from File->Day time:" << fdt.secsTo(cdt);
|
||||||
int secs = fdt.secsTo(cdt);
|
int secs = fdt.secsTo(cdt);
|
||||||
if(fast && (secs<43200) ){
|
if(fast && (secs<43200) && !lasterr ){
|
||||||
//Note: The "fast" check will only be used if the last full check was less than 12 hours earlier.
|
//Note: The "fast" check will only be used if the last full check was less than 12 hours earlier
|
||||||
|
// (unless the last run ended in an error - then it will use the 5-minute check below)
|
||||||
//qDebug() << " - UseFast Re-read";
|
//qDebug() << " - UseFast Re-read";
|
||||||
output = General::readTextFile(UP_UPFILE);
|
if(lasterr){output = General::readTextFile(UP_UPFILE_ERR); }
|
||||||
}else if(secs<600 ){
|
else{ output = General::readTextFile(UP_UPFILE); }
|
||||||
//Note: This will re-use the previous check if it was less than 10 minutes ago (prevent hammering servers from user checks)
|
|
||||||
//qDebug() << " - Use Fast Re-read (failsafe - less than 10 minute interval)";
|
}else if(secs<300){
|
||||||
output = General::readTextFile(UP_UPFILE);
|
//Note: This will re-use the previous check if it was less than 5 minutes ago (prevent hammering servers from user checks)
|
||||||
}else{
|
//qDebug() << " - Use Fast Re-read (failsafe - less than 5 minute interval)";
|
||||||
|
if(lasterr){ output = General::readTextFile(UP_UPFILE_ERR); }
|
||||||
|
else{ output = General::readTextFile(UP_UPFILE); }
|
||||||
|
}else{
|
||||||
//qDebug() << " - Run full check";
|
//qDebug() << " - Run full check";
|
||||||
//output = General::RunCommand("pc-updatemanager check").split("\n");
|
QStringList cmds;
|
||||||
output.append( General::RunCommand("pc-updatemanager pkgcheck").split("\n") );
|
if(tool.endsWith("/pc-updatemanager")){
|
||||||
while(output.last().simplified()==""){ output.removeLast(); }
|
cmds << "pc-updatemanager syncconf" << "pc-updatemanager pkgcheck";
|
||||||
if(!output.last().contains("ERROR:")){ //make sure there was network access available first - otherwise let it try again soon
|
|
||||||
General::writeTextFile(UP_UPFILE, output); //save this check for later "fast" updates
|
|
||||||
}
|
}
|
||||||
|
DISPATCHER->queueProcess("sysadm_update_checkupdates", cmds );
|
||||||
|
retObject.insert("status", "checkingforupdates");
|
||||||
|
//qDebug() << " - Done starting check";
|
||||||
|
return retObject;
|
||||||
}
|
}
|
||||||
//qDebug() << "pc-updatemanager checks:" << output;
|
//qDebug() << "pc-updatemanager checks:" << output;
|
||||||
|
|
||||||
QString nameval;
|
QString nameval;
|
||||||
int pnum=1;
|
int pnum=1;
|
||||||
for ( int i = 0; i < output.size(); i++)
|
for ( int i = 0; i < output.size(); i++)
|
||||||
@@ -135,10 +152,28 @@ QJsonObject Update::checkUpdates(bool fast) {
|
|||||||
retObject.insert("status", "updatesavailable");
|
retObject.insert("status", "updatesavailable");
|
||||||
}
|
}
|
||||||
retObject.insert("details", output.join("\n") ); //full details of the check for updates
|
retObject.insert("details", output.join("\n") ); //full details of the check for updates
|
||||||
retObject.insert("last_check",QFileInfo(UP_UPFILE).lastModified().toString(Qt::ISODate) );
|
if(QFile::exists(UP_UPFILE)){
|
||||||
|
retObject.insert("last_check",QFileInfo(UP_UPFILE).lastModified().toString(Qt::ISODate) );
|
||||||
|
}else if(QFile::exists(UP_UPFILE_ERR)){
|
||||||
|
retObject.insert("last_check",QFileInfo(UP_UPFILE_ERR).lastModified().toString(Qt::ISODate) );
|
||||||
|
}
|
||||||
return retObject;
|
return retObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Update::saveCheckUpdateLog(QString log){
|
||||||
|
QStringList output = log.split("\n");
|
||||||
|
qDebug() << "Got Check Update Log:" << log << output;
|
||||||
|
while(!output.isEmpty() && output.last().simplified().isEmpty()){ output.removeLast(); }
|
||||||
|
if(output.isEmpty()){ return; }
|
||||||
|
if(!output.last().contains("ERROR:")){ //make sure there was network access available first - otherwise let it try again soon
|
||||||
|
General::writeTextFile(UP_UPFILE, output); //save this check for later "fast" updates
|
||||||
|
if(QFile::exists(UP_UPFILE_ERR)){ QFile::remove(UP_UPFILE_ERR); } //remove any previous failed log
|
||||||
|
}else{
|
||||||
|
General::writeTextFile(UP_UPFILE_ERR,output); //save this error return for later
|
||||||
|
if(QFile::exists(UP_UPFILE)){ QFile::remove(UP_UPFILE); } //remove any previous good log
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// List available branches we can switch to
|
// List available branches we can switch to
|
||||||
QJsonObject Update::listBranches() {
|
QJsonObject Update::listBranches() {
|
||||||
QJsonObject retObject;
|
QJsonObject retObject;
|
||||||
@@ -174,50 +209,23 @@ QJsonObject Update::listBranches() {
|
|||||||
QJsonObject Update::startUpdate(QJsonObject jsin) {
|
QJsonObject Update::startUpdate(QJsonObject jsin) {
|
||||||
QJsonObject retObject;
|
QJsonObject retObject;
|
||||||
|
|
||||||
QStringList keys = jsin.keys();
|
//Quick check to ensure the tool is available
|
||||||
if (! keys.contains("target") ) {
|
QString tool = "/usr/local/bin/pc-updatemanager";
|
||||||
retObject.insert("error", "Missing required key 'target'");
|
QStringList flags; flags << "pkgupdate";
|
||||||
|
if(!QFile::exists(tool)){
|
||||||
return retObject;
|
return retObject;
|
||||||
}
|
}
|
||||||
// Save the target
|
|
||||||
QString target;
|
|
||||||
target = jsin.value("target").toString();
|
|
||||||
|
|
||||||
QString flags;
|
|
||||||
if ( target == "chbranch" ) {
|
|
||||||
if (! keys.contains("branch") ) {
|
|
||||||
retObject.insert("error", "Missing required key 'branch'");
|
|
||||||
return retObject;
|
|
||||||
}
|
|
||||||
flags = "chbranch " + jsin.value("branch").toString();
|
|
||||||
} else if ( target == "pkgupdate" ) {
|
|
||||||
flags = "pkgupdate";
|
|
||||||
/* } else if ( target == "fbsdupdate" ) {
|
|
||||||
flags = "fbsdupdate";
|
|
||||||
} else if ( target == "fbsdupdatepkgs" ) {
|
|
||||||
flags = "fbsdupdatepkgs";*/
|
|
||||||
} else if ( target == "standalone" ) {
|
|
||||||
if (! keys.contains("tag") ) {
|
|
||||||
retObject.insert("error", "Missing required key 'tag'");
|
|
||||||
return retObject;
|
|
||||||
}
|
|
||||||
flags = "install " + jsin.value("tag").toString();
|
|
||||||
} else {
|
|
||||||
// Ruh-roh
|
|
||||||
retObject.insert("error", "Unknown target key: " + target);
|
|
||||||
return retObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a unique ID for this queued action
|
// Create a unique ID for this queued action
|
||||||
QString ID = QUuid::createUuid().toString();
|
QString ID = QUuid::createUuid().toString();
|
||||||
|
|
||||||
// Queue the update action
|
// Queue the update action
|
||||||
DISPATCHER->queueProcess("sysadm_update_runupdates::"+ID, "pc-updatemanager " + flags);
|
DISPATCHER->queueProcess("sysadm_update_runupdates::"+ID, tool+" "+ flags.join(" "));
|
||||||
|
|
||||||
if(QFile::exists(UP_UPFILE)){ QFile::remove(UP_UPFILE); } //ensure the next fast update does a full check
|
if(QFile::exists(UP_UPFILE)){ QFile::remove(UP_UPFILE); } //ensure the next fast update does a full check
|
||||||
|
|
||||||
// Return some details to user that the action was queued
|
// Return some details to user that the action was queued
|
||||||
retObject.insert("command", "pc-updatemanger " + flags);
|
retObject.insert("command", tool+" "+ flags.join(" "));
|
||||||
retObject.insert("comment", "Task Queued");
|
retObject.insert("comment", "Task Queued");
|
||||||
retObject.insert("queueid", ID);
|
retObject.insert("queueid", ID);
|
||||||
return retObject;
|
return retObject;
|
||||||
@@ -247,11 +255,19 @@ QJsonObject Update::stopUpdate() {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QJsonObject Update::applyUpdates(){
|
||||||
|
QJsonObject ret;
|
||||||
|
if(QFile::exists("/usr/local/sbin/pc-updatemanager")){
|
||||||
|
QProcess::startDetached("pc-updatemanager startupdate");
|
||||||
|
}
|
||||||
|
ret.insert("result","rebooting to complete updates");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
//SETTINGS OPTIONS
|
//SETTINGS OPTIONS
|
||||||
QJsonObject Update::readSettings(){
|
QJsonObject Update::readSettings(){
|
||||||
QJsonObject ret;
|
QJsonObject ret;
|
||||||
QStringList knownsettings;
|
QStringList knownsettings;
|
||||||
knownsettings << "PACKAGE_SET" << "PACKAGE_URL" << "AUTO_UPDATE" << "MAXBE" << "AUTO_UPDATE_REBOOT";// << "CDN_TYPE";
|
knownsettings << "PACKAGE_SET" << "PACKAGE_URL" << "AUTO_UPDATE" << "MAXBE" << "AUTO_UPDATE_REBOOT" << "CDN_TYPE";
|
||||||
|
|
||||||
QStringList info = General::readTextFile(UP_CONFFILE);
|
QStringList info = General::readTextFile(UP_CONFFILE);
|
||||||
for(int i=0; i<info.length(); i++){
|
for(int i=0; i<info.length(); i++){
|
||||||
@@ -269,7 +285,7 @@ QJsonObject Update::writeSettings(QJsonObject obj){
|
|||||||
QJsonObject ret;
|
QJsonObject ret;
|
||||||
//Check inputs
|
//Check inputs
|
||||||
QStringList knownsettings;
|
QStringList knownsettings;
|
||||||
knownsettings << "PACKAGE_SET" << "PACKAGE_URL" << "AUTO_UPDATE" << "MAXBE" << "AUTO_UPDATE_REBOOT";// << "CDN_TYPE";
|
knownsettings << "PACKAGE_SET" << "PACKAGE_URL" << "AUTO_UPDATE" << "MAXBE" << "AUTO_UPDATE_REBOOT" << "CDN_TYPE";
|
||||||
QStringList keys = obj.keys();
|
QStringList keys = obj.keys();
|
||||||
QStringList vals;
|
QStringList vals;
|
||||||
bool clearlastCheck = false;
|
bool clearlastCheck = false;
|
||||||
@@ -306,6 +322,7 @@ QJsonObject Update::writeSettings(QJsonObject obj){
|
|||||||
ret.insert("result","success");
|
ret.insert("result","success");
|
||||||
if(clearlastCheck){
|
if(clearlastCheck){
|
||||||
if(QFile::exists(UP_UPFILE)){ QFile::remove(UP_UPFILE); } //ensure the next fast update does a full check
|
if(QFile::exists(UP_UPFILE)){ QFile::remove(UP_UPFILE); } //ensure the next fast update does a full check
|
||||||
|
if(QFile::exists(UP_UPFILE_ERR)){ QFile::remove(UP_UPFILE_ERR); } //ensure the next fast update does a full check
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
ret.insert("result","error");
|
ret.insert("result","error");
|
||||||
|
|||||||
@@ -19,10 +19,13 @@ public:
|
|||||||
static QDateTime rebootRequiredSince();
|
static QDateTime rebootRequiredSince();
|
||||||
//Listing routines
|
//Listing routines
|
||||||
static QJsonObject checkUpdates(bool fast = false);
|
static QJsonObject checkUpdates(bool fast = false);
|
||||||
|
static void saveCheckUpdateLog(QString); //Internal for Dispatcher process usage - do not expose to public API
|
||||||
|
|
||||||
static QJsonObject listBranches();
|
static QJsonObject listBranches();
|
||||||
//Start/stop update routine
|
//Start/stop update routine
|
||||||
static QJsonObject startUpdate(QJsonObject);
|
static QJsonObject startUpdate(QJsonObject);
|
||||||
static QJsonObject stopUpdate();
|
static QJsonObject stopUpdate();
|
||||||
|
static QJsonObject applyUpdates();
|
||||||
//Read/write update settings
|
//Read/write update settings
|
||||||
static QJsonObject readSettings();
|
static QJsonObject readSettings();
|
||||||
static QJsonObject writeSettings(QJsonObject);
|
static QJsonObject writeSettings(QJsonObject);
|
||||||
@@ -31,7 +34,7 @@ public:
|
|||||||
static QJsonObject readLog(QJsonObject);
|
static QJsonObject readLog(QJsonObject);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -37,18 +37,17 @@ void MessageOutput(QtMsgType type, const QMessageLogContext &context, const QStr
|
|||||||
break;
|
break;
|
||||||
case QtWarningMsg:
|
case QtWarningMsg:
|
||||||
txt = QString("WARNING: %1").arg(msg);
|
txt = QString("WARNING: %1").arg(msg);
|
||||||
txt += "\n Context: "+QString(context.file)+" Line: "+QString(context.line)+" Function: "+QString(context.function);
|
|
||||||
break;
|
break;
|
||||||
case QtCriticalMsg:
|
case QtCriticalMsg:
|
||||||
txt = QString("CRITICAL: %1").arg(msg);
|
txt = QString("CRITICAL: %1").arg(msg);
|
||||||
txt += "\n Context: "+QString(context.file)+" Line: "+QString(context.line)+" Function: "+QString(context.function);
|
|
||||||
break;
|
break;
|
||||||
case QtFatalMsg:
|
case QtFatalMsg:
|
||||||
txt = QString("FATAL: %1").arg(msg);
|
txt = QString("FATAL: %1").arg(msg);
|
||||||
txt += "\n Context: "+QString(context.file)+" Line: "+QString(context.line)+" Function: "+QString(context.function);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if( type!=QtDebugMsg && !QString(context.file).isEmpty() ){
|
||||||
|
txt += "\n Context: "+QString(context.file)+" Line: "+QString(context.line)+" Function: "+QString(context.function);
|
||||||
|
}
|
||||||
QTextStream out(&logfile);
|
QTextStream out(&logfile);
|
||||||
out << txt;
|
out << txt;
|
||||||
if(!txt.endsWith("\n")){ out << "\n"; }
|
if(!txt.endsWith("\n")){ out << "\n"; }
|
||||||
@@ -79,7 +78,6 @@ qDebug() << " \"bridge_export_key [file]\": Export the public SSL key the serve
|
|||||||
|
|
||||||
int main( int argc, char ** argv )
|
int main( int argc, char ** argv )
|
||||||
{
|
{
|
||||||
|
|
||||||
//Check whether running as root
|
//Check whether running as root
|
||||||
if( getuid() != 0){
|
if( getuid() != 0){
|
||||||
qDebug() << "sysadm-server must be started as root!";
|
qDebug() << "sysadm-server must be started as root!";
|
||||||
@@ -121,7 +119,7 @@ int main( int argc, char ** argv )
|
|||||||
QSslCertificate cert(&cfile);
|
QSslCertificate cert(&cfile);
|
||||||
cfile.close();
|
cfile.close();
|
||||||
if(!cert.isNull()){
|
if(!cert.isNull()){
|
||||||
if(i+1<argc){
|
if(i+1<argc){
|
||||||
i++; QString filepath = argv[i];
|
i++; QString filepath = argv[i];
|
||||||
QFile outfile(filepath);
|
QFile outfile(filepath);
|
||||||
outfile.open(QIODevice::WriteOnly | QIODevice::Truncate);
|
outfile.open(QIODevice::WriteOnly | QIODevice::Truncate);
|
||||||
@@ -150,11 +148,11 @@ int main( int argc, char ** argv )
|
|||||||
if(!file.open(QIODevice::ReadOnly)){ qDebug() << "Could not open file:" << file.fileName(); }
|
if(!file.open(QIODevice::ReadOnly)){ qDebug() << "Could not open file:" << file.fileName(); }
|
||||||
else{
|
else{
|
||||||
QByteArray enc_key;
|
QByteArray enc_key;
|
||||||
if(file.fileName().endsWith(".crt")){
|
if(file.fileName().endsWith(".crt")){
|
||||||
QSslCertificate cert(&file, QSsl::Pem);
|
QSslCertificate cert(&file, QSsl::Pem);
|
||||||
if(!cert.isNull()){ enc_key = cert.publicKey().toPem(); }
|
if(!cert.isNull()){ enc_key = cert.publicKey().toPem(); }
|
||||||
}else if(file.fileName().endsWith(".key")){
|
}else if(file.fileName().endsWith(".key")){
|
||||||
QSslKey key( &file, QSsl::Rsa, QSsl::Pem, QSsl::PublicKey);
|
QSslKey key( &file, QSsl::Rsa, QSsl::Pem, QSsl::PublicKey);
|
||||||
if(!key.isNull()){ enc_key = key.toPem(); }
|
if(!key.isNull()){ enc_key = key.toPem(); }
|
||||||
}else{
|
}else{
|
||||||
qDebug() << "Error: Unknown file type (need .crt or .key file)";
|
qDebug() << "Error: Unknown file type (need .crt or .key file)";
|
||||||
@@ -172,13 +170,13 @@ int main( int argc, char ** argv )
|
|||||||
if(QFile::exists(key)){
|
if(QFile::exists(key)){
|
||||||
QFile file(key);
|
QFile file(key);
|
||||||
QByteArray pubkey;
|
QByteArray pubkey;
|
||||||
if(file.open(QIODevice::ReadOnly)){
|
if(file.open(QIODevice::ReadOnly)){
|
||||||
QSslKey sslkey( &file, QSsl::Rsa, QSsl::Pem, QSsl::PublicKey);
|
QSslKey sslkey( &file, QSsl::Rsa, QSsl::Pem, QSsl::PublicKey);
|
||||||
if(!key.isNull()){ pubkey = sslkey.toPem(); }
|
if(!key.isNull()){ pubkey = sslkey.toPem(); }
|
||||||
else{ qDebug() << "Invalid Key file:" << file.fileName(); ok = false; }
|
else{ qDebug() << "Invalid Key file:" << file.fileName(); ok = false; }
|
||||||
file.close();
|
file.close();
|
||||||
}else{ qDebug() << "Could not open file:" << file.fileName(); ok = false; }
|
}else{ qDebug() << "Could not open file:" << file.fileName(); ok = false; }
|
||||||
}
|
}
|
||||||
if(ok){ ok = AuthorizationManager::RegisterCertificateInternal(user, key, nickname, email); }
|
if(ok){ ok = AuthorizationManager::RegisterCertificateInternal(user, key, nickname, email); }
|
||||||
if(ok){ qDebug() << "Key Added" << user << nickname; }
|
if(ok){ qDebug() << "Key Added" << user << nickname; }
|
||||||
else{ qDebug() << "Could not add key"; } */
|
else{ qDebug() << "Could not add key"; } */
|
||||||
@@ -193,18 +191,20 @@ int main( int argc, char ** argv )
|
|||||||
|
|
||||||
QCoreApplication a(argc, argv);
|
QCoreApplication a(argc, argv);
|
||||||
//Now load the config file
|
//Now load the config file
|
||||||
QStringList conf = ReadFile(CONFFILE).split("\n");
|
QString conf_file = CONFFILE;
|
||||||
|
if( !QFile::exists(conf_file) ){ conf_file.append(".dist"); } //no settings - use the default config
|
||||||
|
QStringList conf = ReadFile(conf_file).split("\n");
|
||||||
if(!conf.filter("[internal]").isEmpty()){
|
if(!conf.filter("[internal]").isEmpty()){
|
||||||
//Older QSettings file - move it to the new location
|
//Older QSettings file - move it to the new location
|
||||||
if(QFile::exists(SETTINGSFILE)){ QFile::remove(SETTINGSFILE); } //remove the new/empty settings file
|
if(QFile::exists(SETTINGSFILE)){ QFile::remove(SETTINGSFILE); } //remove the new/empty settings file
|
||||||
QFile::rename(CONFFILE, SETTINGSFILE);
|
QFile::copy(conf_file, SETTINGSFILE);
|
||||||
CONFIG->sync(); //re-sync settings structure
|
CONFIG->sync(); //re-sync settings structure
|
||||||
conf.clear(); //No config yet
|
conf.clear(); //No config yet
|
||||||
}
|
}
|
||||||
//Load the settings from the config file
|
//Load the settings from the config file
|
||||||
// - port number
|
// - port number
|
||||||
if(port==0){
|
if(port==0){
|
||||||
if(websocket){
|
if(websocket){
|
||||||
int index = conf.indexOf(QRegExp("PORT=*",Qt::CaseSensitive,QRegExp::Wildcard));
|
int index = conf.indexOf(QRegExp("PORT=*",Qt::CaseSensitive,QRegExp::Wildcard));
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
if(index>=0){ port = conf[index].section("=",1,1).toInt(&ok); }
|
if(index>=0){ port = conf[index].section("=",1,1).toInt(&ok); }
|
||||||
@@ -213,7 +213,7 @@ int main( int argc, char ** argv )
|
|||||||
int index = conf.indexOf(QRegExp("PORT_REST=*",Qt::CaseSensitive,QRegExp::Wildcard));
|
int index = conf.indexOf(QRegExp("PORT_REST=*",Qt::CaseSensitive,QRegExp::Wildcard));
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
if(index>=0){ port = conf[index].section("=",1,1).toInt(&ok); }
|
if(index>=0){ port = conf[index].section("=",1,1).toInt(&ok); }
|
||||||
if(port<=0 || !ok){ port = PORTNUMBER; }
|
if(port<=0 || !ok){ port = PORTNUMBER; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// - Blacklist options
|
// - Blacklist options
|
||||||
@@ -238,7 +238,7 @@ int main( int argc, char ** argv )
|
|||||||
rg = QRegExp("BRIDGE_CONNECTIONS_ONLY=*",Qt::CaseSensitive,QRegExp::Wildcard);
|
rg = QRegExp("BRIDGE_CONNECTIONS_ONLY=*",Qt::CaseSensitive,QRegExp::Wildcard);
|
||||||
if(!conf.filter(rg).isEmpty()){
|
if(!conf.filter(rg).isEmpty()){
|
||||||
BRIDGE_ONLY = conf.filter(rg).first().section("=",1,1).simplified().toLower()=="true";
|
BRIDGE_ONLY = conf.filter(rg).first().section("=",1,1).simplified().toLower()=="true";
|
||||||
}
|
}
|
||||||
|
|
||||||
//Setup the log file
|
//Setup the log file
|
||||||
LogManager::checkLogDir(); //ensure the logging directory exists
|
LogManager::checkLogDir(); //ensure the logging directory exists
|
||||||
@@ -254,18 +254,17 @@ int main( int argc, char ** argv )
|
|||||||
}
|
}
|
||||||
logfile.open(QIODevice::WriteOnly | QIODevice::Append);
|
logfile.open(QIODevice::WriteOnly | QIODevice::Append);
|
||||||
qInstallMessageHandler(MessageOutput);
|
qInstallMessageHandler(MessageOutput);
|
||||||
|
|
||||||
//Connect the background classes
|
//Connect the background classes
|
||||||
QObject::connect(DISPATCHER, SIGNAL(DispatchEvent(QJsonObject)), EVENTS, SLOT(DispatchEvent(QJsonObject)) );
|
QObject::connect(DISPATCHER, SIGNAL(DispatchEvent(QJsonObject)), EVENTS, SLOT(DispatchEvent(QJsonObject)) );
|
||||||
QObject::connect(DISPATCHER, SIGNAL(DispatchStarting(QString)), EVENTS, SLOT(DispatchStarting(QString)) );
|
QObject::connect(DISPATCHER, SIGNAL(DispatchStarting(QString)), EVENTS, SLOT(DispatchStarting(QString)) );
|
||||||
|
|
||||||
//Create the daemon
|
//Create the daemon
|
||||||
qDebug() << "Starting the PC-BSD sysadm server...." << (websocket ? "(WebSocket)" : "(TCP)");
|
qDebug() << "Starting the sysadm server...." << (websocket ? "(WebSocket)" : "(TCP)");
|
||||||
WebServer *w = new WebServer();
|
WebServer *w = new WebServer();
|
||||||
//Start the daemon
|
//Start the daemon
|
||||||
int ret = 1; //error return value
|
int ret = 1; //error return value
|
||||||
if( w->startServer(port, websocket) ){
|
if( w->startServer(port, websocket) ){
|
||||||
qDebug() << " - Configuration File:" << CONFIG->fileName();
|
//qDebug() << " - Configuration File:" << CONFIG->fileName();
|
||||||
QThread TBACK, TBACK2;
|
QThread TBACK, TBACK2;
|
||||||
EVENTS->moveToThread(&TBACK);
|
EVENTS->moveToThread(&TBACK);
|
||||||
DISPATCHER->moveToThread(&TBACK2);
|
DISPATCHER->moveToThread(&TBACK2);
|
||||||
@@ -283,7 +282,7 @@ int main( int argc, char ** argv )
|
|||||||
//Cleanup any globals
|
//Cleanup any globals
|
||||||
delete CONFIG;
|
delete CONFIG;
|
||||||
logfile.close();
|
logfile.close();
|
||||||
|
|
||||||
//Return
|
//Return
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,3 +40,10 @@ INSTALLS += target scripts
|
|||||||
QMAKE_LIBDIR = /usr/local/lib/qt5 /usr/local/lib
|
QMAKE_LIBDIR = /usr/local/lib/qt5 /usr/local/lib
|
||||||
INCLUDEPATH += /usr/local/include
|
INCLUDEPATH += /usr/local/include
|
||||||
LIBS += -L/usr/local/lib -lpam -lutil -lssl -lcrypto
|
LIBS += -L/usr/local/lib -lpam -lutil -lssl -lcrypto
|
||||||
|
|
||||||
|
#Some conf to redirect intermediate stuff in separate dirs
|
||||||
|
UI_DIR=./.build/ui/
|
||||||
|
MOC_DIR=./.build/moc/
|
||||||
|
OBJECTS_DIR=./.build/obj
|
||||||
|
RCC_DIR=./.build/rcc
|
||||||
|
QMAKE_DISTCLEAN += -r ./.build
|
||||||
|
|||||||
Reference in New Issue
Block a user