Implemented cmd_spawn and cmd_output actions
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -5,11 +5,11 @@
|
|||||||
/src/qtplugin.moc
|
/src/qtplugin.moc
|
||||||
/src/qtplugin.o
|
/src/qtplugin.o
|
||||||
|
|
||||||
|
/src/action_c.o
|
||||||
/src/failsafe.o
|
/src/failsafe.o
|
||||||
/src/init.o
|
/src/init.o
|
||||||
/src/config.o
|
/src/config.o
|
||||||
/src/dlhook.o
|
/src/dlhook.o
|
||||||
/src/action_c.o
|
|
||||||
|
|
||||||
/src/menu.o
|
/src/menu.o
|
||||||
/src/action_cc.o
|
/src/action_cc.o
|
||||||
|
|||||||
6
res/doc
6
res/doc
@@ -25,8 +25,8 @@
|
|||||||
# nickel_setting - toggles a boolean setting
|
# nickel_setting - toggles a boolean setting
|
||||||
# nickel_extras - opens one of the beta features
|
# nickel_extras - opens one of the beta features
|
||||||
# nickel_misc - other stuff which isn't significant enough for its own category
|
# nickel_misc - other stuff which isn't significant enough for its own category
|
||||||
# cmdline_spawn - starts another process or script in the background (TODO)
|
# cmd_spawn - starts another process or script in the background
|
||||||
# cmdline_output - runs a command and displays the output (TODO)
|
# cmd_output - runs a command and displays the output
|
||||||
# <arg> the argument passed to the action:
|
# <arg> the argument passed to the action:
|
||||||
# dbg_syslog - the text to write
|
# dbg_syslog - the text to write
|
||||||
# dbg_error - the error message
|
# dbg_error - the error message
|
||||||
@@ -44,6 +44,8 @@
|
|||||||
# misc - one of:
|
# misc - one of:
|
||||||
# force_usb_connection - forces a usb connection dialog to be shown
|
# force_usb_connection - forces a usb connection dialog to be shown
|
||||||
# rescan_books - forces nickel to rescan books (TODO)
|
# rescan_books - forces nickel to rescan books (TODO)
|
||||||
|
# cmd_spawn - the command line to pass to /bin/sh -c (started in /)
|
||||||
|
# cmd_output - the timeout in milliseconds (0 < t < 10000), a colon, then the command line to pass to /bin/sh -c (started in /)
|
||||||
#
|
#
|
||||||
# For example, you might have a configuration file in KOBOeReader/.adds/nm/mystuff like:
|
# For example, you might have a configuration file in KOBOeReader/.adds/nm/mystuff like:
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
#include <QProcess>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
#include <initializer_list>
|
||||||
|
|
||||||
#include <alloca.h>
|
#include <alloca.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -150,3 +156,81 @@ extern "C" int nm_action_nickelmisc(const char *arg, char **err_out) {
|
|||||||
NM_RETURN_OK(0);
|
NM_RETURN_OK(0);
|
||||||
#undef NM_ERR_RET
|
#undef NM_ERR_RET
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: stop abusing err_out to display messages, maybe add a msg_out arg
|
||||||
|
// for that kind of thing instead (I've marked those spots by returning 2 for
|
||||||
|
// now).
|
||||||
|
|
||||||
|
extern "C" int nm_action_cmdspawn(const char *arg, char **err_out) {
|
||||||
|
#define NM_ERR_RET 1
|
||||||
|
|
||||||
|
QProcess proc;
|
||||||
|
uint64_t pid;
|
||||||
|
bool ok = proc.startDetached(
|
||||||
|
QStringLiteral("/bin/sh"),
|
||||||
|
QStringList(std::initializer_list<QString>{
|
||||||
|
QStringLiteral("-c"),
|
||||||
|
QString::fromUtf8(arg),
|
||||||
|
}),
|
||||||
|
QStringLiteral("/"),
|
||||||
|
(qint64*)(&pid)
|
||||||
|
);
|
||||||
|
NM_ASSERT(ok, "could not start process");
|
||||||
|
|
||||||
|
if (*err_out)
|
||||||
|
asprintf(err_out, "Successfully started process with PID %lu.", pid);
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
#undef NM_ERR_RET
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int nm_action_cmdoutput(const char *arg, char **err_out) {
|
||||||
|
#define NM_ERR_RET 1
|
||||||
|
|
||||||
|
char *tmp = strdup(arg);
|
||||||
|
|
||||||
|
char *cmd = tmp;
|
||||||
|
char *tmp1 = strsep(&cmd, ":"), *tmp2;
|
||||||
|
long timeout = strtol(tmp1, &tmp2, 10);
|
||||||
|
NM_ASSERT(*tmp1 && !*tmp2 && timeout > 0 && timeout < 10000, "invalid timeout '%s'", tmp1);
|
||||||
|
|
||||||
|
QProcess proc;
|
||||||
|
proc.setProcessChannelMode(QProcess::MergedChannels);
|
||||||
|
proc.setWorkingDirectory(QStringLiteral("/"));
|
||||||
|
proc.start(
|
||||||
|
QStringLiteral("/bin/sh"),
|
||||||
|
QStringList(std::initializer_list<QString>{
|
||||||
|
QStringLiteral("-c"),
|
||||||
|
QString::fromUtf8(cmd),
|
||||||
|
}),
|
||||||
|
QIODevice::ReadOnly
|
||||||
|
);
|
||||||
|
|
||||||
|
bool ok = proc.waitForFinished(timeout);
|
||||||
|
if (!ok) {
|
||||||
|
switch (proc.error()) {
|
||||||
|
case QProcess::Timedout:
|
||||||
|
NM_RETURN_ERR("could not run process: timed out");
|
||||||
|
case QProcess::FailedToStart:
|
||||||
|
NM_RETURN_ERR("could not run process: missing program or wrong permissions");
|
||||||
|
case QProcess::Crashed:
|
||||||
|
NM_RETURN_ERR("could not run process: process crashed");
|
||||||
|
default:
|
||||||
|
NM_RETURN_ERR("could not run process");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (proc.exitStatus() == QProcess::NormalExit && proc.exitCode() != 0)
|
||||||
|
NM_RETURN_ERR("could not run process: process exited with status %d", proc.exitCode());
|
||||||
|
|
||||||
|
QString out = proc.readAllStandardOutput();
|
||||||
|
if (out.length() > 500)
|
||||||
|
out = out.left(500) + "...";
|
||||||
|
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
|
if (err_out)
|
||||||
|
*err_out = strdup(qPrintable(out));
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
#undef NM_ERR_RET
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,9 +4,14 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// This file contains actions which need access to Qt classes, but is still
|
||||||
|
// mostly C code.
|
||||||
|
|
||||||
int nm_action_nickelsetting(const char *arg, char **err_out);
|
int nm_action_nickelsetting(const char *arg, char **err_out);
|
||||||
int nm_action_nickelextras(const char *arg, char **err_out);
|
int nm_action_nickelextras(const char *arg, char **err_out);
|
||||||
int nm_action_nickelmisc(const char *arg, char **err_out);
|
int nm_action_nickelmisc(const char *arg, char **err_out);
|
||||||
|
int nm_action_cmdspawn(const char *arg, char **err_out);
|
||||||
|
int nm_action_cmdoutput(const char *arg, char **err_out);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,6 +132,8 @@ nm_config_t *nm_config_parse(char **err_out) {
|
|||||||
else if (!strcmp(c_act, "nickel_setting")) it->act = nm_action_nickelsetting;
|
else if (!strcmp(c_act, "nickel_setting")) it->act = nm_action_nickelsetting;
|
||||||
else if (!strcmp(c_act, "nickel_extras")) it->act = nm_action_nickelextras;
|
else if (!strcmp(c_act, "nickel_extras")) it->act = nm_action_nickelextras;
|
||||||
else if (!strcmp(c_act, "nickel_misc")) it->act = nm_action_nickelmisc;
|
else if (!strcmp(c_act, "nickel_misc")) it->act = nm_action_nickelmisc;
|
||||||
|
else if (!strcmp(c_act, "cmd_spawn")) it->act = nm_action_cmdspawn;
|
||||||
|
else if (!strcmp(c_act, "cmd_output")) it->act = nm_action_cmdoutput;
|
||||||
else RETERR("file %s: line %d: field 4: unknown action '%s'", fn, line_n, c_act);
|
else RETERR("file %s: line %d: field 4: unknown action '%s'", fn, line_n, c_act);
|
||||||
|
|
||||||
// type: menu_item - field 5: argument
|
// type: menu_item - field 5: argument
|
||||||
|
|||||||
Reference in New Issue
Block a user