screenrun.cpp
Go to the documentation of this file.
00001 #include <ros/ros.h>
00002 #include <sys/select.h>
00003 #include <stdio.h>
00004 #include <dirent.h>
00005 #include <stdlib.h>
00006 #include <vector>
00007 #include <string>
00008 #include <sstream>
00009 using namespace std;
00010 
00011 enum MODE
00012 {
00013     MODE_SCREEN,
00014     MODE_X,
00015 };
00016 
00017 enum MODE g_mode = MODE_SCREEN;
00018 string g_screen_cmd = "screen";
00019 
00020 struct Params
00021 {
00022     std::string keyNewTab;
00023     double sleepNewTab;
00024     std::string keyTabTitle;
00025     double sleepTabTitle;
00026     double sleepCommand;
00027 
00028     bool load() {
00029         ros::NodeHandle nhPriv("~");
00030         nhPriv.param("key_new_tab", keyNewTab, std::string("ctrl+shift+t"));
00031         nhPriv.param("sleep_new_tab", sleepNewTab, 2.0);
00032         nhPriv.param("key_tab_title", keyTabTitle, std::string(""));
00033         nhPriv.param("sleep_tab_title", sleepTabTitle, 1.0);
00034         nhPriv.param("sleep_command", sleepCommand, 1.0);
00035         if(keyNewTab.empty()) {
00036             ROS_FATAL("~key_new_tab param was empty.");
00037             return false;
00038         }
00039         return true;
00040     }
00041 };
00042 Params g_params;
00043 
00044 bool executeCmd(const string & cmd)
00045 {
00046     int ret = system(cmd.c_str());
00047     if(ret != 0) {
00048         perror("executeCmd");
00049         ROS_ERROR("Command \"%s\" returned %d", cmd.c_str(), ret);
00050         return false;
00051     }
00052     return true;
00053 }
00054 
00055 bool queryCmd(const string & cmd, string & result)
00056 {
00057     FILE* p = popen(cmd.c_str(), "r");
00058     if(!p)
00059         return false;
00060     // read pipe
00061     char buf[1024];
00062     char* rr = fgets(buf, 1023, p);
00063     if(rr == NULL) {
00064         ROS_ERROR("Comamnd \"%s\" read from pipe failed.", cmd.c_str());
00065         return false;
00066     }
00067     result = buf;
00068     if(!result.empty()) {
00069         if(result[result.size() - 1] == '\n') {
00070             result = result.substr(0, result.size() - 1);
00071         }
00072     }
00073 
00074     int ret = pclose(p);
00075     if(ret != 0) {
00076         perror("queryCmd");
00077         ROS_ERROR("Command \"%s\" returned %d", cmd.c_str(), ret);
00078         return false;
00079     }
00080     return true;
00081 }
00082 
00083 class ProgramEntry
00084 {
00085     public:
00086         string name;
00087         vector<string> commands;
00088 
00089         void pushToScreen() {
00090             ROS_INFO("Creating screen window for \"%s\"", name.c_str());
00091             if(!executeCmd(g_screen_cmd + " -S ros -X screen -t '" + name + "'"))
00092                 return;
00093             for(vector<string>::iterator it = commands.begin(); it != commands.end(); it++) {
00094                 ROS_INFO("Pushing command: \"%s\"", it->c_str());
00095                 if(!executeCmd(g_screen_cmd + " -p '" + name + "' -S ros -X eval 'stuff \"" + *it + "\"'"))
00096                     return;
00097             }
00098         }
00099 
00102 
00106         bool filterCmdReturn(std::string & cmd) {
00107             if(cmd.length() < 4)
00108                 return false;
00109             if(cmd.substr(cmd.length() - 4) == "\\015") {
00110                 cmd = cmd.substr(0, cmd.length() - 4);
00111                 return true;
00112             }
00113             return false;
00114         }
00115 
00116         std::string toString(double d) {
00117             std::stringstream ss;
00118             ss << d;
00119             return ss.str();
00120         }
00121 
00122         void pushToXWindow(const std::string & wid) {
00123             ROS_INFO("Creating window/tab for \"%s\"", name.c_str());
00124             string cmd = "xdotool ";
00125             if(!executeCmd(cmd + "windowfocus " + wid))
00126                 return;
00127             // new tab
00128             if(!executeCmd(cmd + "key --clearmodifiers " + g_params.keyNewTab))
00129                 return;
00130             if(!executeCmd(cmd + "sleep " + toString(g_params.sleepNewTab)))
00131                 return;
00132             // set tab title
00133             if(!g_params.keyTabTitle.empty()) {
00134                 if(!executeCmd(cmd + "key " + g_params.keyTabTitle))
00135                     return;
00136                 if(!executeCmd(cmd + "type " + name))
00137                     return;
00138                 if(!executeCmd(cmd + "key Return"))
00139                     return;
00140                 if(!executeCmd(cmd + "sleep " + toString(g_params.sleepTabTitle)))
00141                     return;
00142             }
00143             // enter commands into tab
00144             for(vector<string>::iterator it = commands.begin(); it != commands.end(); it++) {
00145                 std::string pushCmd = *it;
00146                 bool doReturn = filterCmdReturn(pushCmd);
00147                 ROS_INFO("Pushing command: \"%s\"", pushCmd.c_str());
00148                 if(!executeCmd(cmd + "type --delay 1 --clearmodifiers \"" + pushCmd.c_str() + "\""))
00149                     return;
00150                 if(doReturn)
00151                     executeCmd(cmd + "key Return"); // this would be OK to fail.
00152                 if(!executeCmd(cmd + "sleep " + toString(g_params.sleepCommand)))
00153                     return;
00154             }
00155             // switch window active
00156             cmd = "wmctrl ";
00157             if(!executeCmd(cmd + "-i -a " + wid))
00158                 return;
00159         }
00160 };
00161 
00162 vector<ProgramEntry> programs;
00163 
00164 bool load()
00165 {
00166     ros::NodeHandle nh("~");
00167 
00168     XmlRpc::XmlRpcValue xmlRpc;
00169     if(!nh.getParam("programs", xmlRpc)) {
00170         ROS_FATAL("No programs defined.");
00171         return false;
00172     } 
00173 
00174     if(xmlRpc.getType() != XmlRpc::XmlRpcValue::TypeArray) {
00175         ROS_FATAL("programs param should be a list.");
00176         return false;
00177     }
00178     if(xmlRpc.size() == 0) {
00179         ROS_FATAL("programs list is empty.");
00180         return false;
00181     }
00182 
00183     for(int i = 0; i < xmlRpc.size(); i++) {
00184         ProgramEntry pe;
00185 
00186         if(xmlRpc[i].getType() != XmlRpc::XmlRpcValue::TypeStruct) {
00187             ROS_FATAL("programs entry %d is not of type string.", i);
00188             return false;
00189         }
00190         pe.name = (string)xmlRpc[i]["name"];
00191         XmlRpc::XmlRpcValue cmds = xmlRpc[i]["commands"];
00192         if(cmds.getType() != XmlRpc::XmlRpcValue::TypeArray) {
00193             ROS_FATAL("commands for %s is not a list (type %d)", pe.name.c_str(), cmds.getType());
00194             return false;
00195         }
00196         for(int j = 0; j < cmds.size(); j++) {
00197             pe.commands.push_back((string)cmds[j]);
00198         }
00199 
00200         programs.push_back(pe);
00201     }
00202 
00203     return true;
00204 }
00205 
00206 string getScreenPath()
00207 {
00208     char* user = getenv("USER");
00209     if(!user)
00210         return "";
00211 
00212     return string("/var/run/screen/S-") + user;
00213 }
00214 
00215 bool screenRunning()
00216 {
00217     string sp = getScreenPath();
00218     if(sp.empty())
00219         return false;
00220 
00221     DIR* dir = opendir(sp.c_str());
00222     if(!dir)
00223         return false;
00224     struct dirent* entry;
00225     while( (entry = readdir(dir)) ) {
00226         string dname = entry->d_name;
00227         if(dname.find("ros") != string::npos)
00228             return true;
00229     }
00230     return false;
00231 }
00232 
00233 bool command_exists(const std::string & cmd)
00234 {
00235     std::string query = std::string("which ") + cmd + " > /dev/null";
00236     int ret = system(query.c_str());
00237     return ret == 0;
00238 }
00239 
00240 int main(int argc, char** argv)
00241 {
00242     ros::init(argc, argv, "screenrun");
00243 
00244     if(argc > 1) {
00245         if(strcmp(argv[1], "b") == 0) {
00246             if(!command_exists("byobu")) {
00247                 ROS_ERROR("Requested byobu for screen, but cannot find byobu executable. Install byobu for this. Falling back to screen for now.");
00248             } else {
00249                 ROS_INFO("Using byobu for screen.");
00250                 g_screen_cmd = "byobu";
00251             }
00252         } else if(strcmp(argv[1], "x") == 0) {
00253             if(!command_exists("xdotool") || !command_exists("wmctrl")) {
00254                 ROS_FATAL("X Mode requested, but either 'xdotool' or 'wmctrl' are not installed.");
00255                 return 1;
00256             }
00257             g_mode = MODE_X;
00258         }
00259     }
00260 
00261     ros::NodeHandle nh;
00262 
00263     if(!load())
00264         return 1;
00265 
00266     std::string wid;
00267     if(g_mode == MODE_SCREEN) {
00268         if(screenRunning()) {
00269             ROS_WARN("Screen \"ros\" already running, reusing this session");
00270         } else {
00271             ROS_INFO("Creating screen \"ros\"");
00272             if(!executeCmd(g_screen_cmd + " -S ros -d -m")) {
00273                 ROS_FATAL("failed");
00274                 return 1;
00275             }
00276         }
00277     } else if(g_mode == MODE_X) {
00278         // get the active window id
00279         std::string cmd = "xprop -root | grep \"_NET_ACTIVE_WINDOW(WINDOW)\"| awk '{print $5}'";
00280         if(!queryCmd(cmd, wid)) {
00281             ROS_FATAL("wid query failed.");
00282             return 1;
00283         }
00284         printf("%s\n", wid.c_str());
00285         if(!g_params.load())
00286             return 1;
00287     }
00288 
00289     for(vector<ProgramEntry>::iterator it = programs.begin(); it != programs.end(); it++) {
00290         if(g_mode == MODE_SCREEN)
00291             it->pushToScreen();
00292         else if(g_mode == MODE_X)
00293             it->pushToXWindow(wid);
00294     }
00295 
00296     return 0;
00297 }
00298 


screenrun
Author(s): Christian Dornhege
autogenerated on Thu Jun 6 2019 21:18:17