diff --git a/Makefile b/Makefile index eeb30e3..47f9311 100644 --- a/Makefile +++ b/Makefile @@ -16,10 +16,13 @@ endif $(shell mkdir -p $(ODIR)) $(shell mkdir -p $(BINDIR)) -# automatically finds .hpp -DEPS = $(shell if [ -n "$(ld $(IDIR))" ] ; then ls $(IDIR)/*.hpp ; fi) -# automatically finds .cpp and makes the corresponding .o rule -OBJ = $(shell ls $(SRCDIR)/*.cpp | sed 's/.cpp/.o/g;s|$(SRCDIR)/|$(ODIR)/|g') +# automatically finds .h and .hpp +DEPS = $(shell if [ -n "$(ld $(IDIR))" ] ; then ls $(IDIR)/*.hpp $(IDIR)/*.h 2>/dev/null ; fi) +# automatically finds .c and .cpp and makes the corresponding .o rule +OBJ = $(shell ls $(SRCDIR)/*.cpp $(SRCDIR)/*.c 2>/dev/null | sed 's|\.cpp|.o|g;s|\.c|.o|g;s|$(SRCDIR)/|$(ODIR)/|g') + +$(ODIR)/%.o: $(SRCDIR)/%.c $(DEPS) + $(CC) $(CXXFLAGS) -c -o $@ $< $(ODIR)/%.o: $(SRCDIR)/%.cpp $(DEPS) $(CC) $(CXXFLAGS) -c -o $@ $< @@ -36,5 +39,5 @@ clean: clear: rm $(BINDIR)/$(NAME) -install: $(BINDIR)/$(NAME) - mv $(BINDIR)/$(NAME) /usr/local/bin +obj: + echo $(OBJ) diff --git a/include/device.hpp b/include/device.hpp index dd3e617..6240533 100644 --- a/include/device.hpp +++ b/include/device.hpp @@ -8,9 +8,6 @@ #include "command.hpp" #include "Filedat.hpp" -#define KILL_COMMAND_FH "kill -s INT $(pgrep -f \"aseqdump -p " -#define KILL_COMMAND_SH "\")" - void sh(std::string const& string); class Device @@ -38,6 +35,7 @@ public: std::vector disconnectCommands; std::thread thread; + pid_t thread_pid; private: static void loop(Device* dev); }; diff --git a/include/log.hpp b/include/log.hpp new file mode 100644 index 0000000..829be6a --- /dev/null +++ b/include/log.hpp @@ -0,0 +1,12 @@ +#ifndef LOG_HPP +#define LOG_HPP + +#include + +#define DEFAULT_LOG_STATE true + +extern bool log_on; + +void log(const std::string& str); + +#endif //LOG_HPP diff --git a/include/popen.h b/include/popen.h new file mode 100644 index 0000000..c39f7dc --- /dev/null +++ b/include/popen.h @@ -0,0 +1,11 @@ +#ifndef POPEN_HPP +#define POPEN_HPP + +#include +#include + +FILE* popen2(const char* command, const char* type, pid_t* pid); + +int pclose2(FILE* fp, pid_t pid); + +#endif //POPEN_HPP diff --git a/include/system.hpp b/include/system.hpp index 385b319..4747b69 100644 --- a/include/system.hpp +++ b/include/system.hpp @@ -1,10 +1,15 @@ #ifndef SYSTEM_HPP #define SYSTEM_HPP +#include "popen.h" + #define ANNOUNCE_COMMAND "aseqdump -p System:1" #define LIST_COMMAND "aseqdump -l | tail -n +2 | cut -c10-42 | tr -s ' '" #define LIST_EXTENDED_COMMAND "aseqdump -l | tail -n +2 | cut -c-42" + +extern pid_t announce_thread_pid; + void device_check(); void announce_loop(); diff --git a/src/device.cpp b/src/device.cpp index 653f7dc..1275dcf 100644 --- a/src/device.cpp +++ b/src/device.cpp @@ -6,6 +6,9 @@ #include +#include "log.hpp" +#include "popen.h" + std::vector device_list; static bool _isNum(char a) @@ -23,6 +26,7 @@ Device::Device() busy=false; nb_command=0; client_id=-1; + thread_pid=-1; } Device::~Device() @@ -245,8 +249,7 @@ void Device::run_signal(char* buff) { if ( (strstr(buff, "Port unsubscribed") != NULL) ) // distonnected { - std::string kill_command=KILL_COMMAND_FH + std::to_string(this->client_id) + KILL_COMMAND_SH; - system(kill_command.c_str()); // kill the process + kill(this->thread_pid, SIGINT); this->busy=false; this->client_id=-1; } @@ -411,10 +414,12 @@ void Device::run_signal(char* buff) void Device::loop(Device* dev) { - std::string command = "aseqdump -p '" + std::to_string(dev->client_id) + '\''; - FILE *stream = popen(command.c_str(), "r"); char* buff = NULL; size_t buff_size = 0; + std::string command = "aseqdump -p '" + std::to_string(dev->client_id) + '\''; + FILE *stream = popen2(command.c_str(), "r", &dev->thread_pid); + + log("Device '" + dev->name + "' connected\n"); for( auto it : dev->connectCommands ) { @@ -431,8 +436,9 @@ void Device::loop(Device* dev) std::thread(sh, it.shell).detach(); } - printf("Device '%s' disconnected\n", dev->name.c_str()); + log("Device '" + dev->name + "' disconnected\n"); - pclose(stream); + pclose2(stream, dev->thread_pid); + dev->thread_pid=-1; free(buff); } diff --git a/src/log.cpp b/src/log.cpp new file mode 100644 index 0000000..e002187 --- /dev/null +++ b/src/log.cpp @@ -0,0 +1,11 @@ +#include "log.hpp" + +#include + +bool log_on=DEFAULT_LOG_STATE; + +void log(const std::string& str) +{ + if(log_on) + printf("%s", str.c_str()); +} diff --git a/src/main.cpp b/src/main.cpp index cff8afd..a43850a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,16 +1,17 @@ #include #include -#include +#include #include "device.hpp" #include "system.hpp" +#include "log.hpp" +#include "help.h" #include "Filedat.hpp" #include "options.hpp" +#include "popen.h" -#include "help.h" - OptionSet options; void help() @@ -23,19 +24,20 @@ void help() void option_p(const std::string& port) { std::string command="aseqdump -p '" + port + '\''; - FILE *stream = popen(command.c_str(), "r"); + pid_t pid; + FILE *stream = popen2(command.c_str(), "r", &pid); char* buff = NULL; size_t buff_size = 0; while (getline(&buff, &buff_size, stream) > 0) { if ( (strstr(buff, "Port unsubscribed") != NULL) ) // distonnected { - std::string kill_command=KILL_COMMAND_FH + port + KILL_COMMAND_SH; - system(kill_command.c_str()); // kill the process + kill(pid, SIGINT); // kill the process } else printf("%s", buff); } + pclose2(stream, pid); } void cleanup() @@ -46,6 +48,7 @@ void cleanup() void stop(int ret) { + kill(announce_thread_pid, SIGINT); exit(ret); } @@ -66,6 +69,7 @@ int main(int argc, char* argv[]) options.addOption(Option('l',"list", false, "List detected devices")); options.addOption(Option('L',"full-list", false, "Print whole device list details")); options.addOption(Option('p',"port", true, "Connect to device and output to console", "device")); + options.addOption(Option("no-log", false, "Disable console logging")); // options.addOption(Option('i',"interactive", false, "Start in interactive mode")); auto argvec = argVector(argc, argv); @@ -75,6 +79,7 @@ int main(int argc, char* argv[]) if( !t.second ) //invalid option return 1; + //exit options Option* op=nullptr; op = options.findOption('h'); if( op->activated ) @@ -125,6 +130,14 @@ int main(int argc, char* argv[]) return 0; } + //behavioral options + op = options.findOption("no-log"); + if( op->activated ) + { + log_on=false; + } + + //no argument: display help if (arg.size() <= 0 || arg[0] == "") { help(); @@ -138,9 +151,10 @@ int main(int argc, char* argv[]) return 10; } - printf("Loading map file '%s'\n", arg[0].c_str()); + //main processing try { + log("Loading map file '" + arg[0] + "'\n"); file.import_file(); //create commands @@ -149,11 +163,11 @@ int main(int argc, char* argv[]) Device *newDevice = new Device; newDevice->import_chunk(file[i]); device_list.push_back(newDevice); - printf("Loaded %d commands for device '%s'\n", newDevice->nb_command, newDevice->name.c_str()); + log("Loaded "+std::to_string(newDevice->nb_command)+" commands for device '"+newDevice->name+"'\n"); } //main loop - printf("Starting scan for devices\n"); + log("Starting scan for devices\n"); announce_loop(); } catch (format_error& e) diff --git a/src/popen.c b/src/popen.c new file mode 100644 index 0000000..07da4eb --- /dev/null +++ b/src/popen.c @@ -0,0 +1,80 @@ +#include "popen.h" + +#include +#include +#include +#include +#include +#include + +#define READ 0 +#define WRITE 1 + +FILE* popen2(const char* command, const char* type, int* pid) +{ + pid_t child_pid; + int fd[2]; + pipe(fd); + + if((child_pid = fork()) == -1) + { + perror("fork"); + exit(1); + } + + /* child process */ + if (child_pid == 0) + { + if ( index(type, 'r') != NULL ) + { + close(fd[READ]); //Close the READ end of the pipe since the child's fd is write-only + dup2(fd[WRITE], 1); //Redirect stdout to pipe + } + else + { + close(fd[WRITE]); //Close the WRITE end of the pipe since the child's fd is read-only + dup2(fd[READ], 0); //Redirect stdin to pipe + } + + setpgid(child_pid, child_pid); //Needed so negative PIDs can kill children of /bin/sh + execl("/bin/sh", "/bin/sh", "-c", command, NULL); + exit(0); + } + else + { + if ( index(type, 'r') != NULL ) + { + close(fd[WRITE]); //Close the WRITE end of the pipe since parent's fd is read-only + } + else + { + close(fd[READ]); //Close the READ end of the pipe since parent's fd is write-only + } + } + if(pid != NULL) + *pid = child_pid; + + if ( index(type, 'r') != NULL ) + { + return fdopen(fd[READ], "r"); + } + + return fdopen(fd[WRITE], "w"); +} + +int pclose2(FILE* fp, pid_t pid) +{ + int stat; + + fclose(fp); + while (waitpid(pid, &stat, 0) == -1) + { + if (errno != EINTR) + { + stat = -1; + break; + } + } + + return stat; +} diff --git a/src/system.cpp b/src/system.cpp index dad7dd1..aed918e 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -9,12 +9,13 @@ #include #include +pid_t announce_thread_pid = -1; + void device_check() { char* buff = NULL; size_t buff_size = 0; FILE *stream = popen(LIST_EXTENDED_COMMAND, "r"); - std::string str; std::vector> ls_device; getline(&buff, &buff_size, stream); //discard the first line @@ -37,9 +38,10 @@ void device_check() i++; while(buff[i-1] == ' ') i--; - + //insert element ls_device.push_back(std::make_pair(t, std::string(buff+j, i-j))); } + pclose(stream); for ( auto dev : device_list ) // iterate devices { @@ -48,7 +50,6 @@ void device_check() if( !dev->busy && dev->name == ls->second && ls->first > 0) //device detected { dev->client_id = ls->first; - printf("Device '%s' found\n", dev->name.c_str()); dev->start_loop(); } if( dev->busy && dev->client_id == ls->first ) @@ -64,7 +65,7 @@ void announce_loop() { char* buff = NULL; size_t buff_size = 0; - FILE *stream = popen(ANNOUNCE_COMMAND,"r"); + FILE* stream = popen2(ANNOUNCE_COMMAND, "r", &announce_thread_pid); if (stream == NULL) { @@ -78,6 +79,8 @@ void announce_loop() device_check(); } + pclose2(stream, announce_thread_pid); + if(buff != NULL) free(buff); }