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
|
// Check for a config change
|
||||||
if (!(opts & RCLMON_NOCONFCHECK) && o_reexec && conf->sourceChanged()) {
|
if (!(opts & RCLMON_NOCONFCHECK) && o_reexec && conf->sourceChanged()) {
|
||||||
LOGDEB("Rclmonprc: config changed, reexecuting myself\n");
|
LOGDEB("Rclmonprc: config changed, reexecuting myself\n");
|
||||||
@ -577,7 +576,6 @@ bool startMonitor(RclConfig *conf, int opts)
|
|||||||
o_reexec->removeArg("-n");
|
o_reexec->removeArg("-n");
|
||||||
o_reexec->reexec();
|
o_reexec->reexec();
|
||||||
}
|
}
|
||||||
#endif // ! _WIN32
|
|
||||||
}
|
}
|
||||||
LOGDEB("Rclmonprc: calling queue setTerminate\n");
|
LOGDEB("Rclmonprc: calling queue setTerminate\n");
|
||||||
rclEQ.setTerminate();
|
rclEQ.setTerminate();
|
||||||
|
|||||||
@ -103,9 +103,7 @@ static struct option long_options[] = {
|
|||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
ReExec *o_reexec;
|
ReExec *o_reexec;
|
||||||
#endif
|
|
||||||
|
|
||||||
// Globals for atexit cleanup
|
// Globals for atexit cleanup
|
||||||
static ConfIndexer *confindexer;
|
static ConfIndexer *confindexer;
|
||||||
@ -458,25 +456,19 @@ static void lockorexit(Pidfile *pidfile, RclConfig *config)
|
|||||||
if (pid > 0) {
|
if (pid > 0) {
|
||||||
cerr << "Can't become exclusive indexer: " << pidfile->getreason()
|
cerr << "Can't become exclusive indexer: " << pidfile->getreason()
|
||||||
<< ". Return (other pid?): " << pid << endl;
|
<< ". Return (other pid?): " << pid << endl;
|
||||||
#ifndef _WIN32
|
|
||||||
// Have a look at the status file. If the other process is
|
// Have a look at the status file. If the other process is
|
||||||
// a monitor we can tell it to start an incremental pass
|
// a monitor we can tell it to start an incremental pass
|
||||||
// by touching the configuration file
|
// by touching the configuration file
|
||||||
DbIxStatus status;
|
DbIxStatus status;
|
||||||
readIdxStatus(config, status);
|
readIdxStatus(config, status);
|
||||||
if (status.hasmonitor) {
|
if (status.hasmonitor) {
|
||||||
string cmd("touch ");
|
|
||||||
string path = path_cat(config->getConfDir(), "recoll.conf");
|
string path = path_cat(config->getConfDir(), "recoll.conf");
|
||||||
cmd += path;
|
if (!path_utimes(path, nullptr)) {
|
||||||
int status;
|
cerr << "Could not notify indexer" << endl;
|
||||||
if ((status = system(cmd.c_str()))) {
|
|
||||||
cerr << cmd << " failed with status " << status << endl;
|
|
||||||
} else {
|
} else {
|
||||||
cerr << "Monitoring indexer process was notified of "
|
cerr << "Monitoring indexer process was notified of indexing request" << endl;
|
||||||
"indexing request\n";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
cerr << "Can't become exclusive indexer: " << pidfile->getreason()
|
cerr << "Can't become exclusive indexer: " << pidfile->getreason()
|
||||||
<< endl;
|
<< endl;
|
||||||
@ -525,16 +517,17 @@ static void flushIdxReasons()
|
|||||||
static vector<const char*> argstovector(int argc, wchar_t **argv, vector<string>& storage)
|
static vector<const char*> argstovector(int argc, wchar_t **argv, vector<string>& storage)
|
||||||
#else
|
#else
|
||||||
#define WARGTOSTRING(w) (w)
|
#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
|
#endif
|
||||||
{
|
{
|
||||||
vector<const char *> args(argc+1);
|
vector<const char *> args(argc+1);
|
||||||
storage.resize(argc+1);
|
storage.resize(argc);
|
||||||
thisprog = path_absolute(WARGTOSTRING(argv[0]));
|
thisprog = path_absolute(WARGTOSTRING(argv[0]));
|
||||||
for (int i = 0; i < argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
storage[i] = WARGTOSTRING(argv[i]);
|
storage[i] = WARGTOSTRING(argv[i]);
|
||||||
args[i] = storage[i].c_str();
|
args[i] = storage[i].c_str();
|
||||||
}
|
}
|
||||||
|
args[argc] = 0;
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,17 +549,13 @@ int wmain(int argc, wchar_t *argv[])
|
|||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
#endif
|
#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
|
// Only actually useful on Windows: convert wargs to utf-8 chars
|
||||||
vector<string> astore;
|
vector<string> astore;
|
||||||
vector<const char*> args = argstovector(argc, argv, 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;
|
vector<string> selpatterns;
|
||||||
int sleepsecs{60};
|
int sleepsecs{60};
|
||||||
@ -683,10 +672,7 @@ int main(int argc, char *argv[])
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
o_reexec->atexit(cleanup);
|
o_reexec->atexit(cleanup);
|
||||||
#endif
|
|
||||||
|
|
||||||
vector<string> nonexist;
|
vector<string> nonexist;
|
||||||
if (!checktopdirs(config, nonexist)) {
|
if (!checktopdirs(config, nonexist)) {
|
||||||
std::cerr << "topdirs not set or only contains invalid paths.\n";
|
std::cerr << "topdirs not set or only contains invalid paths.\n";
|
||||||
@ -848,8 +834,8 @@ int main(int argc, char *argv[])
|
|||||||
Usage();
|
Usage();
|
||||||
statusUpdater()->setMonitor(true);
|
statusUpdater()->setMonitor(true);
|
||||||
if (!(op_flags&OPT_D)) {
|
if (!(op_flags&OPT_D)) {
|
||||||
LOGDEB("recollindex: daemonizing\n");
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
LOGDEB("recollindex: daemonizing\n");
|
||||||
if (daemon(0,0) != 0) {
|
if (daemon(0,0) != 0) {
|
||||||
addIdxReason("monitor", "daemon() failed");
|
addIdxReason("monitor", "daemon() failed");
|
||||||
cerr << "daemon() failed, errno " << errno << endl;
|
cerr << "daemon() failed, errno " << errno << endl;
|
||||||
@ -895,16 +881,13 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
deleteZ(confindexer);
|
deleteZ(confindexer);
|
||||||
#ifndef _WIN32
|
|
||||||
o_reexec->insertArgs(vector<string>(1, "-n"));
|
o_reexec->insertArgs(vector<string>(1, "-n"));
|
||||||
LOGINFO("recollindex: reexecuting with -n after initial full "
|
LOGINFO("recollindex: reexecuting with -n after initial full pass\n");
|
||||||
"pass\n");
|
|
||||||
// Note that -n will be inside the reexec when we come
|
// Note that -n will be inside the reexec when we come
|
||||||
// back, but the monitor will explicitly strip it before
|
// back, but the monitor will explicitly strip it before
|
||||||
// starting a config change exec to ensure that we do a
|
// starting a config change exec to ensure that we do a
|
||||||
// purging pass in this latter case (full restart).
|
// purging pass in this latter case (full restart).
|
||||||
o_reexec->reexec();
|
o_reexec->reexec();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
statusUpdater()->update(DbIxStatus::DBIXS_MONITOR, "");
|
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);
|
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_sec = st.st_atime;
|
||||||
times[0].tv_usec = 0;
|
times[0].tv_usec = 0;
|
||||||
times[1].tv_sec = st.st_mtime;
|
times[1].tv_sec = st.st_mtime;
|
||||||
times[1].tv_usec = 0;
|
times[1].tv_usec = 0;
|
||||||
utimes(dst, times);
|
path_utimes(dst, times);
|
||||||
#endif
|
|
||||||
// All ok, get rid of origin
|
// All ok, get rid of origin
|
||||||
if (!path_unlink(src)) {
|
if (!path_unlink(src)) {
|
||||||
reason += string("Can't unlink ") + src + "Error : " + strerror(errno);
|
reason += string("Can't unlink ") + src + "Error : " + strerror(errno);
|
||||||
|
|||||||
@ -1064,11 +1064,6 @@ std::string ExecCmd::waitStatusAsString(int wstatus)
|
|||||||
|
|
||||||
/// ReExec class methods ///////////////////////////////////////////////////
|
/// ReExec class methods ///////////////////////////////////////////////////
|
||||||
ReExec::ReExec(int argc, char *args[])
|
ReExec::ReExec(int argc, char *args[])
|
||||||
{
|
|
||||||
init(argc, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReExec::init(int argc, char *args[])
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
m_argv.push_back(args[i]);
|
m_argv.push_back(args[i]);
|
||||||
@ -1081,6 +1076,17 @@ void ReExec::init(int argc, char *args[])
|
|||||||
free(cd);
|
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)
|
void ReExec::insertArgs(const vector<string>& args, int idx)
|
||||||
{
|
{
|
||||||
vector<string>::iterator it;
|
vector<string>::iterator it;
|
||||||
|
|||||||
@ -284,7 +284,8 @@ class ReExec {
|
|||||||
public:
|
public:
|
||||||
ReExec() {}
|
ReExec() {}
|
||||||
ReExec(int argc, char *argv[]);
|
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)) {
|
int atexit(void (*function)(void)) {
|
||||||
m_atexitfuncs.push(function);
|
m_atexitfuncs.push(function);
|
||||||
return 0;
|
return 0;
|
||||||
@ -302,7 +303,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
std::vector<std::string> m_argv;
|
std::vector<std::string> m_argv;
|
||||||
std::string m_curdir;
|
std::string m_curdir;
|
||||||
int m_cfd;
|
int m_cfd{-1};
|
||||||
std::string m_reason;
|
std::string m_reason;
|
||||||
std::stack<void (*)(void)> m_atexitfuncs;
|
std::stack<void (*)(void)> m_atexitfuncs;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -100,6 +100,7 @@
|
|||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
#include <Shlobj.h>
|
#include <Shlobj.h>
|
||||||
#include <Stringapiset.h>
|
#include <Stringapiset.h>
|
||||||
|
#include <sys/utime.h>
|
||||||
|
|
||||||
#if !defined(S_IFLNK)
|
#if !defined(S_IFLNK)
|
||||||
#define S_IFLNK 0
|
#define S_IFLNK 0
|
||||||
@ -152,6 +153,7 @@
|
|||||||
#else /* !_WIN32 -> */
|
#else /* !_WIN32 -> */
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/time.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <sys/file.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. */
|
/* Can be OR'd in to one of the above. */
|
||||||
# define LOCK_NB 4 /* Don't block when locking. */
|
# define LOCK_NB 4 /* Don't block when locking. */
|
||||||
|
|
||||||
#include <io.h>
|
|
||||||
|
|
||||||
/* Determine the current size of a file. Because the other braindead
|
/* 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
|
* APIs we'll call need lower/upper 32 bit pairs, keep the file size
|
||||||
* like that too.
|
* like that too.
|
||||||
@ -953,6 +953,34 @@ bool path_rmdir(const std::string& path)
|
|||||||
return RMDIR(syspath) == 0;
|
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)
|
bool path_streamopen(const std::string& path, int mode, std::fstream& outstream)
|
||||||
{
|
{
|
||||||
#if defined(_WIN32) && defined (_MSC_VER)
|
#if defined(_WIN32) && defined (_MSC_VER)
|
||||||
@ -1462,11 +1490,35 @@ Pidfile::~Pidfile()
|
|||||||
this->close();
|
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()
|
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);
|
SYSPATH(m_path, syspath);
|
||||||
|
#endif
|
||||||
int fd = OPEN(syspath, O_RDONLY);
|
int fd = OPEN(syspath, O_RDONLY);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
|
if (errno != ENOENT)
|
||||||
|
m_reason = "Open RDONLY failed: [" + m_path + "]: " + strerror(errno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1474,12 +1526,14 @@ int Pidfile::read_pid()
|
|||||||
int i = read(fd, buf, sizeof(buf) - 1);
|
int i = read(fd, buf, sizeof(buf) - 1);
|
||||||
::close(fd);
|
::close(fd);
|
||||||
if (i <= 0) {
|
if (i <= 0) {
|
||||||
|
m_reason = "Read failed: [" + m_path + "]: " + strerror(errno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
buf[i] = '\0';
|
buf[i] = '\0';
|
||||||
char *endptr;
|
char *endptr;
|
||||||
int pid = strtol(buf, &endptr, 10);
|
int pid = strtol(buf, &endptr, 10);
|
||||||
if (endptr != &buf[i]) {
|
if (endptr != &buf[i]) {
|
||||||
|
m_reason = "Bad pid contents: [" + m_path + "]: " + strerror(errno);
|
||||||
return - 1;
|
return - 1;
|
||||||
}
|
}
|
||||||
return pid;
|
return pid;
|
||||||
@ -1501,8 +1555,8 @@ int Pidfile::flopen()
|
|||||||
lockdata.l_whence = SEEK_SET;
|
lockdata.l_whence = SEEK_SET;
|
||||||
if (fcntl(m_fd, F_SETLK, &lockdata) != 0) {
|
if (fcntl(m_fd, F_SETLK, &lockdata) != 0) {
|
||||||
int serrno = errno;
|
int serrno = errno;
|
||||||
this->close()
|
this->close();
|
||||||
errno = serrno;
|
errno = serrno;
|
||||||
m_reason = "fcntl lock failed";
|
m_reason = "fcntl lock failed";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1538,18 +1592,33 @@ int Pidfile::open()
|
|||||||
|
|
||||||
int Pidfile::write_pid()
|
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 */
|
/* truncate to allow multiple calls */
|
||||||
if (ftruncate(m_fd, 0) == -1) {
|
if (ftruncate(fd, 0) == -1) {
|
||||||
m_reason = "ftruncate failed";
|
m_reason = "ftruncate failed";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
char pidstr[20];
|
char pidstr[20];
|
||||||
sprintf(pidstr, "%u", int(getpid()));
|
sprintf(pidstr, "%u", int(getpid()));
|
||||||
lseek(m_fd, 0, 0);
|
lseek(fd, 0, 0);
|
||||||
if (::write(m_fd, pidstr, strlen(pidstr)) != (PATHUT_SSIZE_T)strlen(pidstr)) {
|
if (::write(fd, pidstr, strlen(pidstr)) != (PATHUT_SSIZE_T)strlen(pidstr)) {
|
||||||
m_reason = "write failed";
|
m_reason = "write failed";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
#ifdef _WIN32
|
||||||
|
close(fd);
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -143,8 +143,7 @@ struct PathStat {
|
|||||||
uint64_t pst_blocks;
|
uint64_t pst_blocks;
|
||||||
uint64_t pst_blksize;
|
uint64_t pst_blksize;
|
||||||
};
|
};
|
||||||
extern int path_fileprops(const std::string path, struct PathStat *stp,
|
extern int path_fileprops(const std::string path, struct PathStat *stp, bool follow = true);
|
||||||
bool follow = true);
|
|
||||||
|
|
||||||
|
|
||||||
/// Return separator for PATH environment variable
|
/// Return separator for PATH environment variable
|
||||||
@ -171,8 +170,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Dump directory
|
/// Dump directory
|
||||||
extern bool listdir(const std::string& dir, std::string& reason,
|
extern bool listdir(const std::string& dir, std::string& reason, std::set<std::string>& entries);
|
||||||
std::set<std::string>& entries);
|
|
||||||
|
|
||||||
/** A small wrapper around statfs et al, to return percentage of disk
|
/** A small wrapper around statfs et al, to return percentage of disk
|
||||||
occupation
|
occupation
|
||||||
@ -189,7 +187,15 @@ bool path_chdir(const std::string& path);
|
|||||||
std::string path_cwd();
|
std::string path_cwd();
|
||||||
bool path_unlink(const std::string& path);
|
bool path_unlink(const std::string& path);
|
||||||
bool path_rmdir(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
|
/* 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
|
* 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
|
* 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 path an utf-8 file path.
|
||||||
* @param mode is an std::fstream mode (ios::in etc.) */
|
* @param mode is an std::fstream mode (ios::in etc.) */
|
||||||
extern bool path_streamopen(
|
extern bool path_streamopen(const std::string& path, int mode, std::fstream& outstream);
|
||||||
const std::string& path, int mode, std::fstream& outstream);
|
|
||||||
|
|
||||||
/// Encode according to rfc 1738
|
/// Encode according to rfc 1738
|
||||||
extern std::string url_encode(const std::string& url,
|
extern std::string url_encode(const std::string& url, std::string::size_type offs = 0);
|
||||||
std::string::size_type offs = 0);
|
|
||||||
extern std::string url_decode(const std::string& encoded);
|
extern std::string url_decode(const std::string& encoded);
|
||||||
//// Convert to file path if url is like file://. This modifies the
|
//// Convert to file path if url is like file://. This modifies the
|
||||||
//// input (and returns a copy for convenience)
|
//// input (and returns a copy for convenience)
|
||||||
|
|||||||
@ -1168,3 +1168,87 @@ std::string ExecCmd::waitStatusAsString(int wstatus)
|
|||||||
return oss.str();
|
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