Added deamon mode.
This commit is contained in:
@@ -32,6 +32,8 @@ install: bin/growcontrold
|
||||
mkdir -p /opt/growcontrol/bin
|
||||
mkdir -p /opt/growcontrol/log
|
||||
cp bin/growcontrold /opt/growcontrol/bin
|
||||
cp -r config /opt/growcontrol
|
||||
|
||||
uninstall:
|
||||
rm -rf /opt/growcontrol/bin/growcontrold
|
||||
rm -rf /opt/growcontrol/config
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
# DEBUG < INFO < NOTICE < WARN < ERROR < CRIT < ALERT < FATAL = EMERG
|
||||
|
||||
log4j.rootCategory=INFO, logAppender
|
||||
|
||||
#log4j.appender.logAppender=org.apache.log4j.ConsoleAppender
|
||||
#log4j.appender.logAppender.Target= System.err
|
||||
log4j.appender.logAppender=org.apache.log4j.FileAppender
|
||||
log4j.appender.logAppender.fileName=/opt/growcontrol/log/growcontrol.log
|
||||
|
||||
log4j.appender.logAppender.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.logAppender.layout.ConversionPattern=%d [%p] %m%n
|
||||
#log4j.appender.logAppender.layout=org.apache.log4j.BasicLayout
|
||||
+16
-2
@@ -10,6 +10,10 @@
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
namespace growcontrol {
|
||||
|
||||
@@ -38,7 +42,7 @@ bool GrowControl::connect(std::string host , uint16_t port, bool retry) {
|
||||
logger << log4cpp::Priority::INFO << "Successfully connected to brickd ("
|
||||
<< tfConnection.getHost() << ":" << tfConnection.getPort() << ").";
|
||||
}
|
||||
} while (retry && !breakFlag);
|
||||
} while (retry && !breakFlag && mainLoopFlag);
|
||||
return breakFlag;
|
||||
}
|
||||
|
||||
@@ -103,6 +107,8 @@ void GrowControl::newDeviceCallback(TfConnection& conn, TfDevice& device) {
|
||||
&& device.getDeviceState() == TfDeviceState::AVAILABLE ) {
|
||||
io16Bricklet = (TfIO16Bricklet*)&device;
|
||||
io16Bricklet->connect();
|
||||
io16Bricklet->setPortConfiguration('a', 0x7F, 'o', false);
|
||||
io16Bricklet->setPort('a', 1);
|
||||
logger << log4cpp::Priority::INFO << "Added io16 device " << device.getDeviceName(true) << ".";
|
||||
}
|
||||
break;
|
||||
@@ -204,6 +210,12 @@ int GrowControl::getFan1() {
|
||||
}
|
||||
|
||||
|
||||
void GrowControl::shutdownController() {
|
||||
std::lock_guard<std::mutex> lock(controlMutex);
|
||||
mainLoopFlag = false;
|
||||
}
|
||||
|
||||
|
||||
void GrowControl::mainLoop() {
|
||||
|
||||
while (mainLoopFlag) {
|
||||
@@ -241,7 +253,9 @@ void GrowControl::mainLoop() {
|
||||
|
||||
lcd.controlMainLoopCallback(sensorValues);
|
||||
|
||||
sleep(sleepDuration);
|
||||
if (mainLoopFlag) {
|
||||
sleep(sleepDuration);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -72,6 +72,8 @@ public:
|
||||
double getHum1();
|
||||
|
||||
int getFan1();
|
||||
|
||||
void shutdownController();
|
||||
};
|
||||
|
||||
} /* namespace growcontrol */
|
||||
|
||||
+49
-39
@@ -101,50 +101,60 @@ void IPCManager::workerThreadFunc(IPCManager* obj, int socket, std::thread* self
|
||||
IPCManager::IPCManager() {}
|
||||
|
||||
void IPCManager::init(GrowControl& growControl, std::string socketPath) {
|
||||
this->growControl = &growControl;
|
||||
this->socketPath = socketPath;
|
||||
// Create Socket
|
||||
if ((socketFD = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
||||
logger << log4cpp::Priority::ERROR << "Could not create socket";
|
||||
throw GCException("Could not create socket", GCErrorCode::OTHER_ERROR);
|
||||
if (!configFlag) {
|
||||
this->growControl = &growControl;
|
||||
this->socketPath = socketPath;
|
||||
// Create Socket
|
||||
if ((socketFD = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
||||
logger << log4cpp::Priority::ERROR << "Could not create socket";
|
||||
throw GCException("Could not create socket", GCErrorCode::OTHER_ERROR);
|
||||
}
|
||||
// Create address struct
|
||||
struct sockaddr_un local;
|
||||
local.sun_family = AF_UNIX;
|
||||
strncpy(local.sun_path, socketPath.c_str(), sizeof(local.sun_path));
|
||||
// Unlink the socket path (remove possible remains?)
|
||||
unlink(local.sun_path);
|
||||
// bind socket
|
||||
if (bind(socketFD, (struct sockaddr *)&local, sizeof(local)) == -1) {
|
||||
logger << log4cpp::Priority::ERROR << "Could not bind socket";
|
||||
throw GCException("Could not bind socket", GCErrorCode::OTHER_ERROR);
|
||||
}
|
||||
// mark as listen connection
|
||||
if (listen(socketFD, 5) == -1) {
|
||||
logger << log4cpp::Priority::ERROR << "Could not switch socket to accepting mode";
|
||||
throw GCException("Could not switch socket to accepting mode", GCErrorCode::OTHER_ERROR);
|
||||
}
|
||||
logger << log4cpp::Priority::INFO << "Successfully created new ipc socket " << socketPath << ".";
|
||||
listenerThreadFlag = true;
|
||||
listenerThread = new std::thread(listenerThreadFunc, this);
|
||||
configFlag = true;
|
||||
}
|
||||
// Create address struct
|
||||
struct sockaddr_un local;
|
||||
local.sun_family = AF_UNIX;
|
||||
strncpy(local.sun_path, socketPath.c_str(), sizeof(local.sun_path));
|
||||
// Unlink the socket path (remove possible remains?)
|
||||
unlink(local.sun_path);
|
||||
// bind socket
|
||||
if (bind(socketFD, (struct sockaddr *)&local, sizeof(local)) == -1) {
|
||||
logger << log4cpp::Priority::ERROR << "Could not bind socket";
|
||||
throw GCException("Could not bind socket", GCErrorCode::OTHER_ERROR);
|
||||
}
|
||||
// mark as listen connection
|
||||
if (listen(socketFD, 5) == -1) {
|
||||
logger << log4cpp::Priority::ERROR << "Could not switch socket to accepting mode";
|
||||
throw GCException("Could not switch socket to accepting mode", GCErrorCode::OTHER_ERROR);
|
||||
}
|
||||
logger << log4cpp::Priority::INFO << "Successfully created new ipc socket " << socketPath << ".";
|
||||
listenerThreadFlag = true;
|
||||
listenerThread = new std::thread(listenerThreadFunc, this);
|
||||
}
|
||||
|
||||
IPCManager::~IPCManager() {
|
||||
if (socketFD > 0) {
|
||||
close(socketFD);
|
||||
unlink(socketPath.c_str());
|
||||
}
|
||||
if (listenerThread != nullptr) {
|
||||
listenerThreadFlag = false;
|
||||
listenerThread->join();
|
||||
delete listenerThread;
|
||||
}
|
||||
std::set<std::thread*> workers(workerThreads);
|
||||
for (auto w : workers) {
|
||||
w->join();
|
||||
delete w;
|
||||
}
|
||||
shutdown();
|
||||
}
|
||||
|
||||
|
||||
void IPCManager::shutdown() {
|
||||
if (configFlag) {
|
||||
if (socketFD > 0) {
|
||||
close(socketFD);
|
||||
unlink(socketPath.c_str());
|
||||
}
|
||||
if (listenerThread != nullptr) {
|
||||
listenerThreadFlag = false;
|
||||
listenerThread->join();
|
||||
delete listenerThread;
|
||||
}
|
||||
std::set<std::thread*> workers(workerThreads);
|
||||
for (auto w : workers) {
|
||||
w->join();
|
||||
delete w;
|
||||
}
|
||||
configFlag = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -28,11 +28,14 @@ private:
|
||||
std::thread* listenerThread = nullptr;
|
||||
bool listenerThreadFlag = false;
|
||||
std::set<std::thread*> workerThreads;
|
||||
bool configFlag = false;
|
||||
|
||||
public:
|
||||
IPCManager();
|
||||
virtual ~IPCManager();
|
||||
|
||||
void shutdown();
|
||||
|
||||
void init(GrowControl& growControl, std::string socketPath);
|
||||
|
||||
static void listenerThreadFunc(IPCManager* obj);
|
||||
|
||||
@@ -5,3 +5,4 @@ SRC_FILES += src/main.cpp \
|
||||
src/IPCManager.cpp
|
||||
|
||||
include src/lcdpages/config.mk
|
||||
include src/third-party/config.mk
|
||||
|
||||
+157
-9
@@ -7,31 +7,179 @@
|
||||
|
||||
#include <TfCPPsimple.h>
|
||||
#include "GrowControl.h"
|
||||
#include "GCException.h"
|
||||
#include "IPCManager.h"
|
||||
#include "third-party/daemon.h"
|
||||
#include "third-party/pidfile.h"
|
||||
#include <log4cpp/Category.hh>
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
||||
|
||||
using namespace tfcppsimple;
|
||||
using namespace growcontrol;
|
||||
|
||||
static log4cpp::Category& logger = log4cpp::Category::getInstance("growcontrol");
|
||||
|
||||
#define HOST "localhost"
|
||||
#define PORT 4223
|
||||
std::string pidFile = "/var/run/growcontrold.pid";
|
||||
std::string socketPath = "/var/run/growcontrol.socket";
|
||||
std::string log4cppConfig = "log4cpp.config";
|
||||
std::string host = "localhost";
|
||||
uint16_t port = 4223;
|
||||
bool daemonMode = false;
|
||||
int pid_fd = 0;
|
||||
|
||||
GrowControl controller;
|
||||
IPCManager ipcManager;
|
||||
|
||||
bool termSignalCaught = false;
|
||||
|
||||
|
||||
|
||||
void signalHandler(int signum) {
|
||||
signal (signum, signalHandler);
|
||||
switch (signum) {
|
||||
case SIGHUP:
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
logger << log4cpp::Priority::WARN << "Caught term signal, exiting ...";
|
||||
termSignalCaught = true;
|
||||
controller.shutdownController();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void printUsage(std::ostream& stream, std::string name) {
|
||||
stream << "Usage: " << name << " [-d] [-pid pid-file] [-s socket-path] [-l log4cpp-config] [-h host] [-p port]" << std::endl
|
||||
<< "\t-d ... daemon mode" << std::endl
|
||||
<< "\t-pid ... pid-file" << std::endl
|
||||
<< "\t-s ... path of ipc socket" << std::endl
|
||||
<< "\t-l ... path to log4cpp config file" << std::endl
|
||||
<< "\t-h ... brickd address" << std::endl
|
||||
<< "\t-p ... brickd port" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
TfUtils::configureLog4CPP("log4cpp.config");
|
||||
controller.connect(HOST, PORT);
|
||||
sleep(2);
|
||||
try {
|
||||
ipcManager.init(controller, "/tmp/growcontrol.socket");
|
||||
} catch (GCException &e) {
|
||||
|
||||
for (int t = 1; t < argc; t++) {
|
||||
if (strcmp(argv[t], "-d") == 0) {
|
||||
daemonMode = true;
|
||||
} else if (strcmp(argv[t], "--help") == 0) {
|
||||
printUsage(std::cerr, argv[0]);
|
||||
exit(0);
|
||||
} else if (strcmp(argv[t], "-pid") == 0) {
|
||||
if (t+1 < argc && argv[t+1][0] != '-') {
|
||||
t++;
|
||||
pidFile = argv[t];
|
||||
} else {
|
||||
std::cerr << "Option -pid is missing an argument." << std::endl << std::endl;
|
||||
printUsage(std::cerr, argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
} else if (strcmp(argv[t], "-s") == 0) {
|
||||
if (t+1 < argc && argv[t+1][0] != '-') {
|
||||
t++;
|
||||
socketPath = argv[t];
|
||||
} else {
|
||||
std::cerr << "Option -s is missing an argument." << std::endl << std::endl;
|
||||
printUsage(std::cerr, argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
} else if (strcmp(argv[t], "-l") == 0) {
|
||||
if (t+1 < argc && argv[t+1][0] != '-') {
|
||||
t++;
|
||||
log4cppConfig = argv[t];
|
||||
} else {
|
||||
std::cerr << "Option -l is missing an argument." << std::endl << std::endl;
|
||||
printUsage(std::cerr, argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
} else if (strcmp(argv[t], "-h") == 0) {
|
||||
if (t+1 < argc && argv[t+1][0] != '-') {
|
||||
t++;
|
||||
host = argv[t];
|
||||
} else {
|
||||
std::cerr << "Option -h is missing an argument." << std::endl << std::endl;
|
||||
printUsage(std::cerr, argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
} else if (strcmp(argv[t], "-p") == 0) {
|
||||
if (t+1 < argc && argv[t+1][0] != '-') {
|
||||
t++;
|
||||
port = std::atoi(argv[t]);
|
||||
if (port == 0) {
|
||||
std::cerr << "Option -p has invalid argument \"" << argv[t] << "\"." << std::endl << std::endl;
|
||||
printUsage(std::cerr, argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Option -p is missing an argument." << std::endl << std::endl;
|
||||
printUsage(std::cerr, argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Unknown argument \"" << argv[t] << "\"." << std::endl << std::endl;
|
||||
printUsage(std::cerr, argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
TfUtils::configureLog4CPP(log4cppConfig);
|
||||
|
||||
logger << log4cpp::Priority::INFO << "Daemon Mode: " << daemonMode;
|
||||
logger << log4cpp::Priority::INFO << "Pid-File: " << pidFile;
|
||||
logger << log4cpp::Priority::INFO << "socket-path: " << socketPath;
|
||||
logger << log4cpp::Priority::INFO << "log4cpp-config: " << log4cppConfig;
|
||||
logger << log4cpp::Priority::INFO << "Brickd-Address: " << host << ":" << port;
|
||||
|
||||
if (daemonMode) {
|
||||
pid_fd = daemon_start(pidFile.c_str());
|
||||
} else {
|
||||
pid_fd = pidfile_acquire(pidFile.c_str(), getpid());
|
||||
}
|
||||
|
||||
if (pid_fd >= 0) {
|
||||
|
||||
signal(SIGTERM, signalHandler);
|
||||
signal(SIGINT, signalHandler);
|
||||
signal(SIGHUP, signalHandler);
|
||||
|
||||
controller.connect(host, port);
|
||||
|
||||
if (!termSignalCaught) {
|
||||
sleep(2);
|
||||
try {
|
||||
ipcManager.init(controller, socketPath);
|
||||
} catch (GCException &e) {
|
||||
}
|
||||
|
||||
controller.mainLoop();
|
||||
|
||||
logger << log4cpp::Priority::WARN << "Shutting down ipc ...";
|
||||
|
||||
ipcManager.shutdown();
|
||||
}
|
||||
|
||||
} else {
|
||||
logger << log4cpp::Priority::WARN << "Problems while forking/writing pid-file.";
|
||||
}
|
||||
|
||||
logger << log4cpp::Priority::WARN << "Shutting down ...";
|
||||
|
||||
if (pid_fd >= 0) {
|
||||
pidfile_release(pidFile.c_str(), pid_fd);
|
||||
}
|
||||
controller.mainLoop();
|
||||
|
||||
}
|
||||
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
|
||||
SRC_FILES += src/third-party/pidfile.cpp \
|
||||
src/third-party/daemon.cpp
|
||||
Vendored
+209
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* brickd
|
||||
* Copyright (C) 2012-2013 Matthias Bolte <matthias@tinkerforge.com>
|
||||
*
|
||||
* main_linux.c: Brick Daemon starting point for Linux
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include "pidfile.h"
|
||||
#include <log4cpp/Category.hh>
|
||||
|
||||
static log4cpp::Category& logger = log4cpp::Category::getInstance("growcontrol");
|
||||
|
||||
static int daemon_parent(pid_t child, int status_read, const char* _pid_filename) {
|
||||
int8_t status = -1;
|
||||
ssize_t rc;
|
||||
|
||||
// wait for first child to exit
|
||||
while (waitpid(child, NULL, 0) < 0 && errno == EINTR) {
|
||||
}
|
||||
|
||||
/*if (waitpid(pid, NULL, 0) < 0) {
|
||||
fprintf(stderr, "Could not wait for first child process to exit: %s (%d)\n",
|
||||
get_errno_name(errno), errno);
|
||||
|
||||
close(status_pipe[0]);
|
||||
|
||||
return -1;
|
||||
}*/
|
||||
|
||||
// wait for second child to start successfully
|
||||
while ((rc = read(status_read, &status, 1)) < 0 && errno == EINTR) {
|
||||
}
|
||||
|
||||
if (status < 0) {
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Could not read from status pipe: %s (%d)\n",
|
||||
strerror(errno), errno);
|
||||
}
|
||||
|
||||
close(status_read);
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
close(status_read);
|
||||
|
||||
if (status != 1) {
|
||||
if (status == 2) {
|
||||
fprintf(stderr, "Already running according to '%s'\n", _pid_filename);
|
||||
} else {
|
||||
fprintf(stderr, "Second child process exited with an error (status: %d)\n",
|
||||
status);
|
||||
}
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// exit first parent
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
int daemon_start(const char* _pid_filename) {
|
||||
int status_pipe[2];
|
||||
pid_t pid;
|
||||
int pid_fd = -1;
|
||||
int8_t status = 0;
|
||||
int null_fd = -1;
|
||||
|
||||
// create status pipe
|
||||
if (pipe(status_pipe) < 0) {
|
||||
logger << log4cpp::Priority::ERROR << "Could not create status pipe: "
|
||||
<< strerror(errno) << " (" << errno << ").";
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
|
||||
if (pid < 0) {
|
||||
logger << log4cpp::Priority::ERROR << "Could not fork first child process: "
|
||||
<< strerror(errno) << " (" << errno << ").";
|
||||
|
||||
close(status_pipe[0]);
|
||||
close(status_pipe[1]);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pid > 0) { // first parent
|
||||
close(status_pipe[1]);
|
||||
|
||||
daemon_parent(pid, status_pipe[0], _pid_filename);
|
||||
}
|
||||
|
||||
// first child, decouple from parent environment
|
||||
close(status_pipe[0]);
|
||||
|
||||
if (chdir("/") < 0) {
|
||||
logger << log4cpp::Priority::ERROR << "Could not change directory to '/': "
|
||||
<< strerror(errno) << " (" << errno << ").";
|
||||
|
||||
close(status_pipe[1]);
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// FIXME: check error
|
||||
setsid();
|
||||
umask(0);
|
||||
|
||||
pid = fork();
|
||||
|
||||
if (pid < 0) {
|
||||
logger << log4cpp::Priority::ERROR << "Could not fork second child process: "
|
||||
<< strerror(errno) << " (" << errno << ").";
|
||||
|
||||
close(status_pipe[1]);
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (pid > 0) {
|
||||
// exit second parent
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// second child, write pid
|
||||
pid_fd = pidfile_acquire(_pid_filename, getpid());
|
||||
|
||||
if (pid_fd < 0) {
|
||||
if (pid_fd < -1) {
|
||||
status = 2;
|
||||
}
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// redirect standard file descriptors
|
||||
null_fd = open("/dev/null", O_RDONLY);
|
||||
|
||||
if (null_fd < 0) {
|
||||
logger << log4cpp::Priority::ERROR << "Could not open /dev/null to redirect: "
|
||||
<< strerror(errno) << " (" << errno << ").";
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (dup2(null_fd, STDIN_FILENO) != STDIN_FILENO) {
|
||||
logger << log4cpp::Priority::ERROR << "Could not redirect stdin: "
|
||||
<< strerror(errno) << " (" << errno << ").";
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (dup2(null_fd, STDOUT_FILENO) != STDOUT_FILENO) {
|
||||
logger << log4cpp::Priority::ERROR << "Could not redirect stdout: "
|
||||
<< strerror(errno) << " (" << errno << ").";
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (dup2(null_fd, STDERR_FILENO) != STDERR_FILENO) {
|
||||
logger << log4cpp::Priority::ERROR << "Could not redirect stderr: "
|
||||
<< strerror(errno) << " (" << errno << ").";
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
status = 1;
|
||||
|
||||
cleanup:
|
||||
if (null_fd > STDERR_FILENO) {
|
||||
close(null_fd);
|
||||
}
|
||||
|
||||
while (write(status_pipe[1], &status, 1) < 0 && errno == EINTR) {
|
||||
}
|
||||
|
||||
close(status_pipe[1]);
|
||||
|
||||
return status == 1 ? pid_fd : -1;
|
||||
}
|
||||
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* daemon.h
|
||||
*
|
||||
* Created on: 16.06.2014
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#ifndef DAEMON_H_
|
||||
#define DAEMON_H_
|
||||
|
||||
|
||||
int daemon_start(const char* _pid_filename);
|
||||
|
||||
|
||||
#endif /* DAEMON_H_ */
|
||||
Vendored
+112
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* brickd
|
||||
* Copyright (C) 2012-2013 Matthias Bolte <matthias@tinkerforge.com>
|
||||
*
|
||||
* pidfile.c: PID file specific functions
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* this functions realize a flock'ed PID file.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "pidfile.h"
|
||||
|
||||
#include <log4cpp/Category.hh>
|
||||
|
||||
static log4cpp::Category& logger = log4cpp::Category::getInstance("growcontrol");
|
||||
|
||||
int pidfile_acquire(const char *filename, pid_t pid) {
|
||||
int fd = -1;
|
||||
struct stat stat1;
|
||||
struct stat stat2;
|
||||
struct flock flock;
|
||||
char buffer[64];
|
||||
|
||||
for (;;) {
|
||||
fd = open(filename, O_WRONLY | O_CREAT, 0644);
|
||||
|
||||
if (fd < 0) {
|
||||
logger << log4cpp::Priority::ERROR << "Could not open PID file '" << filename << "': "
|
||||
<< strerror(errno) << " (" << errno << ").";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fstat(fd, &stat1) < 0) {
|
||||
logger << log4cpp::Priority::ERROR << "Could not get status of PID file '" << filename << "': "
|
||||
<< strerror(errno) << " (" << errno << ").";
|
||||
close(fd);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
flock.l_type = F_WRLCK;
|
||||
flock.l_whence = SEEK_SET;
|
||||
flock.l_start = 0;
|
||||
flock.l_len = 1;
|
||||
|
||||
if (fcntl(fd, F_SETLK, &flock) < 0) {
|
||||
if (errno != EAGAIN) {
|
||||
logger << log4cpp::Priority::ERROR << "Could not lock PID file '" << filename << "': "
|
||||
<< strerror(errno) << " (" << errno << ").";
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return errno == EAGAIN ? -2 : -1;
|
||||
}
|
||||
|
||||
if (stat(filename, &stat2) < 0) {
|
||||
close(fd);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (stat1.st_ino != stat2.st_ino) {
|
||||
close(fd);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "%lld", (long long)pid);
|
||||
|
||||
if (write(fd, buffer, strlen(buffer)) < 0) {
|
||||
logger << log4cpp::Priority::ERROR << "Could not write to PID file '" << filename << "': "
|
||||
<< strerror(errno) << " (" << errno << ").";
|
||||
|
||||
close(fd);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
void pidfile_release(const char *filename, int fd) {
|
||||
unlink(filename);
|
||||
close(fd);
|
||||
}
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* brickd
|
||||
* Copyright (C) 2012-2013 Matthias Bolte <matthias@tinkerforge.com>
|
||||
*
|
||||
* pidfile.h: PID file specific functions
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef BRICKD_PIDFILE_H
|
||||
#define BRICKD_PIDFILE_H
|
||||
|
||||
int pidfile_acquire(const char *filename, pid_t pid);
|
||||
void pidfile_release(const char *filename, int fd);
|
||||
|
||||
#endif // BRICKD_PIDFILE_H
|
||||
Reference in New Issue
Block a user