polybar-dwm/src/ipc.cpp
patrick96 c24a6999a4 refactor(cmake): Allow targets to be enabled individually
Each major target of polybar can now be enabled/disabled while
configuring (even polybar itself).

The cmake code specific to each target will only run if the target is
enabled.

This allows us to for example just build the documentation without
having to run all the cmake code related to compilation or having the
polybar dependencies installed (other than sphinx).
2020-12-24 02:20:38 +01:00

134 lines
3.8 KiB
C++

#include <fcntl.h>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <vector>
#include "common.hpp"
#include "utils/file.hpp"
using namespace polybar;
using namespace std;
#ifndef IPC_CHANNEL_PREFIX
#define IPC_CHANNEL_PREFIX "/tmp/polybar_mqueue."
#endif
void display(const string& msg) {
fprintf(stdout, "%s\n", msg.c_str());
}
void log(int exit_code, const string& msg) {
fprintf(stderr, "polybar-msg: %s\n", msg.c_str());
exit(exit_code);
}
void usage(const string& parameters) {
fprintf(stderr, "Usage: polybar-msg [-p pid] %s\n", parameters.c_str());
exit(127);
}
void remove_pipe(const string& handle) {
if (unlink(handle.c_str()) == -1) {
log(1, "Could not remove stale ipc channel: "s + strerror(errno));
} else {
display("Removed stale ipc channel: " + handle);
}
}
bool validate_type(const string& type) {
return (type == "action" || type == "cmd" || type == "hook");
}
int main(int argc, char** argv) {
const int E_NO_CHANNELS{2};
const int E_MESSAGE_TYPE{3};
const int E_INVALID_PID{4};
const int E_INVALID_CHANNEL{5};
const int E_WRITE{6};
vector<string> args{argv + 1, argv + argc};
string::size_type p;
int pid{0};
// If -p <pid> is passed, check if the process is running and that
// a valid channel pipe is available
if (args.size() >= 2 && args[0].compare(0, 2, "-p") == 0) {
if (!file_util::exists("/proc/" + args[1])) {
log(E_INVALID_PID, "No process with pid " + args[1]);
} else if (!file_util::exists(IPC_CHANNEL_PREFIX + args[1])) {
log(E_INVALID_CHANNEL, "No channel available for pid " + args[1]);
}
pid = strtol(args[1].c_str(), nullptr, 10);
args.erase(args.begin());
args.erase(args.begin());
}
// Validate args
auto help = find_if(args.begin(), args.end(), [](string a) { return a == "-h" || a == "--help"; }) != args.end();
if (help || args.size() < 2) {
usage("<command=(action|cmd|hook)> <payload> [...]");
} else if (!validate_type(args[0])) {
log(E_MESSAGE_TYPE, "\"" + args[0] + "\" is not a valid type.");
}
string ipc_type{args[0]};
args.erase(args.begin());
string ipc_payload{args[0]};
args.erase(args.begin());
// Check hook specific args
if (ipc_type == "hook") {
if (args.size() != 1) {
usage("hook <module-name> <hook-index>");
} else if ((p = ipc_payload.find("module/")) != 0) {
ipc_payload = "module/" + ipc_payload + args[0];
args.erase(args.begin());
} else {
ipc_payload += args[0];
args.erase(args.begin());
}
}
// Get availble channel pipes
auto pipes = file_util::glob(IPC_CHANNEL_PREFIX + "*"s);
// Remove stale channel files without a running parent process
for (auto it = pipes.rbegin(); it != pipes.rend(); it++) {
if ((p = it->rfind('.')) == string::npos) {
continue;
} else if (!file_util::exists("/proc/" + it->substr(p + 1))) {
remove_pipe(*it);
pipes.erase(remove(pipes.begin(), pipes.end(), *it), pipes.end());
} else if (pid && to_string(pid) != it->substr(p + 1)) {
pipes.erase(remove(pipes.begin(), pipes.end(), *it), pipes.end());
}
}
if (pipes.empty()) {
log(E_NO_CHANNELS, "No active ipc channels");
}
int exit_status = 127;
// Write message to each available channel or match
// against pid if one was defined
for (auto&& channel : pipes) {
try {
file_descriptor fd(channel, O_WRONLY | O_NONBLOCK);
string payload{ipc_type + ':' + ipc_payload};
if (write(fd, payload.c_str(), payload.size()) != -1) {
display("Successfully wrote \"" + payload + "\" to \"" + channel + "\"");
exit_status = 0;
} else {
log(E_WRITE, "Failed to write \"" + payload + "\" to \"" + channel + "\" (err: " + strerror(errno) + ")");
}
} catch (const exception& err) {
remove_pipe(channel);
}
}
return exit_status;
}