Windows: monitor, reexec, pinging process. Not done yet.
This commit is contained in:
parent
266967bea7
commit
497b61e017
@ -567,7 +567,6 @@ bool startMonitor(RclConfig *conf, int opts)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
// Check for a config change
|
||||
if (!(opts & RCLMON_NOCONFCHECK) && o_reexec && conf->sourceChanged()) {
|
||||
LOGDEB("Rclmonprc: config changed, reexecuting myself\n");
|
||||
@ -577,7 +576,6 @@ bool startMonitor(RclConfig *conf, int opts)
|
||||
o_reexec->removeArg("-n");
|
||||
o_reexec->reexec();
|
||||
}
|
||||
#endif // ! _WIN32
|
||||
}
|
||||
LOGDEB("Rclmonprc: calling queue setTerminate\n");
|
||||
rclEQ.setTerminate();
|
||||
|
||||
@ -103,9 +103,7 @@ static struct option long_options[] = {
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
#ifndef _WIN32
|
||||
ReExec *o_reexec;
|
||||
#endif
|
||||
|
||||
// Globals for atexit cleanup
|
||||
static ConfIndexer *confindexer;
|
||||
@ -458,25 +456,19 @@ static void lockorexit(Pidfile *pidfile, RclConfig *config)
|
||||
if (pid > 0) {
|
||||
cerr << "Can't become exclusive indexer: " << pidfile->getreason()
|
||||
<< ". Return (other pid?): " << pid << endl;
|
||||
#ifndef _WIN32
|
||||
// Have a look at the status file. If the other process is
|
||||
// a monitor we can tell it to start an incremental pass
|
||||
// by touching the configuration file
|
||||
DbIxStatus status;
|
||||
readIdxStatus(config, status);
|
||||
if (status.hasmonitor) {
|
||||
string cmd("touch ");
|
||||
string path = path_cat(config->getConfDir(), "recoll.conf");
|
||||
cmd += path;
|
||||
int status;
|
||||
if ((status = system(cmd.c_str()))) {
|
||||
cerr << cmd << " failed with status " << status << endl;
|
||||
if (!path_utimes(path, nullptr)) {
|
||||
cerr << "Could not notify indexer" << endl;
|
||||
} else {
|
||||
cerr << "Monitoring indexer process was notified of "
|
||||
"indexing request\n";
|
||||
cerr << "Monitoring indexer process was notified of indexing request" << endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
cerr << "Can't become exclusive indexer: " << pidfile->getreason()
|
||||
<< endl;
|
||||
@ -525,16 +517,17 @@ static void flushIdxReasons()
|
||||
static vector<const char*> argstovector(int argc, wchar_t **argv, vector<string>& storage)
|
||||
#else
|
||||
#define WARGTOSTRING(w) (w)
|
||||
static vector<const char*> argstovector(int argc, char **argv, vector<string>& storage)
|
||||
static vector<const char*> argstovector(int argc, char **argv, vector<string>& storage)
|
||||
#endif
|
||||
{
|
||||
vector<const char *> args(argc+1);
|
||||
storage.resize(argc+1);
|
||||
storage.resize(argc);
|
||||
thisprog = path_absolute(WARGTOSTRING(argv[0]));
|
||||
for (int i = 0; i < argc; i++) {
|
||||
storage[i] = WARGTOSTRING(argv[i]);
|
||||
args[i] = storage[i].c_str();
|
||||
}
|
||||
args[argc] = 0;
|
||||
return args;
|
||||
}
|
||||
|
||||
@ -556,17 +549,13 @@ int wmain(int argc, wchar_t *argv[])
|
||||
int main(int argc, char *argv[])
|
||||
#endif
|
||||
{
|
||||
#ifndef _WIN32
|
||||
// The reexec struct is used by the daemon to shed memory after
|
||||
// the initial indexing pass and to restart when the configuration
|
||||
// changes
|
||||
o_reexec = new ReExec;
|
||||
o_reexec->init(argc, argv);
|
||||
#endif
|
||||
|
||||
// Only actually useful on Windows: convert wargs to utf-8 chars
|
||||
vector<string> astore;
|
||||
vector<const char*> args = argstovector(argc, argv, astore);
|
||||
// The reexec struct is used by the daemon to shed memory after
|
||||
// the initial indexing pass and to restart when the configuration
|
||||
// changes
|
||||
o_reexec = new ReExec(astore);
|
||||
|
||||
vector<string> selpatterns;
|
||||
int sleepsecs{60};
|
||||
@ -683,10 +672,7 @@ int main(int argc, char *argv[])
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
o_reexec->atexit(cleanup);
|
||||
#endif
|
||||
|
||||
vector<string> nonexist;
|
||||
if (!checktopdirs(config, nonexist)) {
|
||||
std::cerr << "topdirs not set or only contains invalid paths.\n";
|
||||
@ -848,8 +834,8 @@ int main(int argc, char *argv[])
|
||||
Usage();
|
||||
statusUpdater()->setMonitor(true);
|
||||
if (!(op_flags&OPT_D)) {
|
||||
LOGDEB("recollindex: daemonizing\n");
|
||||
#ifndef _WIN32
|
||||
LOGDEB("recollindex: daemonizing\n");
|
||||
if (daemon(0,0) != 0) {
|
||||
addIdxReason("monitor", "daemon() failed");
|
||||
cerr << "daemon() failed, errno " << errno << endl;
|
||||
@ -895,16 +881,13 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
deleteZ(confindexer);
|
||||
#ifndef _WIN32
|
||||
o_reexec->insertArgs(vector<string>(1, "-n"));
|
||||
LOGINFO("recollindex: reexecuting with -n after initial full "
|
||||
"pass\n");
|
||||
LOGINFO("recollindex: reexecuting with -n after initial full pass\n");
|
||||
// Note that -n will be inside the reexec when we come
|
||||
// back, but the monitor will explicitly strip it before
|
||||
// starting a config change exec to ensure that we do a
|
||||
// purging pass in this latter case (full restart).
|
||||
o_reexec->reexec();
|
||||
#endif
|
||||
}
|
||||
|
||||
statusUpdater()->update(DbIxStatus::DBIXS_MONITOR, "");
|
||||
|
||||
@ -176,13 +176,15 @@ bool renameormove(const char *src, const char *dst, string &reason)
|
||||
reason += string("Chown ") + dst + "Error : " + strerror(errno);
|
||||
}
|
||||
}
|
||||
struct timeval times[2];
|
||||
#endif
|
||||
|
||||
struct path_timeval times[2];
|
||||
times[0].tv_sec = st.st_atime;
|
||||
times[0].tv_usec = 0;
|
||||
times[1].tv_sec = st.st_mtime;
|
||||
times[1].tv_usec = 0;
|
||||
utimes(dst, times);
|
||||
#endif
|
||||
path_utimes(dst, times);
|
||||
|
||||
// All ok, get rid of origin
|
||||
if (!path_unlink(src)) {
|
||||
reason += string("Can't unlink ") + src + "Error : " + strerror(errno);
|
||||
|
||||
@ -1064,11 +1064,6 @@ std::string ExecCmd::waitStatusAsString(int wstatus)
|
||||
|
||||
/// ReExec class methods ///////////////////////////////////////////////////
|
||||
ReExec::ReExec(int argc, char *args[])
|
||||
{
|
||||
init(argc, args);
|
||||
}
|
||||
|
||||
void ReExec::init(int argc, char *args[])
|
||||
{
|
||||
for (int i = 0; i < argc; i++) {
|
||||
m_argv.push_back(args[i]);
|
||||
@ -1081,6 +1076,17 @@ void ReExec::init(int argc, char *args[])
|
||||
free(cd);
|
||||
}
|
||||
|
||||
ReExec::ReExec(const std::vector<std::string>& args)
|
||||
: m_argv(args)
|
||||
{
|
||||
m_cfd = open(".", 0);
|
||||
char *cd = getcwd(0, 0);
|
||||
if (cd) {
|
||||
m_curdir = cd;
|
||||
}
|
||||
free(cd);
|
||||
}
|
||||
|
||||
void ReExec::insertArgs(const vector<string>& args, int idx)
|
||||
{
|
||||
vector<string>::iterator it;
|
||||
|
||||
@ -284,7 +284,8 @@ class ReExec {
|
||||
public:
|
||||
ReExec() {}
|
||||
ReExec(int argc, char *argv[]);
|
||||
void init(int argc, char *argv[]);
|
||||
// Mostly useful with Windows and wmain: args must be utf-8
|
||||
ReExec(const std::vector<std::string>& args);
|
||||
int atexit(void (*function)(void)) {
|
||||
m_atexitfuncs.push(function);
|
||||
return 0;
|
||||
@ -302,7 +303,7 @@ public:
|
||||
private:
|
||||
std::vector<std::string> m_argv;
|
||||
std::string m_curdir;
|
||||
int m_cfd;
|
||||
int m_cfd{-1};
|
||||
std::string m_reason;
|
||||
std::stack<void (*)(void)> m_atexitfuncs;
|
||||
};
|
||||
|
||||
@ -100,6 +100,7 @@
|
||||
#include <direct.h>
|
||||
#include <Shlobj.h>
|
||||
#include <Stringapiset.h>
|
||||
#include <sys/utime.h>
|
||||
|
||||
#if !defined(S_IFLNK)
|
||||
#define S_IFLNK 0
|
||||
@ -152,6 +153,7 @@
|
||||
#else /* !_WIN32 -> */
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/param.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/file.h>
|
||||
@ -333,8 +335,6 @@ static bool path_isdriveabs(const string& s)
|
||||
/* Can be OR'd in to one of the above. */
|
||||
# define LOCK_NB 4 /* Don't block when locking. */
|
||||
|
||||
#include <io.h>
|
||||
|
||||
/* Determine the current size of a file. Because the other braindead
|
||||
* APIs we'll call need lower/upper 32 bit pairs, keep the file size
|
||||
* like that too.
|
||||
@ -953,6 +953,34 @@ bool path_rmdir(const std::string& path)
|
||||
return RMDIR(syspath) == 0;
|
||||
}
|
||||
|
||||
bool path_utimes(const std::string& path, struct path_timeval _tv[2])
|
||||
{
|
||||
#ifdef _WIN32
|
||||
struct _utimbuf times;
|
||||
if (nullptr == _tv) {
|
||||
times.actime = times.modtime = time(0L);
|
||||
} else {
|
||||
times.actime = _tv[0].tv_sec;
|
||||
times.modtime = _tv[1].tv_sec;
|
||||
}
|
||||
SYSPATH(path, syspath);
|
||||
return _wutime(syspath, ×) != -1;
|
||||
#else
|
||||
struct timeval tvb[2];
|
||||
if (nullptr == _tv) {
|
||||
gettimeofday(tvb, nullptr);
|
||||
tvb[1].tv_sec = tvb[0].tv_sec;
|
||||
tvb[1].tv_usec = tvb[0].tv_usec;
|
||||
} else {
|
||||
tvb[0].tv_sec = _tv[0].tv_sec;
|
||||
tvb[0].tv_usec = _tv[0].tv_usec;
|
||||
tvb[1].tv_sec = _tv[1].tv_sec;
|
||||
tvb[1].tv_usec = _tv[1].tv_usec;
|
||||
}
|
||||
return utimes(path.c_str(), tvb) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool path_streamopen(const std::string& path, int mode, std::fstream& outstream)
|
||||
{
|
||||
#if defined(_WIN32) && defined (_MSC_VER)
|
||||
@ -1462,11 +1490,35 @@ Pidfile::~Pidfile()
|
||||
this->close();
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// It appears that we can't read the locked file on Windows, so we use
|
||||
// separate files for locking and holding the data.
|
||||
static std::string pid_data_path(const std::string& path)
|
||||
{
|
||||
// Remove extension. append -data to name, add back extension.
|
||||
auto ext = path_suffix(path);
|
||||
auto spath = path_cat(path_getfather(path), path_basename(path, ext));
|
||||
if (spath.back() == '.')
|
||||
spath.pop_back();
|
||||
if (!ext.empty())
|
||||
spath += std::string("-data") + "." + ext;
|
||||
return spath;
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
int Pidfile::read_pid()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// It appears that we can't read the locked file on Windows, so use an aux file
|
||||
auto path = pid_data_path(m_path);
|
||||
SYSPATH(path, syspath);
|
||||
#else
|
||||
SYSPATH(m_path, syspath);
|
||||
#endif
|
||||
int fd = OPEN(syspath, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
if (errno != ENOENT)
|
||||
m_reason = "Open RDONLY failed: [" + m_path + "]: " + strerror(errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1474,12 +1526,14 @@ int Pidfile::read_pid()
|
||||
int i = read(fd, buf, sizeof(buf) - 1);
|
||||
::close(fd);
|
||||
if (i <= 0) {
|
||||
m_reason = "Read failed: [" + m_path + "]: " + strerror(errno);
|
||||
return -1;
|
||||
}
|
||||
buf[i] = '\0';
|
||||
char *endptr;
|
||||
int pid = strtol(buf, &endptr, 10);
|
||||
if (endptr != &buf[i]) {
|
||||
m_reason = "Bad pid contents: [" + m_path + "]: " + strerror(errno);
|
||||
return - 1;
|
||||
}
|
||||
return pid;
|
||||
@ -1501,8 +1555,8 @@ int Pidfile::flopen()
|
||||
lockdata.l_whence = SEEK_SET;
|
||||
if (fcntl(m_fd, F_SETLK, &lockdata) != 0) {
|
||||
int serrno = errno;
|
||||
this->close()
|
||||
errno = serrno;
|
||||
this->close();
|
||||
errno = serrno;
|
||||
m_reason = "fcntl lock failed";
|
||||
return -1;
|
||||
}
|
||||
@ -1538,18 +1592,33 @@ int Pidfile::open()
|
||||
|
||||
int Pidfile::write_pid()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// It appears that we can't read the locked file on Windows, so use an aux file
|
||||
auto path = pid_data_path(m_path);
|
||||
SYSPATH(path, syspath);
|
||||
int fd;
|
||||
if ((fd = OPEN(syspath, O_RDWR | O_CREAT, 0644)) == -1) {
|
||||
m_reason = "Open failed: [" + path + "]: " + strerror(errno);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
int fd = m_fd;
|
||||
#endif
|
||||
/* truncate to allow multiple calls */
|
||||
if (ftruncate(m_fd, 0) == -1) {
|
||||
if (ftruncate(fd, 0) == -1) {
|
||||
m_reason = "ftruncate failed";
|
||||
return -1;
|
||||
}
|
||||
char pidstr[20];
|
||||
sprintf(pidstr, "%u", int(getpid()));
|
||||
lseek(m_fd, 0, 0);
|
||||
if (::write(m_fd, pidstr, strlen(pidstr)) != (PATHUT_SSIZE_T)strlen(pidstr)) {
|
||||
lseek(fd, 0, 0);
|
||||
if (::write(fd, pidstr, strlen(pidstr)) != (PATHUT_SSIZE_T)strlen(pidstr)) {
|
||||
m_reason = "write failed";
|
||||
return -1;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
close(fd);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -143,8 +143,7 @@ struct PathStat {
|
||||
uint64_t pst_blocks;
|
||||
uint64_t pst_blksize;
|
||||
};
|
||||
extern int path_fileprops(const std::string path, struct PathStat *stp,
|
||||
bool follow = true);
|
||||
extern int path_fileprops(const std::string path, struct PathStat *stp, bool follow = true);
|
||||
|
||||
|
||||
/// Return separator for PATH environment variable
|
||||
@ -171,8 +170,7 @@ private:
|
||||
};
|
||||
|
||||
/// Dump directory
|
||||
extern bool listdir(const std::string& dir, std::string& reason,
|
||||
std::set<std::string>& entries);
|
||||
extern bool listdir(const std::string& dir, std::string& reason, std::set<std::string>& entries);
|
||||
|
||||
/** A small wrapper around statfs et al, to return percentage of disk
|
||||
occupation
|
||||
@ -189,7 +187,15 @@ bool path_chdir(const std::string& path);
|
||||
std::string path_cwd();
|
||||
bool path_unlink(const std::string& path);
|
||||
bool path_rmdir(const std::string& path);
|
||||
|
||||
|
||||
// Setting file times. Windows defines timeval in winsock2.h but it seems safer to use local def
|
||||
// Also on Windows, we use _wutime and ignore the tv_usec part.
|
||||
typedef struct path_timeval {
|
||||
long tv_sec;
|
||||
long tv_usec;
|
||||
} path_timeval;
|
||||
bool path_utimes(const std::string& path, struct path_timeval times[2]);
|
||||
|
||||
/* Open file, trying to do the right thing with non-ASCII paths on
|
||||
* Windows, where it only works with MSVC at the moment if the path is
|
||||
* not ASCII, because it uses fstream(wchar_t*), which is an MSVC
|
||||
@ -200,12 +206,10 @@ bool path_rmdir(const std::string& path);
|
||||
*
|
||||
* @param path an utf-8 file path.
|
||||
* @param mode is an std::fstream mode (ios::in etc.) */
|
||||
extern bool path_streamopen(
|
||||
const std::string& path, int mode, std::fstream& outstream);
|
||||
extern bool path_streamopen(const std::string& path, int mode, std::fstream& outstream);
|
||||
|
||||
/// Encode according to rfc 1738
|
||||
extern std::string url_encode(const std::string& url,
|
||||
std::string::size_type offs = 0);
|
||||
extern std::string url_encode(const std::string& url, std::string::size_type offs = 0);
|
||||
extern std::string url_decode(const std::string& encoded);
|
||||
//// Convert to file path if url is like file://. This modifies the
|
||||
//// input (and returns a copy for convenience)
|
||||
|
||||
@ -1168,3 +1168,87 @@ std::string ExecCmd::waitStatusAsString(int wstatus)
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
|
||||
///////////// ReExec class methods.
|
||||
ReExec::ReExec(int argc, char *args[])
|
||||
{
|
||||
for (int i = 0; i < argc; i++) {
|
||||
m_argv.push_back(args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
ReExec::ReExec(const std::vector<std::string>& args)
|
||||
: m_argv(args)
|
||||
{
|
||||
}
|
||||
|
||||
void ReExec::insertArgs(const vector<string>& args, int idx)
|
||||
{
|
||||
vector<string>::iterator it;
|
||||
unsigned int cmpoffset = (unsigned int) - 1;
|
||||
|
||||
if (idx == -1 || string::size_type(idx) >= m_argv.size()) {
|
||||
it = m_argv.end();
|
||||
if (m_argv.size() >= args.size()) {
|
||||
cmpoffset = m_argv.size() - args.size();
|
||||
}
|
||||
} else {
|
||||
it = m_argv.begin() + idx;
|
||||
if (idx + args.size() <= m_argv.size()) {
|
||||
cmpoffset = idx;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the option is not already there
|
||||
if (cmpoffset != (unsigned int) - 1) {
|
||||
bool allsame = true;
|
||||
for (unsigned int i = 0; i < args.size(); i++) {
|
||||
if (m_argv[cmpoffset + i] != args[i]) {
|
||||
allsame = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allsame) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_argv.insert(it, args.begin(), args.end());
|
||||
}
|
||||
|
||||
void ReExec::removeArg(const string& arg)
|
||||
{
|
||||
for (vector<string>::iterator it = m_argv.begin(); it != m_argv.end(); it++) {
|
||||
if (*it == arg) {
|
||||
it = m_argv.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReExec::reexec()
|
||||
{
|
||||
// Execute the atexit funcs
|
||||
while (!m_atexitfuncs.empty()) {
|
||||
(m_atexitfuncs.top())();
|
||||
m_atexitfuncs.pop();
|
||||
}
|
||||
|
||||
// Allocate arg vector (1 more for final 0)
|
||||
typedef const wchar_t *Ccharp;
|
||||
Ccharp *argv;
|
||||
argv = (Ccharp *)malloc((m_argv.size() + 1) * sizeof(wchar_t *));
|
||||
if (argv == 0) {
|
||||
LOGERR("ExecCmd::doexec: malloc() failed. errno " << errno << "\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Fill up argv
|
||||
int i = 0;
|
||||
std::vector<std::unique_ptr<wchar_t[]>> ptrs;
|
||||
for (const auto& arg: m_argv) {
|
||||
ptrs.push_back(utf8towchar(arg));
|
||||
argv[i++] = ptrs.back().get();
|
||||
}
|
||||
argv[i] = nullptr;
|
||||
_wexecvp(argv[0], argv);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user