YARP
Yet Another Robot Platform
Run.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2018 Istituto Italiano di Tecnologia (IIT)
3  * Copyright (C) 2006-2010 RobotCub Consortium
4  * All rights reserved.
5  *
6  * This software may be modified and distributed under the terms of the
7  * BSD-3-Clause license. See the accompanying LICENSE file for details.
8  */
9 
10 #include <yarp/run/Run.h>
16 
17 #include <yarp/os/Network.h>
18 #include <yarp/os/Os.h>
19 #include <yarp/os/LogStream.h>
20 #include <yarp/os/RpcClient.h>
21 #include <yarp/os/RpcServer.h>
22 #include <yarp/os/SystemInfo.h>
24 #include <yarp/os/Time.h>
25 
27 #include <yarp/os/impl/Logger.h>
32 
33 #include <cstdio>
34 #include <string>
35 #include <cstring>
36 #include <random>
37 
38 #if defined(_WIN32)
39 # if !defined(WIN32_LEAN_AND_MEAN)
40 # define WIN32_LEAN_AND_MEAN
41 # endif
42 # include <windows.h>
43 #else
44 # define C_MAXARGS 128 // the max number of command parameters. rational?
45 #endif
46 
47 #if defined(_WIN32)
48 YarpRunInfoVector yarp::run::Run::mProcessVector;
49 YarpRunInfoVector yarp::run::Run::mStdioVector;
50 inline std::string lastError2String()
51 {
52  int error=GetLastError();
53  char buff[1024];
54  FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, error, 0, buff, 1024, nullptr);
55 
56  return std::string(buff);
57 }
58 #else
59 //#define SIGSTDIO SIGHUP
60 #define READ_FROM_PIPE 0
61 #define WRITE_TO_PIPE 1
62 #define REDIRECT_TO(from, to) yarp::run::impl::dup2(to, from)
63 YarpRunInfoVector* yarp::run::Run::mProcessVector = nullptr;
64 YarpRunInfoVector* yarp::run::Run::mStdioVector = nullptr;
65 ZombieHunterThread* yarp::run::Run::mBraveZombieHunter = nullptr;
66 #endif
67 
69 // OS INDEPENDENT FUNCTIONS
71 
72 std::string yarp::run::Run::mPortName;
73 yarp::os::RpcServer* yarp::run::Run::pServerPort=nullptr;
74 int yarp::run::Run::mProcCNT=0;
75 bool yarp::run::Run::mStresstest=false;
76 bool yarp::run::Run::mLogged=false;
77 std::string yarp::run::Run::mLoggerPort("/yarplogger");
78 
80 
81 static RunTerminator *pTerminator = nullptr;
82 
83 void sigstdio_handler(int sig)
84 {
85  char msg[16];
87  sprintf(msg, "SIGNAL %d", sig);
88  RUNLOG(msg);
89 
90  if (pTerminator) pTerminator->exit();
91 }
92 
94 
97 static yarp::os::Bottle parsePaths(const std::string& txt) {
100  yarp::os::Bottle result;
101  const char *at = txt.c_str();
102  int slash_tweak = 0;
103  int len = 0;
104  for (std::string::size_type i=0; i<txt.length(); i++) {
105  char ch = txt[i];
106  if (ch==sep) {
107  result.addString(std::string(at, len-slash_tweak));
108  at += len+1;
109  len = 0;
110  slash_tweak = 0;
111  continue;
112  }
113  slash_tweak = (ch==slash && len>0)?1:0;
114  len++;
115  }
116  if (len>0) {
117  result.addString(std::string(at, len-slash_tweak));
118  }
119  return result;
120 }
121 
122 static bool fileExists(const char *fname) {
123  FILE *fp = nullptr;
124  fp = fopen(fname, "r");
125  if (!fp) {
126  return false;
127  } else {
128  fclose(fp);
129  return true;
130  }
131  }
132 
133 
135 int yarp::run::Run::main(int argc, char *argv[])
136 {
137  yarp::os::Property config;
138  config.fromCommand(argc, argv, false);
139 
140  // SERVER
141  if (config.check("server"))
142  {
143  mLogged=config.check("log");
144 
145  if (mLogged)
146  {
147  yarp::os::Bottle botPortLogger=config.findGroup("log");
148 
149  if (botPortLogger.size()>1)
150  {
151  mLoggerPort=botPortLogger.get(1).asString();
152  }
153  }
154 
155  mPortName=std::string(config.find("server").asString());
156 
157  return server();
158  }
159 
160  if (config.check("echo"))
161  {
162  char line[1024];
163  fprintf(stderr, "Program echo started.\n");
164  fflush(stderr);
165 
166  while(true)
167  {
168  int ret=scanf("%s", line);
169 
170  if (ret>0)
171  {
172  fprintf(stderr, "%s\n", line);
173  fflush(stderr);
174  }
175  }
176 
177  return 0;
178  }
179 
180  //yarp::os::Network yarp;
181 
182  mPortName="";
183 
185  {
187  {
188  fprintf(stderr, "ERROR: no yarp network found.\n");
189 
190  return YARPRUN_ERROR;
191  }
192  }
193 
195 
196  if (config.check("readwrite"))
197  {
199  std::string uuid=config.findGroup("readwrite").get(1).asString();
200  std::string fPortName("");
201  std::string lPortName("");
202 
203  if (config.check("forward"))
204  {
205  fPortName=config.findGroup("forward").get(1).asString();
206  lPortName=config.findGroup("forward").get(2).asString();
207  }
208 
209 #if defined(_WIN32)
210  yarp::os::impl::signal(SIGINT, sigstdio_handler);
211  yarp::os::impl::signal(SIGTERM, sigstdio_handler);
212  yarp::os::impl::signal(SIGBREAK, sigstdio_handler);
213 #elif defined(__APPLE__)
214  //prctl(PR_SET_PDEATHSIG, SIGTERM);
215 
216  struct sigaction new_action;
217  new_action.sa_handler=sigstdio_handler;
218  sigfillset(&new_action.sa_mask);
219  new_action.sa_flags=0;
220 
221  sigaction(SIGTERM, &new_action, nullptr);
222  sigaction(SIGHUP, &new_action, nullptr);
223  //yarp::os::impl::signal(SIGHUP, SIG_IGN);
224  //yarp::os::impl::signal(SIGINT, SIG_IGN);
225  yarp::os::impl::signal(SIGPIPE, SIG_IGN);
226 
227  if (getppid()==1) return 0;
228 #else
229  yarp::os::impl::prctl(PR_SET_PDEATHSIG, SIGTERM);
230 
231  struct sigaction new_action;
232  new_action.sa_handler=sigstdio_handler;
233  yarp::os::impl::sigfillset(&new_action.sa_mask);
234  new_action.sa_flags=0;
235 
236  yarp::os::impl::sigaction(SIGTERM, &new_action, nullptr);
237  yarp::os::impl::signal(SIGHUP, SIG_IGN);
238  //yarp::os::impl::signal(SIGINT, SIG_IGN);
239  yarp::os::impl::signal(SIGPIPE, SIG_IGN);
240 
241  if (yarp::os::getpid() == 1) {
242  return 0;
243  }
244 #endif
245 
246  RunReadWrite rw(uuid, fPortName, lPortName);
247  RunTerminator rt(&rw);
248  pTerminator=&rt;
249  rt.start();
250 
251  return rw.loop();
252  }
253 
254  if (config.check("write"))
255  {
257  std::string portName=config.findGroup("write").get(1).asString();
258 
259 #if defined(_WIN32)
260  yarp::os::impl::signal(SIGINT, sigstdio_handler);
261  yarp::os::impl::signal(SIGTERM, sigstdio_handler);
262  yarp::os::impl::signal(SIGBREAK, sigstdio_handler);
263 #else
264  struct sigaction new_action;
265  new_action.sa_handler=sigstdio_handler;
266  yarp::os::impl::sigfillset(&new_action.sa_mask);
267  new_action.sa_flags=0;
268  yarp::os::impl::sigaction(SIGTERM, &new_action, nullptr);
269  //yarp::os::impl::signal(SIGINT, SIG_IGN);
270  yarp::os::impl::signal(SIGPIPE, SIG_IGN);
271  yarp::os::impl::signal(SIGHUP, SIG_IGN);
272 #endif
273 
274  if (config.check("log"))
275  {
276  std::string loggerName=config.find("log").asString();
277  RunWrite w(portName, loggerName);
278  RunTerminator rt(&w);
279  pTerminator=&rt;
280  rt.start();
281  return w.loop();
282  }
283  else
284  {
285  RunWrite w(portName);
286  RunTerminator rt(&w);
287  pTerminator=&rt;
288  rt.start();
289  return w.loop();
290  }
291 
292  return 0;
293  }
294 
295  if (config.check("read"))
296  {
298  std::string uuid=config.findGroup("read").get(1).asString();
299 
300  #if defined(_WIN32)
301  yarp::os::impl::signal(SIGINT, sigstdio_handler);
302  yarp::os::impl::signal(SIGTERM, sigstdio_handler);
303  yarp::os::impl::signal(SIGBREAK, sigstdio_handler);
304  #else
305  //yarp::os::impl::signal(SIGINT, SIG_IGN);
306  yarp::os::impl::signal(SIGTERM, sigstdio_handler);
307  yarp::os::impl::signal(SIGHUP, SIG_IGN);
308  #endif
309 
310  RunRead r(uuid);
311  RunTerminator rt(&r);
312  pTerminator=&rt;
313  rt.start();
314 
315  return r.loop();
316  }
317 
319 
320  if (config.check("stresstest"))
321  {
322  fprintf(stderr, "Yarprun stress test started.\n");
323  fflush(stderr);
324 
325  int max_interval_ms=config.find("stresstest").asInt32();
326  std::string tag_zero=config.find("as").asString();
327  yarp::os::Bottle srv=config.findGroup("on");
328 
329  config.unput("as");
330  config.unput("stresstest");
331 
332  std::string cmd;
333 
334  bool isCommand=false;
335 
336  if (config.check("cmd"))
337  {
338  isCommand=true;
339  cmd=config.find("cmd").asString();
340  config.unput("cmd");
341  }
342 
343  unsigned int t=0, u=0;
344  int term_cycle=0;
345 
346  char tag[256];
347  char cmd_and_name[512];
348 
349  mStresstest=true;
350 
351  std::random_device rd;
352  std::mt19937 mt(rd());
353  std::uniform_int_distribution<int> dist0maxint(0, max_interval_ms -1);
354 
355  while (mStresstest)
356  {
357  yarp::os::SystemClock::delaySystem(0.001*(dist0maxint(mt)));
358 
359  yarp::os::Property stresser=config;
360 
361  sprintf(tag, "%s_%u", tag_zero.c_str(), t++);
362  stresser.put("as", tag);
363 
364  if (isCommand)
365  {
366  sprintf(cmd_and_name, "%s --name /%s", cmd.c_str(), tag);
367  stresser.put("cmd", cmd_and_name);
368  }
369 
370  client(stresser);
371 
372  std::uniform_int_distribution<int> dist07(0, 7);
373  if (isCommand && ++term_cycle>=4)
374  {
375  term_cycle=0;
376 
377  int r = t - (dist07(mt));
378 
379  for (int i=u; i<r; ++i)
380  {
381  sprintf(tag, "%s_%u", tag_zero.c_str(), i);
382 
383  yarp::os::Bottle as;
384  as.addString("sigterm");
385  as.addString(tag);
386 
387  yarp::os::Bottle term;
388  term.addList()=srv;
389  term.addList()=as;
390 
391  sendMsg(term, srv.get(1).asString());
392 
393  ++u;
394  }
395  }
396  }
397 
398  return 0;
399  }
400 
401  // HELP
402  if (config.check("help"))
403  {
404  Help();
405 
406  return 0;
407  }
408 
409  // CLIENT (config is from keyboard)
410  if (config.check("stdio")
411  || config.check("cmd")
412  || config.check("kill")
413  || config.check("sigterm")
414  || config.check("sigtermall")
415  || config.check("exit")
416  || config.check("isrunning")
417  || config.check("ps")
418  || config.check("env")
419  || config.check("sysinfo")
420  || config.check("which"))
421  {
422  int ret=client(config);
423 
424  return ret;
425  }
426 
427  Help();
428 
429  return 0;
430 }
431 
432 yarp::os::Bottle yarp::run::Run::sendMsg(yarp::os::Bottle& msg, std::string target, int RETRY, double DELAY)
433 {
434  yarp::os::Bottle response;
435 
436  for (int r=0; r<RETRY; ++r)
437  {
438  yarp::os::RpcClient port;
439 
440  if (!port.open("..."))
441  {
443  continue;
444  }
445 
446  if (!yarp::os::Network::connect(port.getName(), target))
447  {
448  port.close();
450  continue;
451  }
452 
453  RUNLOG("<<<port.write(msg, response)")
454  if (!port.write(msg, response))
455  {
456  port.close();
458  continue;
459  }
460  RUNLOG(">>>port.write(msg, response)")
461 
462  yarp::os::Network::disconnect(port.getName().c_str(), target.c_str());
463  port.close();
464 
465  fprintf(stderr, "RESPONSE:\n=========\n");
466  for (size_t s=0; s<response.size(); ++s)
467  {
468  fprintf(stderr, "%s\n", response.get(s).toString().c_str());
469  }
470 
471  return response;
472  }
473 
474  response.addString("RESPONSE:\n");
475  response.addString("=========\n");
476  response.addString("Cannot connect to remote server, aborting...\n");
477  for (size_t s=0; s<response.size(); ++s)
478  {
479  fprintf(stderr, "%s\n", response.get(s).toString().c_str());
480  }
481  return response;
482 }
483 
484 void sigint_handler(int sig)
485 {
486  YARP_UNUSED(sig);
487  yarp::run::Run::mStresstest=false;
488 
489  if (yarp::run::Run::pServerPort)
490  {
491  yarp::os::RpcServer *pClose=yarp::run::Run::pServerPort;
492  yarp::run::Run::pServerPort = nullptr;
493  pClose->close();
494  }
495  //else
496  //{
497  //}
498 }
499 
501 // WINDOWS SERVER
502 #if defined(_WIN32)
503 int yarp::run::Run::server()
504 {
505  yarp::os::Semaphore serializer(1);
506 
507  yarp::os::RpcServer port;
508 
509  if (!port.open(mPortName.c_str()))
510  {
511  yError() << "Yarprun failed to open port: " << mPortName.c_str();
512  return YARPRUN_ERROR;
513  }
514 
515  yarp::os::Bottle cmd, reply;
516  cmd.addString("set");
517  cmd.addString(port.getName());
518  cmd.addString("yarprun");
519  cmd.addString("true");
521 
522  yInfo() << "Yarprun successfully started on port: " << mPortName.c_str();
523 
524  pServerPort=&port;
525 
526  yarp::os::impl::signal(SIGINT, sigint_handler);
527  yarp::os::impl::signal(SIGTERM, sigint_handler);
528 
529  // Enabling cpu load collector on windows
530  //yarp::os::impl::SystemInfo::enableCpuLoadCollector();
531 
532  while (pServerPort)
533  {
534  yarp::os::Bottle msg;
535 
536  RUNLOG("<<<port.read(msg, true)")
537  if (!port.read(msg, true)) break;
538  RUNLOG(">>>port.read(msg, true)")
539 
540  if (!pServerPort) break;
541 
542  //printf("<<< %s >>>\n", msg.toString().c_str());
543  //fflush(stdout);
544 
546 
547  // command with stdio management
548  if (msg.check("stdio"))
549  {
550  std::string strOnPort=msg.find("on").asString();
551  std::string strStdioPort=msg.find("stdio").asString();
552 
553  if (strOnPort==mPortName)
554  {
555  std::string strUUID=mPortName+"/"+int2String(getpid())+"/"+msg.find("as").asString()+"-"+int2String(mProcCNT++);
556  yarp::os::Bottle botUUID;
557  botUUID.addString("stdiouuid");
558  botUUID.addString(strUUID.c_str());
559  msg.addList()=botUUID;
560 
561  if (mLogged || msg.check("log"))
562  {
563  std::string strAlias=msg.find("as").asString();
564  std::string portName="/log";
565  portName+=mPortName+"/";
566  std::string command=msg.findGroup("cmd").get(1).asString();
567  int space=command.find(" ");
568  if (space!=std::string::npos) command=command.substr(0, space);
569  portName+=command;
570 
571  yarp::os::Bottle botFwd;
572  botFwd.addString("forward");
573  botFwd.addString(portName.c_str());
574  if (msg.check("log"))
575  {
576  yarp::os::Bottle botLogger=msg.findGroup("log");
577 
578  if (botLogger.size()>1)
579  {
580  botFwd.addString(botLogger.get(1).asString());
581  }
582  else
583  {
584  botFwd.addString(mLoggerPort);
585  }
586  }
587  else
588  {
589  botFwd.addString(mLoggerPort);
590  }
591  msg.addList()=botFwd;
592  }
593 
594  yarp::os::Bottle cmdResult;
595  if (executeCmdAndStdio(msg, cmdResult)>0)
596  {
597  if (strStdioPort==mPortName)
598  {
599  yarp::os::Bottle stdioResult;
600  userStdio(msg, stdioResult);
601  cmdResult.append(stdioResult);
602  }
603  else
604  {
605  cmdResult.append(sendMsg(msg, strStdioPort));
606  }
607  }
608 
609  port.reply(cmdResult);
610  }
611  else
612  {
613  yarp::os::Bottle stdioResult;
614  userStdio(msg, stdioResult);
615  port.reply(stdioResult);
616  }
617 
618  continue;
619  }
620 
621  // without stdio
622  if (msg.check("cmd"))
623  {
624  yarp::os::Bottle cmdResult;
625 
626  if (msg.check("log"))
627  {
628  yarp::os::Bottle botLogger=msg.findGroup("log");
629 
630  if (botLogger.size()>1)
631  {
632  std::string loggerName=botLogger.get(1).asString();
633  executeCmdStdout(msg, cmdResult, loggerName);
634  }
635  else
636  {
637  executeCmdStdout(msg, cmdResult, mLoggerPort);
638  }
639  }
640  else if (mLogged)
641  {
642  executeCmdStdout(msg, cmdResult, mLoggerPort);
643  }
644  else
645  {
646  executeCmd(msg, cmdResult);
647  }
648  port.reply(cmdResult);
649  continue;
650  }
651 
652  if (msg.check("kill"))
653  {
654  std::string alias(msg.findGroup("kill").get(1).asString());
655  int sig=msg.findGroup("kill").get(2).asInt32();
656  yarp::os::Bottle result;
657  result.addString(mProcessVector.Signal(alias, sig)?"kill OK":"kill FAILED");
658  port.reply(result);
659  continue;
660  }
661 
662  if (msg.check("sigterm"))
663  {
664  std::string alias(msg.find("sigterm").asString());
665  yarp::os::Bottle result;
666  result.addString(mProcessVector.Signal(alias, SIGTERM)?"sigterm OK":"sigterm FAILED");
667  port.reply(result);
668  continue;
669  }
670 
671  if (msg.check("sigtermall"))
672  {
673  mProcessVector.Killall(SIGTERM);
674  yarp::os::Bottle result;
675  result.addString("sigtermall OK");
676  port.reply(result);
677  continue;
678  }
679 
680  if (msg.check("ps"))
681  {
682  yarp::os::Bottle result;
683  result.append(mProcessVector.PS());
684  port.reply(result);
685  continue;
686  }
687 
688  if (msg.check("isrunning"))
689  {
690  std::string alias(msg.find("isrunning").asString());
691  yarp::os::Bottle result;
692  result.addString(mProcessVector.IsRunning(alias)?"running":"not running");
693  port.reply(result);
694  continue;
695  }
696 
697  if (msg.check("killstdio"))
698  {
699  std::string alias(msg.find("killstdio").asString());
700  mStdioVector.Signal(alias, SIGTERM);
701  yarp::os::Bottle result;
702  result.addString("killstdio OK");
703  port.reply(result);
704  continue;
705  }
706 
708 
709  if (msg.check("sysinfo"))
710  {
712  port.reply(sysinfo);
713  continue;
714  }
715 
716  if (msg.check("which"))
717  {
718  std::string fileName=msg.find("which").asString();
719  if (fileName!="")
720  {
722  for (int i=0; i<possiblePaths.size(); ++i)
723  {
724  std::string guessString=possiblePaths.get(i).asString() + slash + fileName;
725  const char* guess=guessString.c_str();
726  if (fileExists (guess))
727  {
728  fileName= "\"" + std::string(guess) + "\"";
729  break;
730  }
731  }
732  }
733  yarp::os::Value fileNameWriter(fileName);
734  port.reply(fileNameWriter);
735  continue;
736  }
737 
738  if (msg.check("exit"))
739  {
740  pServerPort=0;
741  yarp::os::Bottle result;
742  result.addString("exit OK");
743  port.reply(result);
744  port.close();
745  }
746  }
747 
748 
749  Run::mStdioVector.Killall(SIGTERM);
750 
751  Run::mProcessVector.Killall(SIGTERM);
752 
753  return 0;
754 }
755 
757 #else // LINUX SERVER
758 
760 void yarp::run::Run::cleanBeforeExec()
761 {
762  // zombie hunter stop
763 
764  //yarp::os::impl::signal(SIGPIPE, SIG_IGN);
765  //yarp::os::impl::signal(SIGCHLD, SIG_DFL);
766  //yarp::os::impl::signal(SIGINT, SIG_DFL);
767  //yarp::os::impl::signal(SIGTERM, SIG_DFL);
768 
769  if (mProcessVector)
770  {
771  YarpRunInfoVector *p=mProcessVector;
772  mProcessVector = nullptr;
773  delete p;
774  }
775  if (mStdioVector)
776  {
777  YarpRunInfoVector *p=mStdioVector;
778  mStdioVector = nullptr;
779  delete p;
780  }
781  if (mBraveZombieHunter)
782  {
783  ZombieHunterThread *p=mBraveZombieHunter;
784  mBraveZombieHunter = nullptr;
785  p->stop();
786  delete p;
787  }
788 
789  //yarp::os::Network::fini();
790 }
791 
792 void yarp::run::Run::writeToPipe(int fd, std::string str)
793 {
794  int len=str.length()+1;
795 
796  write(fd, &len, 4);
797  write(fd, str.c_str(), len);
798 }
799 
800 int yarp::run::Run::readFromPipe(int fd, char* &data, int& buffsize)
801 {
802  int len=0;
803  char* buff=(char*)&len;
804 
805  for (int c=4, r=0; c>0; c-=r)
806  {
807  r=read(fd, buff, c);
808 
809  if (r<1) return -1;
810 
811  buff+=r;
812  }
813 
814  if (len<=0) return 0;
815 
816  if (len>buffsize)
817  {
818  delete [] data;
819  data=new char[buffsize=1024+(len/1024)*1024];
820  }
821 
822  buff=data;
823 
824  for (int c=len, r=0; c>0; c-=r)
825  {
826  r=read(fd, buff, c);
827 
828  if (r<1) return -1;
829 
830  buff+=r;
831  }
832 
833  return len;
834 }
835 
836 static void sigchld_handler(int sig)
837 {
838  YARP_UNUSED(sig);
839  if (yarp::run::Run::mBraveZombieHunter)
840  {
841  yarp::run::Run::mBraveZombieHunter->sigchldHandler();
842  }
843 }
844 
845 int yarp::run::Run::server()
846 {
847  int pipe_server2manager[2];
848  int pipe_manager2server[2];
849 
850  if (yarp::run::impl::pipe(pipe_server2manager))
851  {
852  fprintf(stderr, "Can't open pipe because %s\n", strerror(errno));
853  fflush(stderr);
854 
855  return YARPRUN_ERROR;
856  }
857 
858  if (yarp::run::impl::pipe(pipe_manager2server))
859  {
860  fprintf(stderr, "Can't open pipe because %s\n", strerror(errno));
861  fflush(stderr);
862 
863  return YARPRUN_ERROR;
864  }
865 
866  int pid_process_manager=yarp::run::impl::fork();
867 
868  if (IS_INVALID(pid_process_manager))
869  {
870  int error=errno;
871 
872  CLOSE(pipe_server2manager[WRITE_TO_PIPE]);
873  CLOSE(pipe_server2manager[READ_FROM_PIPE]);
874  CLOSE(pipe_manager2server[WRITE_TO_PIPE]);
875  CLOSE(pipe_manager2server[READ_FROM_PIPE]);
876 
877  fprintf(stderr, "Can't fork process manager because %s\n", strerror(error));
878  fflush(stderr);
879 
880  return YARPRUN_ERROR;
881  }
882 
883  if (IS_PARENT_OF(pid_process_manager))
884  {
885  yarp::os::impl::signal(SIGPIPE, SIG_IGN);
886 
887  CLOSE(pipe_server2manager[READ_FROM_PIPE]);
888  CLOSE(pipe_manager2server[WRITE_TO_PIPE]);
889 
890  //yarp::os::Network::init();
892 
893  yarp::os::RpcServer port;
894 
895  if (!port.open(mPortName.c_str()))
896  {
897  yError() << "Yarprun failed to open port: " << mPortName.c_str();
898 
899  if (mPortName[0]!='/') yError("Invalid port name '%s', it should start with '/'\n", mPortName.c_str());
900  return YARPRUN_ERROR;
901  }
902  yarp::os::Bottle cmd, reply;
903  cmd.addString("set");
904  cmd.addString(port.getName());
905  cmd.addString("yarprun");
906  cmd.addString("true");
907 
909 
910  yInfo() << "Yarprun successfully started on port: " << mPortName.c_str();
911 
912  pServerPort=&port;
913 
914  yarp::os::impl::signal(SIGINT, sigint_handler);
915  yarp::os::impl::signal(SIGTERM, sigint_handler);
916 
917  int rsp_size=1024;
918  char *rsp_str=new char[rsp_size];
919 
920  yarp::os::Bottle msg, response;
921 
922  while (pServerPort)
923  {
924  RUNLOG("<<<port.read(msg, true)")
925  if (!port.read(msg, true)) break;
926  RUNLOG(">>>port.read(msg, true)")
927 
928  if (!pServerPort) break;
929 
930  if (msg.check("sysinfo"))
931  {
933  port.reply(sysinfo);
934  continue;
935  }
936 
937  if (msg.check("which"))
938  {
939  std::string fileName=msg.find("which").asString();
940  if (fileName!="")
941  {
943  for (size_t i=0; i<possiblePaths.size(); ++i)
944  {
945  std::string guessString=possiblePaths.get(i).asString() + slash + fileName;
946  const char* guess=guessString.c_str();
947  if (fileExists (guess))
948  {
949  fileName = guess;
950  break;
951  }
952  }
953  }
954  yarp::os::Value fileNameWriter(fileName);
955  port.reply(fileNameWriter);
956  continue;
957  }
958 
959  if (msg.check("exit"))
960  {
961  pServerPort = nullptr;
962  yarp::os::Bottle result;
963  result.addString("exit OK");
964  port.reply(result);
965  port.close();
966  break;
967  }
968 
969  RUNLOG("<<<writeToPipe")
970  writeToPipe(pipe_server2manager[WRITE_TO_PIPE], msg.toString());
971  RUNLOG(">>>writeToPipe")
972 
973  RUNLOG("<<<readFromPipe")
974  int nread=readFromPipe(pipe_manager2server[READ_FROM_PIPE], rsp_str, rsp_size);
975  RUNLOG(">>>readFromPipe")
976 
977  if (nread<0)
978  {
979  fprintf(stderr, "ERROR: broken pipe between server and manager\n");
980  fflush(stderr);
981  break;
982  }
983 
984  if (nread)
985  {
986  response.fromString(rsp_str);
987  port.reply(response);
988  }
989  }
990 
991  //yarp::os::Network::fini();
992 
993  CLOSE(pipe_server2manager[WRITE_TO_PIPE]);
994  CLOSE(pipe_manager2server[READ_FROM_PIPE]);
995 
996  delete [] rsp_str;
997 
998  return 0;
999  }
1000 
1001  if (IS_NEW_PROCESS(pid_process_manager))
1002  {
1003  yarp::os::impl::signal(SIGPIPE, SIG_IGN);
1004 
1005  CLOSE(pipe_server2manager[WRITE_TO_PIPE]);
1006  CLOSE(pipe_manager2server[READ_FROM_PIPE]);
1007 
1008  //yarp::os::Network::init();
1009 
1010  mProcessVector=new YarpRunInfoVector;
1011  mStdioVector=new YarpRunInfoVector;
1012 
1013  mBraveZombieHunter=new ZombieHunterThread;
1014  mBraveZombieHunter->start();
1015 
1016  yarp::os::impl::signal(SIGCHLD, sigchld_handler);
1017  //yarp::os::impl::signal(SIGINT, SIG_IGN);
1018  //yarp::os::impl::signal(SIGTERM, SIG_IGN);
1019 
1020  int msg_size=1024;
1021  char *msg_str=new char[msg_size];
1022 
1023  yarp::os::Bottle msg;
1024 
1025  //while(readFromPipe(pipe_server2manager[READ_FROM_PIPE], msg_str, msg_size)>0)
1026  while (true)
1027  {
1028  RUNLOG("<<<readFromPipe")
1029  if (readFromPipe(pipe_server2manager[READ_FROM_PIPE], msg_str, msg_size)<=0) break;
1030  RUNLOG(">>>readFromPipe")
1031 
1032  //printf("<<< %s >>>\n", msg_str);
1033  //fflush(stdout);
1034 
1035  msg.fromString(msg_str);
1036 
1037  // command with stdio management
1038  if (msg.check("stdio"))
1039  {
1040  std::string strOnPort=msg.find("on").asString();
1041  std::string strStdioPort=msg.find("stdio").asString();
1042 
1043  if (strOnPort==mPortName)
1044  {
1045  std::string strUUID=mPortName+"/"+int2String(getpid())+"/"+msg.find("as").asString()+"-"+int2String(mProcCNT++);
1046  yarp::os::Bottle botUUID;
1047  botUUID.addString("stdiouuid");
1048  botUUID.addString(strUUID.c_str());
1049  msg.addList()=botUUID;
1050 
1051  if (mLogged || msg.check("log"))
1052  {
1053  std::string strAlias=msg.find("as").asString();
1054  std::string portName="/log";
1055  portName+=mPortName+"/";
1056  std::string command=msg.findGroup("cmd").get(1).asString();
1057  size_t space=command.find(' ');
1058  if (space!=std::string::npos) command=command.substr(0, space);
1059  portName+=command;
1060 
1061  yarp::os::Bottle botFwd;
1062  botFwd.addString("forward");
1063  botFwd.addString(portName.c_str());
1064  if (msg.check("log"))
1065  {
1066  yarp::os::Bottle botLogger=msg.findGroup("log");
1067 
1068  if (botLogger.size()>1)
1069  {
1070  botFwd.addString(botLogger.get(1).asString());
1071  }
1072  else
1073  {
1074  botFwd.addString(mLoggerPort);
1075  }
1076  }
1077  else
1078  {
1079  botFwd.addString(mLoggerPort);
1080  }
1081  msg.addList()=botFwd;
1082 
1083  yarp::os::ContactStyle style;
1084  style.persistent=true;
1085  yarp::os::Network::connect(portName.c_str(), mLoggerPort.c_str(), style);
1086  }
1087 
1088  yarp::os::Bottle cmdResult;
1089  if (executeCmdAndStdio(msg, cmdResult)>0)
1090  {
1091  if (strStdioPort==mPortName)
1092  {
1093  yarp::os::Bottle stdioResult;
1094  userStdio(msg, stdioResult);
1095  cmdResult.append(stdioResult);
1096  }
1097  else
1098  {
1099  cmdResult.append(sendMsg(msg, strStdioPort));
1100  }
1101  }
1102 
1103  RUNLOG("<<<writeToPipe")
1104  writeToPipe(pipe_manager2server[WRITE_TO_PIPE], cmdResult.toString());
1105  RUNLOG(">>>writeToPipe")
1106  }
1107  else
1108  {
1109  yarp::os::Bottle stdioResult;
1110  userStdio(msg, stdioResult);
1111  RUNLOG("<<<writeToPipe")
1112  writeToPipe(pipe_manager2server[WRITE_TO_PIPE], stdioResult.toString());
1113  RUNLOG(">>>writeToPipe")
1114  }
1115 
1116  continue;
1117  }
1118 
1119  // without stdio
1120  if (msg.check("cmd"))
1121  {
1122  yarp::os::Bottle cmdResult;
1123 
1124  if (msg.check("log"))
1125  {
1126  yarp::os::Bottle botLogger=msg.findGroup("log");
1127 
1128  if (botLogger.size()>1)
1129  {
1130  std::string loggerName=botLogger.get(1).asString();
1131  executeCmdStdout(msg, cmdResult, loggerName);
1132  }
1133  else
1134  {
1135  executeCmdStdout(msg, cmdResult, mLoggerPort);
1136  }
1137  }
1138  else if (mLogged)
1139  {
1140  executeCmdStdout(msg, cmdResult, mLoggerPort);
1141  }
1142  else
1143  {
1144  executeCmd(msg, cmdResult);
1145  }
1146 
1147  RUNLOG("<<<writeToPipe")
1148  writeToPipe(pipe_manager2server[WRITE_TO_PIPE], cmdResult.toString());
1149  RUNLOG(">>>writeToPipe")
1150  continue;
1151  }
1152 
1153  if (msg.check("kill"))
1154  {
1155  std::string alias(msg.findGroup("kill").get(1).asString());
1156  int sig=msg.findGroup("kill").get(2).asInt32();
1157  yarp::os::Bottle result;
1158  result.addString(mProcessVector->Signal(alias, sig)?"kill OK":"kill FAILED");
1159  RUNLOG("<<<writeToPipe")
1160  writeToPipe(pipe_manager2server[WRITE_TO_PIPE], result.toString());
1161  RUNLOG(">>>writeToPipe")
1162  continue;
1163  }
1164 
1165  if (msg.check("sigterm"))
1166  {
1167  std::string alias(msg.find("sigterm").asString());
1168  yarp::os::Bottle result;
1169  result.addString(mProcessVector->Signal(alias, SIGTERM)?"sigterm OK":"sigterm FAILED");
1170  RUNLOG("<<<writeToPipe")
1171  writeToPipe(pipe_manager2server[WRITE_TO_PIPE], result.toString());
1172  RUNLOG(">>>writeToPipe")
1173  continue;
1174  }
1175 
1176  if (msg.check("sigtermall"))
1177  {
1178  mProcessVector->Killall(SIGTERM);
1179  yarp::os::Bottle result;
1180  result.addString("sigtermall OK");
1181 
1182  RUNLOG("<<<writeToPipe")
1183  writeToPipe(pipe_manager2server[WRITE_TO_PIPE], result.toString());
1184  RUNLOG(">>>writeToPipe")
1185  continue;
1186  }
1187 
1188  if (msg.check("ps"))
1189  {
1190  yarp::os::Bottle result;
1191  result.append(mProcessVector->PS());
1192  RUNLOG("<<<writeToPipe")
1193  writeToPipe(pipe_manager2server[WRITE_TO_PIPE], result.toString());
1194  RUNLOG(">>>writeToPipe")
1195  continue;
1196  }
1197 
1198  if (msg.check("isrunning"))
1199  {
1200  std::string alias(msg.find("isrunning").asString());
1201  yarp::os::Bottle result;
1202  result.addString(mProcessVector->IsRunning(alias)?"running":"not running");
1203  RUNLOG("<<<writeToPipe")
1204  writeToPipe(pipe_manager2server[WRITE_TO_PIPE], result.toString());
1205  RUNLOG(">>>writeToPipe")
1206  continue;
1207  }
1208 
1209  if (msg.check("killstdio"))
1210  {
1211  std::string alias(msg.find("killstdio").asString());
1212  mStdioVector->Signal(alias, SIGTERM);
1213  yarp::os::Bottle result;
1214  result.addString("killstdio OK");
1215  RUNLOG("<<<writeToPipe")
1216  writeToPipe(pipe_manager2server[WRITE_TO_PIPE], result.toString());
1217  RUNLOG(">>>writeToPipe")
1218  continue;
1219  }
1220  }
1221 
1222  mStdioVector->Killall(SIGTERM);
1223 
1224  mProcessVector->Killall(SIGTERM);
1225 
1226  if (mBraveZombieHunter)
1227  {
1228  mBraveZombieHunter->stop();
1229  delete mBraveZombieHunter;
1230  mBraveZombieHunter = nullptr;
1231  }
1232 
1233  delete mProcessVector;
1234 
1235  delete mStdioVector;
1236 
1237  //yarp::os::Network::fini();
1238 
1239  CLOSE(pipe_server2manager[READ_FROM_PIPE]);
1240  CLOSE(pipe_manager2server[WRITE_TO_PIPE]);
1241 
1242  delete [] msg_str;
1243  }
1244 
1245  return 0;
1246 } // LINUX SERVER
1247 #endif
1248 
1249 
1250 
1251 
1252 // CLIENT
1254 {
1255  // WITH STDIO
1256  //
1257  if (config.check("cmd") && config.check("stdio"))
1258  {
1260  // syntax check
1261  if (config.find("stdio").asString()=="")
1262  {
1263  Help("SYNTAX ERROR: missing remote stdio server\n");
1264  return YARPRUN_ERROR;
1265  }
1266  if (config.find("cmd").asString()=="")
1267  {
1268  Help("SYNTAX ERROR: missing command\n");
1269  return YARPRUN_ERROR;
1270  }
1271  if (!config.check("as") || config.find("as").asString()=="")
1272  {
1273  Help("SYNTAX ERROR: missing tag\n");
1274  return YARPRUN_ERROR;
1275  }
1276  if (!config.check("on") || config.find("on").asString()=="")
1277  {
1278  Help("SYNTAX ERROR: missing remote server\n");
1279  return YARPRUN_ERROR;
1280  }
1281  //
1283 
1284  printf("*********** %s ************\n", config.toString().c_str());
1285 
1286  yarp::os::Bottle msg;
1287  msg.addList()=config.findGroup("stdio");
1288  msg.addList()=config.findGroup("cmd");
1289  msg.addList()=config.findGroup("as");
1290  msg.addList()=config.findGroup("on");
1291 
1292  if (config.check("workdir")) msg.addList()=config.findGroup("workdir");
1293  if (config.check("geometry")) msg.addList()=config.findGroup("geometry");
1294  if (config.check("hold")) msg.addList()=config.findGroup("hold");
1295  if (config.check("env")) msg.addList()=config.findGroup("env");
1296  if (config.check("log")) msg.addList()=config.findGroup("log");
1297  /*
1298  {
1299  yarp::os::Bottle log;
1300  log.addString("log");
1301  log.addString("log");
1302  msg.addList()=log;
1303  }
1304  */
1305 
1306  std::string on=config.find("on").asString();
1307 
1308  yarp::os::Bottle response=sendMsg(msg, on);
1309 
1310  if (!response.size()) return YARPRUN_ERROR;
1311 
1312  if (response.get(0).asInt32()<=0) return 2;
1313 
1314  return 0;
1315  }
1316 
1317  // NO STDIO
1318  //
1319  if (config.check("cmd"))
1320  {
1322  // syntax check
1323  if (config.find("cmd").asString()=="")
1324  {
1325  Help("SYNTAX ERROR: missing command\n");
1326  return YARPRUN_ERROR;
1327  }
1328  if (!config.check("as") || config.find("as").asString()=="")
1329  {
1330  Help("SYNTAX ERROR: missing tag\n");
1331  return YARPRUN_ERROR;
1332  }
1333  if (!config.check("on") || config.find("on").asString()=="")
1334  {
1335  Help("SYNTAX ERROR: missing remote server\n");
1336  return YARPRUN_ERROR;
1337  }
1338  //
1340 
1341  yarp::os::Bottle msg;
1342  msg.addList()=config.findGroup("cmd");
1343  msg.addList()=config.findGroup("as");
1344 
1345  if (config.check("workdir")) msg.addList()=config.findGroup("workdir");
1346  if (config.check("log")) msg.addList()=config.findGroup("log");
1347  /*
1348  {
1349  yarp::os::Bottle log;
1350  log.addString("log");
1351  log.addString("log");
1352  msg.addList()=log;
1353  }
1354  */
1355  if (config.check("env")) msg.addList()=config.findGroup("env");
1356 
1357  yarp::os::Bottle response=sendMsg(msg, config.find("on").asString());
1358 
1359  if (!response.size()) return YARPRUN_ERROR;
1360 
1361  if (response.get(0).asInt32()<=0) return 2;
1362 
1363  return 0;
1364  }
1365 
1366 
1367 
1368 
1369 
1370  // client -> cmd server
1371  if (config.check("kill"))
1372  {
1373  if (!config.check("on") || config.find("on").asString()=="")
1374  {
1375  Help("SYNTAX ERROR: missing remote server\n");
1376  return YARPRUN_ERROR;
1377  }
1378  if (config.findGroup("kill").get(1).asString()=="")
1379  {
1380  Help("SYNTAX ERROR: missing tag\n");
1381  return YARPRUN_ERROR;
1382  }
1383  if (config.findGroup("kill").get(2).asInt32()==0)
1384  {
1385  Help("SYNTAX ERROR: missing signum\n");
1386  return YARPRUN_ERROR;
1387  }
1388 
1389  yarp::os::Bottle msg;
1390  msg.addList()=config.findGroup("kill");
1391 
1392  yarp::os::Bottle response=sendMsg(msg, config.find("on").asString());
1393 
1394  if (!response.size())
1395  {
1396  return YARPRUN_ERROR;
1397  }
1398 
1399  return response.get(0).asString()=="kill OK"?0:2;
1400  }
1401 
1402  // client -> cmd server
1403  if (config.check("sigterm"))
1404  {
1405  if (config.find("sigterm").asString()=="")
1406  {
1407  Help("SYNTAX ERROR: missing tag");
1408  return YARPRUN_ERROR;
1409  }
1410  if (!config.check("on") || config.find("on").asString()=="")
1411  {
1412  Help("SYNTAX ERROR: missing remote server\n");
1413  return YARPRUN_ERROR;
1414  }
1415 
1416  yarp::os::Bottle msg;
1417  msg.addList()=config.findGroup("sigterm");
1418 
1419  yarp::os::Bottle response=sendMsg(msg, config.find("on").asString());
1420 
1421  if (!response.size())
1422  {
1423  return YARPRUN_ERROR;
1424  }
1425 
1426  return response.get(0).asString()=="sigterm OK"?0:2;
1427  }
1428 
1429  // client -> cmd server
1430  if (config.check("sigtermall"))
1431  {
1432  if (!config.check("on") || config.find("on").asString()=="")
1433  {
1434  Help("SYNTAX ERROR: missing remote server\n");
1435  return YARPRUN_ERROR;
1436  }
1437 
1438  yarp::os::Bottle msg;
1439  msg.addList()=config.findGroup("sigtermall");
1440 
1441  yarp::os::Bottle response=sendMsg(msg, config.find("on").asString());
1442 
1443  if (!response.size())
1444  {
1445  return YARPRUN_ERROR;
1446  }
1447 
1448  return 0;
1449  }
1450 
1451  if (config.check("ps"))
1452  {
1453  if (!config.check("on") || config.find("on").asString()=="")
1454  {
1455  Help("SYNTAX ERROR: missing remote server\n");
1456  return YARPRUN_ERROR;
1457  }
1458 
1459  yarp::os::Bottle msg;
1460  msg.addList()=config.findGroup("ps");
1461 
1462  yarp::os::Bottle response=sendMsg(msg, config.find("on").asString());
1463 
1464  if (!response.size())
1465  {
1466  return YARPRUN_ERROR;
1467  }
1468 
1469  return 0;
1470  }
1471 
1472  if (config.check("isrunning"))
1473  {
1474  if (!config.check("on") || config.find("on").asString()=="")
1475  {
1476  Help("SYNTAX ERROR: missing remote server\n");
1477  return YARPRUN_ERROR;
1478  }
1479 
1480  if (config.find("isrunning").asString()=="")
1481  {
1482  Help("SYNTAX ERROR: missing tag\n");
1483  return YARPRUN_ERROR;
1484  }
1485 
1486  yarp::os::Bottle msg;
1487  msg.addList()=config.findGroup("isrunning");
1488 
1489  yarp::os::Bottle response=sendMsg(msg, config.find("on").asString());
1490 
1491  if (!response.size())
1492  {
1493  return YARPRUN_ERROR;
1494  }
1495 
1496  return response.get(0).asString()=="running"?0:2;
1497  }
1498 
1499  if (config.check("sysinfo"))
1500  {
1501  if (!config.check("on") || config.find("on").asString()=="")
1502  {
1503  Help("SYNTAX ERROR: missing remote server\n");
1504  return YARPRUN_ERROR;
1505  }
1506 
1507  yarp::os::Bottle msg;
1508  msg.addList()=config.findGroup("sysinfo");
1509 
1510  yarp::os::RpcClient port;
1511  //port.setTimeout(5.0);
1512  if (!port.open("..."))
1513  {
1514  fprintf(stderr, "RESPONSE:\n=========\n");
1515  fprintf(stderr, "Cannot open port, aborting...\n");
1516 
1517  return YARPRUN_ERROR;
1518  }
1519 
1520  bool connected = yarp::os::Network::connect(port.getName(), config.find("on").asString());
1521 
1522  if (!connected)
1523  {
1524  fprintf(stderr, "RESPONSE:\n=========\n");
1525  fprintf(stderr, "Cannot connect to remote server, aborting...\n");
1526  port.close();
1527  //yarp::os::Network::unregisterName(port.getName());
1528  return YARPRUN_ERROR;
1529  }
1530 
1532 
1533  RUNLOG("<<<port.write(msg, info)")
1534  int ret = port.write(msg, info);
1535  RUNLOG(">>>port.write(msg, info)")
1536  yarp::os::Network::disconnect(port.getName().c_str(), config.find("on").asString());
1537  port.close();
1538  //yarp::os::Network::unregisterName(port.getName());
1539  fprintf(stdout, "RESPONSE:\n=========\n\n");
1540 
1541  if (!ret)
1542  {
1543  fprintf(stdout, "No response. (timeout)\n");
1544 
1545  return YARPRUN_ERROR;
1546  }
1547 
1548  fprintf(stdout, "Platform name : %s\n", info.platform.name.c_str());
1549  fprintf(stdout, "Platform dist : %s\n", info.platform.distribution.c_str());
1550  fprintf(stdout, "Platform release : %s\n", info.platform.release.c_str());
1551  fprintf(stdout, "Platform code : %s\n", info.platform.codename.c_str());
1552  fprintf(stdout, "Platform kernel : %s\n\n", info.platform.kernel.c_str());
1553 
1554  fprintf(stdout, "User Id : %d\n", info.user.userID);
1555  fprintf(stdout, "User name : %s\n", info.user.userName.c_str());
1556  fprintf(stdout, "User real name : %s\n", info.user.realName.c_str());
1557  fprintf(stdout, "User home dir : %s\n\n", info.user.homeDir.c_str());
1558 
1559  fprintf(stdout, "Cpu load Ins.: %d\n", info.load.cpuLoadInstant);
1560  fprintf(stdout, "Cpu load 1 : %.2lf\n", info.load.cpuLoad1);
1561  fprintf(stdout, "Cpu load 5 : %.2lf\n", info.load.cpuLoad5);
1562  fprintf(stdout, "Cpu load 15 : %.2lf\n\n", info.load.cpuLoad15);
1563 
1564  fprintf(stdout, "Memory total : %dM\n", info.memory.totalSpace);
1565  fprintf(stdout, "Memory free : %dM\n\n", info.memory.freeSpace);
1566 
1567  fprintf(stdout, "Storage total : %dM\n", info.storage.totalSpace);
1568  fprintf(stdout, "Storage free : %dM\n\n", info.storage.freeSpace);
1569 
1570  fprintf(stdout, "Processor model : %s\n", info.processor.model.c_str());
1571  fprintf(stdout, "Processor model num : %d\n", info.processor.modelNumber);
1572  fprintf(stdout, "Processor family : %d\n", info.processor.family);
1573  fprintf(stdout, "Processor vendor : %s\n", info.processor.vendor.c_str());
1574  fprintf(stdout, "Processor arch : %s\n", info.processor.architecture.c_str());
1575  fprintf(stdout, "Processor cores : %d\n", info.processor.cores);
1576  fprintf(stdout, "Processor siblings : %d\n", info.processor.siblings);
1577  fprintf(stdout, "Processor Mhz : %.2lf\n\n", info.processor.frequency);
1578 
1579  fprintf(stdout, "Environment variables :\n%s\n", info.platform.environmentVars.toString().c_str());
1580  //fprintf(stdout, "Network IP4 : %s\n", info.network.ip4.c_str());
1581  //fprintf(stdout, "Network IP6 : %s\n", info.network.ip6.c_str());
1582  //fprintf(stdout, "Network mac : %s\n\n", info.network.mac.c_str());
1583 
1584  return 0;
1585  }
1586 
1587  if (config.check("which"))
1588  {
1589  if (!config.check("on") || config.find("on").asString()=="")
1590  {
1591  Help("SYNTAX ERROR: missing remote server\n");
1592 
1593  return YARPRUN_ERROR;
1594  }
1595 
1596  yarp::os::Bottle msg;
1597  msg.addList()=config.findGroup("which");
1598 
1599  yarp::os::Bottle response=sendMsg(msg, config.find("on").asString());
1600 
1601  if (!response.size())
1602  {
1603  return YARPRUN_ERROR;
1604  }
1605  return 0;
1606  }
1607 
1608  if (config.check("exit"))
1609  {
1610  if (!config.check("on") || config.find("on").asString()=="")
1611  {
1612  Help("SYNTAX ERROR: missing remote server\n");
1613 
1614  return YARPRUN_ERROR;
1615  }
1616 
1617  yarp::os::Bottle msg;
1618  msg.addList()=config.findGroup("exit");
1619 
1620  yarp::os::Bottle response=sendMsg(msg, config.find("on").asString());
1621 
1622  if (!response.size())
1623  {
1624  return YARPRUN_ERROR;
1625  }
1626 
1627  return 0;
1628  }
1629 
1630  return 0;
1631 }
1632 
1633 void yarp::run::Run::Help(const char *msg)
1634 {
1635  fprintf(stderr, "%s", msg);
1636  fprintf(stderr, "\nUSAGE:\n\n");
1637  fprintf(stderr, "yarp run --server SERVERPORT\nrun a server on the local machine\n\n");
1638  fprintf(stderr, "yarp run --on SERVERPORT --as TAG --cmd COMMAND [ARGLIST] [--workdir WORKDIR] [--env ENVIRONMENT]\nrun a command on SERVERPORT server\n\n");
1639  fprintf(stderr, "yarp run --on SERVERPORT --as TAG --stdio STDIOSERVERPORT [--hold] [--geometry WxH+X+Y] --cmd COMMAND [ARGLIST] [--workdir WORKDIR] [--env ENVIRONMENT]\n");
1640  fprintf(stderr, "run a command on SERVERPORT server sending I/O to STDIOSERVERPORT server\n\n");
1641  fprintf(stderr, "yarp run --on SERVERPORT --kill TAG SIGNUM\nsend SIGNUM signal to TAG command\n\n");
1642  fprintf(stderr, "yarp run --on SERVERPORT --sigterm TAG\nterminate TAG command\n\n");
1643  fprintf(stderr, "yarp run --on SERVERPORT --sigtermall\nterminate all commands\n\n");
1644  fprintf(stderr, "yarp run --on SERVERPORT --ps\nreport commands running on SERVERPORT\n\n");
1645  fprintf(stderr, "yarp run --on SERVERPORT --isrunning TAG\nTAG command is running?\n\n");
1646  fprintf(stderr, "yarp run --on SERVERPORT --sysinfo\nreport system information of SERVERPORT\n\n");
1647  fprintf(stderr, "yarp run --on SERVERPORT --exit\nstop SERVERPORT server\n\n");
1648 }
1649 
1651 // OS DEPENDENT FUNCTIONS
1653 
1654 // WINDOWS
1655 
1656 #if defined(_WIN32)
1657 
1658 // CMD SERVER
1659 int yarp::run::Run::executeCmdAndStdio(yarp::os::Bottle& msg, yarp::os::Bottle& result)
1660 {
1661  std::string strAlias=msg.find("as").asString();
1662  std::string strStdio=msg.find("stdio").asString();
1663  std::string strStdioUUID=msg.find("stdiouuid").asString();
1664  //std::string strCmdUUID=mPortName+"/"+int2String(GetCurrentProcessId())+"/"+strAlias+"-"+int2String(mProcCNT++);
1665 
1666  // PIPES
1667  SECURITY_ATTRIBUTES pipe_sec_attr;
1668  pipe_sec_attr.nLength=sizeof(SECURITY_ATTRIBUTES);
1669  pipe_sec_attr.bInheritHandle=TRUE;
1670  pipe_sec_attr.lpSecurityDescriptor = nullptr;
1671  HANDLE read_from_pipe_stdin_to_cmd, write_to_pipe_stdin_to_cmd;
1672  CreatePipe(&read_from_pipe_stdin_to_cmd, &write_to_pipe_stdin_to_cmd, &pipe_sec_attr, 0);
1673  HANDLE read_from_pipe_cmd_to_stdout, write_to_pipe_cmd_to_stdout;
1674  CreatePipe(&read_from_pipe_cmd_to_stdout, &write_to_pipe_cmd_to_stdout, &pipe_sec_attr, 0);
1675 
1676  // RUN STDOUT
1677  PROCESS_INFORMATION stdout_process_info;
1678  ZeroMemory(&stdout_process_info, sizeof(PROCESS_INFORMATION));
1679  STARTUPINFO stdout_startup_info;
1680  ZeroMemory(&stdout_startup_info, sizeof(STARTUPINFO));
1681 
1682  stdout_startup_info.cb=sizeof(STARTUPINFO);
1683  stdout_startup_info.hStdError=GetStdHandle(STD_ERROR_HANDLE);
1684  stdout_startup_info.hStdOutput=GetStdHandle(STD_OUTPUT_HANDLE);
1685  stdout_startup_info.hStdInput=read_from_pipe_cmd_to_stdout;
1686  stdout_startup_info.dwFlags|=STARTF_USESTDHANDLES;
1687 
1688  BOOL bSuccess=CreateProcess(nullptr, // command name
1689  (char*)(std::string("yarprun --write ")+strStdioUUID).c_str(), // command line
1690  nullptr, // process security attributes
1691  nullptr, // primary thread security attributes
1692  TRUE, // handles are inherited
1693  CREATE_NEW_PROCESS_GROUP, // creation flags
1694  nullptr, // use parent's environment
1695  nullptr, // use parent's current directory
1696  &stdout_startup_info, // STARTUPINFO pointer
1697  &stdout_process_info); // receives PROCESS_INFORMATION
1698 
1699  if (!bSuccess)
1700  {
1701  std::string strError=std::string("ABORTED: server=")+mPortName
1702  +std::string(" alias=")+strAlias
1703  +std::string(" cmd=stdout\n")
1704  +std::string("Can't execute stdout because ")+lastError2String()
1705  +std::string("\n");
1706 
1707  result.addInt32(YARPRUN_ERROR);
1708  result.addString(strError.c_str());
1709  fprintf(stderr, "%s", strError.c_str());
1710  fflush(stderr);
1711 
1712  CloseHandle(write_to_pipe_stdin_to_cmd);
1713  CloseHandle(read_from_pipe_stdin_to_cmd);
1714  CloseHandle(write_to_pipe_cmd_to_stdout);
1715  CloseHandle(read_from_pipe_cmd_to_stdout);
1716 
1717  return YARPRUN_ERROR;
1718  }
1719 
1720  // RUN STDIN
1721 
1722  PROCESS_INFORMATION stdin_process_info;
1723  ZeroMemory(&stdin_process_info, sizeof(PROCESS_INFORMATION));
1724  STARTUPINFO stdin_startup_info;
1725  ZeroMemory(&stdin_startup_info, sizeof(STARTUPINFO));
1726 
1727  stdin_startup_info.cb=sizeof(STARTUPINFO);
1728  stdin_startup_info.hStdError=write_to_pipe_stdin_to_cmd;
1729  stdin_startup_info.hStdOutput=write_to_pipe_stdin_to_cmd;
1730  stdin_startup_info.hStdInput=GetStdHandle(STD_INPUT_HANDLE);
1731  stdin_startup_info.dwFlags|=STARTF_USESTDHANDLES;
1732 
1733  bSuccess=CreateProcess(nullptr, // command name
1734  (char*)(std::string("yarprun --read ")+strStdioUUID).c_str(), // command line
1735  nullptr, // process security attributes
1736  nullptr, // primary thread security attributes
1737  TRUE, // handles are inherited
1738  CREATE_NEW_PROCESS_GROUP, // creation flags
1739  nullptr, // use parent's environment
1740  nullptr, // use parent's current directory
1741  &stdin_startup_info, // STARTUPINFO pointer
1742  &stdin_process_info); // receives PROCESS_INFORMATION
1743 
1744  if (!bSuccess)
1745  {
1746  std::string strError=std::string("ABORTED: server=")+mPortName
1747  +std::string(" alias=")+strAlias
1748  +std::string(" cmd=stdin\n")
1749  +std::string("Can't execute stdin because ")+lastError2String()
1750  +std::string("\n");
1751 
1752  result.addInt32(YARPRUN_ERROR);
1753  result.addString(strError.c_str());
1754  fprintf(stderr, "%s", strError.c_str());
1755 
1756  TerminateProcess(stdout_process_info.hProcess, YARPRUN_ERROR);
1757 
1758  CloseHandle(stdout_process_info.hProcess);
1759 
1760  CloseHandle(write_to_pipe_stdin_to_cmd);
1761  CloseHandle(read_from_pipe_stdin_to_cmd);
1762  CloseHandle(write_to_pipe_cmd_to_stdout);
1763  CloseHandle(read_from_pipe_cmd_to_stdout);
1764 
1765  return YARPRUN_ERROR;
1766  }
1767 
1768  // RUN COMMAND
1769 
1770  PROCESS_INFORMATION cmd_process_info;
1771  ZeroMemory(&cmd_process_info, sizeof(PROCESS_INFORMATION));
1772  STARTUPINFO cmd_startup_info;
1773  ZeroMemory(&cmd_startup_info, sizeof(STARTUPINFO));
1774 
1775  cmd_startup_info.cb=sizeof(STARTUPINFO);
1776  cmd_startup_info.hStdError=write_to_pipe_cmd_to_stdout;
1777  cmd_startup_info.hStdOutput=write_to_pipe_cmd_to_stdout;
1778  cmd_startup_info.hStdInput=read_from_pipe_stdin_to_cmd;
1779  cmd_startup_info.dwFlags|=STARTF_USESTDHANDLES;
1780 
1781  yarp::os::Bottle botCmd=msg.findGroup("cmd").tail();
1782 
1783  std::string strCmd;
1784  for (int s=0; s<botCmd.size(); ++s)
1785  {
1786  strCmd+=botCmd.get(s).toString()+std::string(" ");
1787  }
1788 
1789  /*
1790  * setting environment variable for child process
1791  */
1792  TCHAR chNewEnv[32767];
1793 
1794  // Get a pointer to the env block.
1795  LPTCH chOldEnv = GetEnvironmentStrings();
1796 
1797  // copying parent env variables
1798  LPTSTR lpOld = (LPTSTR) chOldEnv;
1799  LPTSTR lpNew = (LPTSTR) chNewEnv;
1800  while (*lpOld)
1801  {
1802  lstrcpy(lpNew, lpOld);
1803  lpOld += lstrlen(lpOld) + 1;
1804  lpNew += lstrlen(lpNew) + 1;
1805  }
1806 
1807  // adding new env variables
1808  std::string cstrEnvName;
1809  if (msg.check("env"))
1810  {
1811  yarp::os::impl::SplitString ss(msg.find("env").asString().c_str(), ';');
1812  for(int i=0; i<ss.size(); i++) {
1813  lstrcpy(lpNew, (LPTCH) ss.get(i));
1814  lpNew += lstrlen(lpNew) + 1;
1815  }
1816  }
1817 
1818  // closing env block
1819  *lpNew = (TCHAR)0;
1820 
1821  bool bWorkdir=msg.check("workdir");
1822  std::string strWorkdir=bWorkdir?msg.find("workdir").asString()+"\\":"";
1823 
1824  bSuccess=CreateProcess(nullptr, // command name
1825  (char*)(strWorkdir+strCmd).c_str(), // command line
1826  nullptr, // process security attributes
1827  nullptr, // primary thread security attributes
1828  TRUE, // handles are inherited
1829  CREATE_NEW_PROCESS_GROUP, // creation flags
1830  (LPVOID) chNewEnv, // use new environment list
1831  bWorkdir ? strWorkdir.c_str() : nullptr, // working directory
1832  &cmd_startup_info, // STARTUPINFO pointer
1833  &cmd_process_info); // receives PROCESS_INFORMATION
1834 
1835  if (!bSuccess && bWorkdir)
1836  {
1837  bSuccess=CreateProcess(nullptr, // command name
1838  (char*)(strCmd.c_str()), // command line
1839  nullptr, // process security attributes
1840  nullptr, // primary thread security attributes
1841  TRUE, // handles are inherited
1842  CREATE_NEW_PROCESS_GROUP, // creation flags
1843  (LPVOID) chNewEnv, // use new environment list
1844  strWorkdir.c_str(), // working directory
1845  &cmd_startup_info, // STARTUPINFO pointer
1846  &cmd_process_info); // receives PROCESS_INFORMATION
1847  }
1848 
1849  // deleting old environment variable
1850  FreeEnvironmentStrings(chOldEnv);
1851 
1852  if (!bSuccess)
1853  {
1854  result.addInt32(YARPRUN_ERROR);
1855 
1856  DWORD nBytes;
1857  std::string line1=std::string("ABORTED: server=")+mPortName
1858  +std::string(" alias=")+strAlias
1859  +std::string(" cmd=")+strCmd
1860  +std::string("pid=")+int2String(cmd_process_info.dwProcessId)
1861  +std::string("\n");
1862 
1863  WriteFile(write_to_pipe_cmd_to_stdout, line1.c_str(), line1.length(), &nBytes, 0);
1864 
1865  std::string line2=std::string("Can't execute command because ")+lastError2String()+std::string("\n");
1866  WriteFile(write_to_pipe_cmd_to_stdout, line1.c_str(), line2.length(), &nBytes, 0);
1867  FlushFileBuffers(write_to_pipe_cmd_to_stdout);
1868 
1869  std::string out=line1+line2;
1870  result.addString(out.c_str());
1871  fprintf(stderr, "%s", out.c_str());
1872  fflush(stderr);
1873 
1874  CloseHandle(write_to_pipe_stdin_to_cmd);
1875  CloseHandle(read_from_pipe_stdin_to_cmd);
1876  CloseHandle(write_to_pipe_cmd_to_stdout);
1877  CloseHandle(read_from_pipe_cmd_to_stdout);
1878 
1879  TerminateProcess(stdout_process_info.hProcess, YARPRUN_ERROR);
1880 
1881  CloseHandle(stdout_process_info.hProcess);
1882 
1883  TerminateProcess(stdin_process_info.hProcess, YARPRUN_ERROR);
1884 
1885  CloseHandle(stdin_process_info.hProcess);
1886 
1887  return YARPRUN_ERROR;
1888  }
1889 
1890  FlushFileBuffers(write_to_pipe_cmd_to_stdout);
1891 
1892  // EVERYTHING IS ALL RIGHT
1893  YarpRunCmdWithStdioInfo* pInf = new YarpRunCmdWithStdioInfo(strAlias,
1894  mPortName,
1895  strStdio,
1896  cmd_process_info.dwProcessId,
1897  strStdioUUID,
1898  &mStdioVector,
1899  stdin_process_info.dwProcessId,
1900  stdout_process_info.dwProcessId,
1901  read_from_pipe_stdin_to_cmd,
1902  write_to_pipe_stdin_to_cmd,
1903  read_from_pipe_cmd_to_stdout,
1904  write_to_pipe_cmd_to_stdout,
1905  cmd_process_info.hProcess,
1906  false);
1907 
1908  pInf->setCmd(strCmd);
1909  if (msg.check("env"))
1910  {
1911  pInf->setEnv(msg.find("env").asString());
1912  }
1913  mProcessVector.Add(pInf);
1914 
1915  result.addInt32(cmd_process_info.dwProcessId);
1916  std::string out=std::string("STARTED: server=")+mPortName
1917  +std::string(" alias=")+strAlias
1918  +std::string(" cmd=")+strCmd
1919  +std::string("pid=")+int2String(cmd_process_info.dwProcessId)
1920  +std::string("\n");
1921 
1922  result.addString(out.c_str());
1923  result.addString(strStdioUUID.c_str());
1924  fprintf(stderr, "%s", out.c_str());
1925 
1926  return cmd_process_info.dwProcessId;
1927 }
1928 
1929 int yarp::run::Run::executeCmdStdout(yarp::os::Bottle& msg, yarp::os::Bottle& result, std::string& loggerName)
1930 {
1931  std::string strAlias=msg.find("as").asString();
1932  std::string portName="/log";
1933  portName+=mPortName+"/";
1934  std::string command=msg.findGroup("cmd").get(1).asString();
1935  int space=command.find(" ");
1936  if (space!=std::string::npos) command=command.substr(0, space);
1937  portName+=command;
1938 
1939  // PIPES
1940  SECURITY_ATTRIBUTES pipe_sec_attr;
1941  pipe_sec_attr.nLength=sizeof(SECURITY_ATTRIBUTES);
1942  pipe_sec_attr.bInheritHandle=TRUE;
1943  pipe_sec_attr.lpSecurityDescriptor = nullptr;
1944  HANDLE read_from_pipe_cmd_to_stdout, write_to_pipe_cmd_to_stdout;
1945  CreatePipe(&read_from_pipe_cmd_to_stdout, &write_to_pipe_cmd_to_stdout, &pipe_sec_attr, 0);
1946 
1947  // RUN STDOUT
1948  PROCESS_INFORMATION stdout_process_info;
1949  ZeroMemory(&stdout_process_info, sizeof(PROCESS_INFORMATION));
1950  STARTUPINFO stdout_startup_info;
1951  ZeroMemory(&stdout_startup_info, sizeof(STARTUPINFO));
1952 
1953  stdout_startup_info.cb=sizeof(STARTUPINFO);
1954  stdout_startup_info.hStdError=GetStdHandle(STD_ERROR_HANDLE);
1955  stdout_startup_info.hStdOutput=GetStdHandle(STD_OUTPUT_HANDLE);
1956  stdout_startup_info.hStdInput=read_from_pipe_cmd_to_stdout;
1957  stdout_startup_info.dwFlags|=STARTF_USESTDHANDLES;
1958 
1959  BOOL bSuccess=CreateProcess(nullptr, // command name
1960  (char*)(std::string("yarprun --log ")+loggerName+std::string(" --write ")+portName).c_str(), // command line
1961  nullptr, // process security attributes
1962  nullptr, // primary thread security attributes
1963  TRUE, // handles are inherited
1964  CREATE_NEW_PROCESS_GROUP, // creation flags
1965  nullptr, // use parent's environment
1966  nullptr, // use parent's current directory
1967  &stdout_startup_info, // STARTUPINFO pointer
1968  &stdout_process_info); // receives PROCESS_INFORMATION
1969 
1970  if (!bSuccess)
1971  {
1972  std::string strError=std::string("ABORTED: server=")+mPortName
1973  +std::string(" alias=")+strAlias
1974  +std::string(" cmd=stdout\n")
1975  +std::string("Can't execute stdout because ")+lastError2String()
1976  +std::string("\n");
1977 
1978  result.addInt32(YARPRUN_ERROR);
1979  result.addString(strError.c_str());
1980  fprintf(stderr, "%s", strError.c_str());
1981  fflush(stderr);
1982 
1983  CloseHandle(write_to_pipe_cmd_to_stdout);
1984  CloseHandle(read_from_pipe_cmd_to_stdout);
1985 
1986  return YARPRUN_ERROR;
1987  }
1988 
1989  // RUN COMMAND
1990 
1991  PROCESS_INFORMATION cmd_process_info;
1992  ZeroMemory(&cmd_process_info, sizeof(PROCESS_INFORMATION));
1993  STARTUPINFO cmd_startup_info;
1994  ZeroMemory(&cmd_startup_info, sizeof(STARTUPINFO));
1995 
1996  cmd_startup_info.cb=sizeof(STARTUPINFO);
1997  cmd_startup_info.hStdError=write_to_pipe_cmd_to_stdout;
1998  cmd_startup_info.hStdOutput=write_to_pipe_cmd_to_stdout;
1999  cmd_startup_info.hStdInput=GetStdHandle(STD_INPUT_HANDLE);
2000  cmd_startup_info.dwFlags|=STARTF_USESTDHANDLES;
2001 
2002  yarp::os::Bottle botCmd=msg.findGroup("cmd").tail();
2003 
2004  std::string strCmd;
2005  for (int s=0; s<botCmd.size(); ++s)
2006  {
2007  strCmd+=botCmd.get(s).toString()+std::string(" ");
2008  }
2009 
2010  /*
2011  * setting environment variable for child process
2012  */
2013  TCHAR chNewEnv[32767];
2014 
2015  // Get a pointer to the env block.
2016  LPTCH chOldEnv = GetEnvironmentStrings();
2017 
2018  // copying parent env variables
2019  LPTSTR lpOld = (LPTSTR) chOldEnv;
2020  LPTSTR lpNew = (LPTSTR) chNewEnv;
2021  while (*lpOld)
2022  {
2023  lstrcpy(lpNew, lpOld);
2024  lpOld += lstrlen(lpOld) + 1;
2025  lpNew += lstrlen(lpNew) + 1;
2026  }
2027 
2028  // adding new env variables
2029  std::string cstrEnvName;
2030  if (msg.check("env"))
2031  {
2032  lstrcpy(lpNew, (LPTCH) msg.find("env").asString().c_str());
2033  lpNew += lstrlen(lpNew) + 1;
2034  }
2035 
2036  // closing env block
2037  *lpNew = (TCHAR)0;
2038 
2039  bool bWorkdir=msg.check("workdir");
2040  std::string strWorkdir=bWorkdir?msg.find("workdir").asString()+"\\":"";
2041 
2042  bSuccess=CreateProcess(nullptr, // command name
2043  (char*)(strWorkdir+strCmd).c_str(), // command line
2044  nullptr, // process security attributes
2045  nullptr, // primary thread security attributes
2046  TRUE, // handles are inherited
2047  CREATE_NEW_PROCESS_GROUP, // creation flags
2048  (LPVOID) chNewEnv, // use new environment list
2049  bWorkdir?strWorkdir.c_str():nullptr, // working directory
2050  &cmd_startup_info, // STARTUPINFO pointer
2051  &cmd_process_info); // receives PROCESS_INFORMATION
2052 
2053  if (!bSuccess && bWorkdir)
2054  {
2055  bSuccess=CreateProcess(nullptr, // command name
2056  (char*)(strCmd.c_str()), // command line
2057  nullptr, // process security attributes
2058  nullptr, // primary thread security attributes
2059  TRUE, // handles are inherited
2060  CREATE_NEW_PROCESS_GROUP, // creation flags
2061  (LPVOID) chNewEnv, // use new environment list
2062  strWorkdir.c_str(), // working directory
2063  &cmd_startup_info, // STARTUPINFO pointer
2064  &cmd_process_info); // receives PROCESS_INFORMATION
2065  }
2066 
2067  // deleting old environment variable
2068  FreeEnvironmentStrings(chOldEnv);
2069 
2070  if (!bSuccess)
2071  {
2072  result.addInt32(YARPRUN_ERROR);
2073 
2074  DWORD nBytes;
2075  std::string line1=std::string("ABORTED: server=")+mPortName
2076  +std::string(" alias=")+strAlias
2077  +std::string(" cmd=")+strCmd
2078  +std::string("pid=")+int2String(cmd_process_info.dwProcessId)
2079  +std::string("\n");
2080 
2081  WriteFile(write_to_pipe_cmd_to_stdout, line1.c_str(), line1.length(), &nBytes, 0);
2082 
2083  std::string line2=std::string("Can't execute command because ")+lastError2String()+std::string("\n");
2084  WriteFile(write_to_pipe_cmd_to_stdout, line1.c_str(), line2.length(), &nBytes, 0);
2085  FlushFileBuffers(write_to_pipe_cmd_to_stdout);
2086 
2087  std::string out=line1+line2;
2088  result.addString(out.c_str());
2089  fprintf(stderr, "%s", out.c_str());
2090  fflush(stderr);
2091 
2092  CloseHandle(write_to_pipe_cmd_to_stdout);
2093  CloseHandle(read_from_pipe_cmd_to_stdout);
2094 
2095  TerminateProcess(stdout_process_info.hProcess, YARPRUN_ERROR);
2096 
2097  CloseHandle(stdout_process_info.hProcess);
2098 
2099  return YARPRUN_ERROR;
2100  }
2101 
2102  FlushFileBuffers(write_to_pipe_cmd_to_stdout);
2103 
2104  // EVERYTHING IS ALL RIGHT
2105  YarpRunCmdWithStdioInfo* pInf = new YarpRunCmdWithStdioInfo(strAlias,
2106  mPortName,
2107  portName,
2108  cmd_process_info.dwProcessId,
2109  stdout_process_info.dwProcessId,
2110  read_from_pipe_cmd_to_stdout,
2111  write_to_pipe_cmd_to_stdout,
2112  cmd_process_info.hProcess,
2113  false);
2114 
2115 
2116 
2117 
2118  pInf->setCmd(strCmd);
2119  if (msg.check("env"))
2120  {
2121  pInf->setEnv(msg.find("env").asString());
2122  }
2123  mProcessVector.Add(pInf);
2124 
2125  result.addInt32(cmd_process_info.dwProcessId);
2126  std::string out=std::string("STARTED: server=")+mPortName
2127  +std::string(" alias=")+strAlias
2128  +std::string(" cmd=")+strCmd
2129  +std::string("pid=")+int2String(cmd_process_info.dwProcessId)
2130  +std::string("\n");
2131 
2132  result.addString(out.c_str());
2133  result.addString(portName.c_str());
2134  fprintf(stderr, "%s", out.c_str());
2135 
2136  return cmd_process_info.dwProcessId;
2137 }
2138 
2139 
2140 int yarp::run::Run::executeCmd(yarp::os::Bottle& msg, yarp::os::Bottle& result)
2141 {
2142  std::string strAlias=msg.find("as").asString().c_str();
2143 
2144  // RUN COMMAND
2145  PROCESS_INFORMATION cmd_process_info;
2146  ZeroMemory(&cmd_process_info, sizeof(PROCESS_INFORMATION));
2147  STARTUPINFO cmd_startup_info;
2148  ZeroMemory(&cmd_startup_info, sizeof(STARTUPINFO));
2149 
2150  cmd_startup_info.cb=sizeof(STARTUPINFO);
2151 
2152  yarp::os::Bottle botCmd=msg.findGroup("cmd").tail();
2153 
2154  std::string strCmd;
2155  for (int s=0; s<botCmd.size(); ++s)
2156  {
2157  strCmd+=botCmd.get(s).toString()+std::string(" ");
2158  }
2159 
2160  /*
2161  if (msg.check("env"))
2162  {
2163  int pos = msg.find("env").asString().find("=");
2164  if (pos)
2165  {
2166  std::string cstrName = msg.find("env").asString().substr(0, pos);
2167  int nValue = msg.find("env").asString().length() -
2168  cstrName.length() - 1;
2169  std::string cstrValue = msg.find("env").asString().substr(pos+1, nValue);
2170  SetEnvironmentVariable(cstrName.c_str(), cstrValue.c_str());
2171  }
2172 
2173  }
2174  */
2175 
2176  /*
2177  * setting environment variable for child process
2178  */
2179  TCHAR chNewEnv[32767];
2180 
2181  // Get a pointer to the env block.
2182  LPTCH chOldEnv = GetEnvironmentStrings();
2183 
2184  // copying parent env variables
2185  LPTSTR lpOld = (LPTSTR) chOldEnv;
2186  LPTSTR lpNew = (LPTSTR) chNewEnv;
2187  while (*lpOld)
2188  {
2189  lstrcpy(lpNew, lpOld);
2190  lpOld += lstrlen(lpOld) + 1;
2191  lpNew += lstrlen(lpNew) + 1;
2192  }
2193 
2194  // adding new env variables
2195  std::string cstrEnvName;
2196  if (msg.check("env"))
2197  {
2198  lstrcpy(lpNew, (LPTCH) msg.find("env").asString().c_str());
2199  lpNew += lstrlen(lpNew) + 1;
2200  }
2201 
2202  // closing env block
2203  *lpNew = (TCHAR)0;
2204 
2205  bool bWorkdir=msg.check("workdir");
2206  std::string strWorkdir=bWorkdir?msg.find("workdir").asString()+"\\":"";
2207 
2208  BOOL bSuccess=CreateProcess(nullptr, // command name
2209  (char*)(strWorkdir+strCmd).c_str(), // command line
2210  nullptr, // process security attributes
2211  nullptr, // primary thread security attributes
2212  TRUE, // handles are inherited
2213  CREATE_NEW_PROCESS_GROUP, // creation flags
2214  (LPVOID) chNewEnv, // use new environment
2215  bWorkdir ? strWorkdir.c_str() : nullptr, // working directory
2216  &cmd_startup_info, // STARTUPINFO pointer
2217  &cmd_process_info); // receives PROCESS_INFORMATION
2218 
2219  if (!bSuccess && bWorkdir)
2220  {
2221  bSuccess=CreateProcess(nullptr, // command name
2222  (char*)(strCmd.c_str()), // command line
2223  nullptr, // process security attributes
2224  nullptr, // primary thread security attributes
2225  TRUE, // handles are inherited
2226  CREATE_NEW_PROCESS_GROUP, // creation flags
2227  (LPVOID) chNewEnv, // use new environment
2228  strWorkdir.c_str(), // working directory
2229  &cmd_startup_info, // STARTUPINFO pointer
2230  &cmd_process_info); // receives PROCESS_INFORMATION
2231  }
2232 
2233  // deleting old environment variable
2234  FreeEnvironmentStrings(chOldEnv);
2235 
2236  if (!bSuccess)
2237  {
2238  result.addInt32(YARPRUN_ERROR);
2239 
2240  std::string out=std::string("ABORTED: server=")+mPortName
2241  +std::string(" alias=")+strAlias
2242  +std::string(" cmd=")+strCmd
2243  +std::string(" pid=")+int2String(cmd_process_info.dwProcessId)
2244  +std::string("\nCan't execute command because ")+lastError2String()
2245  +std::string("\n");
2246 
2247  result.addString(out.c_str());
2248  fprintf(stderr, "%s", out.c_str());
2249  fflush(stderr);
2250 
2251  return YARPRUN_ERROR;
2252  }
2253 
2254  // EVERYTHING IS ALL RIGHT
2255  YarpRunProcInfo* pInf = new YarpRunProcInfo(strAlias,
2256  mPortName,
2257  cmd_process_info.dwProcessId,
2258  cmd_process_info.hProcess,
2259  false);
2260  pInf->setCmd(strCmd);
2261  if (msg.check("env"))
2262  pInf->setEnv(msg.find("env").asString());
2263 
2264  mProcessVector.Add(pInf);
2265 
2266  result.addInt32(cmd_process_info.dwProcessId);
2267  std::string out=std::string("STARTED: server=")+mPortName
2268  +std::string(" alias=")+strAlias
2269  +std::string(" cmd=")+strCmd
2270  +std::string("pid=")+int2String(cmd_process_info.dwProcessId)
2271  +std::string("\n");
2272 
2273  fprintf(stderr, "%s", out.c_str());
2274 
2275  return cmd_process_info.dwProcessId;
2276 }
2277 
2278 // STDIO SERVER
2279 int yarp::run::Run::userStdio(yarp::os::Bottle& msg, yarp::os::Bottle& result)
2280 {
2281  PROCESS_INFORMATION stdio_process_info;
2282  ZeroMemory(&stdio_process_info, sizeof(PROCESS_INFORMATION));
2283 
2284  STARTUPINFO stdio_startup_info;
2285  ZeroMemory(&stdio_startup_info, sizeof(STARTUPINFO));
2286  stdio_startup_info.cb=sizeof(STARTUPINFO);
2287  stdio_startup_info.wShowWindow=SW_SHOWNOACTIVATE;
2288  stdio_startup_info.dwFlags=STARTF_USESHOWWINDOW;
2289 
2290  std::string strAlias=msg.find("as").asString();
2291  std::string strUUID=msg.find("stdiouuid").asString();
2292  std::string strCmd=std::string("yarprun --readwrite ")+strUUID;
2293  if (msg.check("forward")) strCmd+=std::string(" --forward ")+msg.findGroup("forward").get(1).asString()+std::string(" ")+msg.findGroup("forward").get(2).asString();
2294 
2295  BOOL bSuccess=CreateProcess(nullptr, // command name
2296  (char*)strCmd.c_str(), // command line
2297  nullptr, // process security attributes
2298  nullptr, // primary thread security attributes
2299  TRUE, // handles are inherited
2300  CREATE_NEW_CONSOLE, // creation flags
2301  nullptr, // use parent's environment
2302  nullptr, // use parent's current directory
2303  &stdio_startup_info, // STARTUPINFO pointer
2304  &stdio_process_info); // receives PROCESS_INFORMATION
2305 
2306  std::string out;
2307 
2308  if (bSuccess)
2309  {
2310  mStdioVector.Add(new YarpRunProcInfo(strAlias,
2311  mPortName,
2312  stdio_process_info.dwProcessId,
2313  stdio_process_info.hProcess,
2314  false));
2315 
2316  out=std::string("STARTED: server=")+mPortName
2317  +std::string(" alias=")+strAlias
2318  +std::string(" cmd=stdio pid=")+int2String(stdio_process_info.dwProcessId)
2319  +std::string("\n");
2320  }
2321  else
2322  {
2323  stdio_process_info.dwProcessId=YARPRUN_ERROR;
2324 
2325  out=std::string("ABORTED: server=")+mPortName
2326  +std::string(" alias=")+strAlias
2327  +std::string(" cmd=stdio\n")
2328  +std::string("Can't open stdio window because ")+lastError2String()
2329  +std::string("\n");
2330  }
2331 
2332  result.clear();
2333  result.addInt32(stdio_process_info.dwProcessId);
2334  result.addString(out.c_str());
2335  fprintf(stderr, "%s", out.c_str());
2336  fflush(stderr);
2337 
2338  return stdio_process_info.dwProcessId;
2339 }
2340 
2342 #else // LINUX
2343 /*
2345 int CountArgs(char *str)
2346 {
2347  int nargs=0;
2348 
2349  for (bool bSpace=true; *str; ++str)
2350  {
2351  if (bSpace)
2352  {
2353  if (*str!=' ')
2354  {
2355  ++nargs;
2356  bSpace=false;
2357  }
2358  }
2359  else
2360  {
2361  if (*str==' ')
2362  {
2363  bSpace=true;
2364  }
2365  }
2366  }
2367 
2368  return nargs;
2369 }
2370 
2371 void ParseCmd(char* cmd_str, char** arg_str)
2372 {
2373  int nargs=0;
2374 
2375  for (bool bSpace=true; *cmd_str; ++cmd_str)
2376  {
2377  if (*cmd_str!=' ')
2378  {
2379  if (bSpace) arg_str[nargs++]=cmd_str;
2380  bSpace=false;
2381  }
2382  else
2383  {
2384  *cmd_str=0;
2385  bSpace=true;
2386  }
2387  }
2388 }
2389 */
2393 void splitLine(char *pLine, char **pArgs)
2394 {
2395  char *pTmp = strchr(pLine, ' ');
2396 
2397  if (pTmp) {
2398  *pTmp = '\0';
2399  pTmp++;
2400  while ((*pTmp) && (*pTmp == ' ')) {
2401  pTmp++;
2402  }
2403  if (*pTmp == '\0') {
2404  pTmp = nullptr;
2405  }
2406  }
2407  *pArgs = pTmp;
2408 }
2409 
2410 
2411 
2415 void parseArguments(char *io_pLine, int *o_pArgc, char **o_pArgv)
2416 {
2417  char *pNext = io_pLine;
2418  size_t i;
2419  int j;
2420  int quoted = 0;
2421  size_t len = strlen(io_pLine);
2422 
2423  // Protect spaces inside quotes, but lose the quotes
2424  for(i = 0; i < len; i++) {
2425  if ((!quoted) && ('"' == io_pLine[i])) {
2426  quoted = 1;
2427  io_pLine[i] = ' ';
2428  } else if ((quoted) && ('"' == io_pLine[i])) {
2429  quoted = 0;
2430  io_pLine[i] = ' ';
2431  } else if ((quoted) && (' ' == io_pLine[i])) {
2432  io_pLine[i] = '\1';
2433  }
2434  }
2435 
2436  // init
2437  memset(o_pArgv, 0x00, sizeof(char*) * C_MAXARGS);
2438  *o_pArgc = 1;
2439  o_pArgv[0] = io_pLine;
2440 
2441  while ((nullptr != pNext) && (*o_pArgc < C_MAXARGS)) {
2442  splitLine(pNext, &(o_pArgv[*o_pArgc]));
2443  pNext = o_pArgv[*o_pArgc];
2444 
2445  if (nullptr != o_pArgv[*o_pArgc]) {
2446  *o_pArgc += 1;
2447  }
2448  }
2449 
2450  for(j = 0; j < *o_pArgc; j++) {
2451  len = strlen(o_pArgv[j]);
2452  for(i = 0; i < len; i++) {
2453  if ('\1' == o_pArgv[j][i]) {
2454  o_pArgv[j][i] = ' ';
2455  }
2456  }
2457  }
2458 }
2459 
2460 void yarp::run::Run::CleanZombie(int pid)
2461 {
2462  bool bFound=mProcessVector && mProcessVector->CleanZombie(pid);
2463 
2464  if (!bFound) if (mStdioVector) mStdioVector->CleanZombie(pid);
2465 }
2466 
2468 
2469 int yarp::run::Run::executeCmdAndStdio(yarp::os::Bottle& msg, yarp::os::Bottle& result)
2470 {
2471  std::string strAlias=msg.find("as").asString();
2472  std::string strCmd=msg.find("cmd").asString();
2473  std::string strStdio=msg.find("stdio").asString();
2474  std::string strStdioUUID=msg.find("stdiouuid").asString();
2475 
2476  int pipe_stdin_to_cmd[2];
2477  int ret_stdin_to_cmd=yarp::run::impl::pipe(pipe_stdin_to_cmd);
2478 
2479  int pipe_cmd_to_stdout[2];
2480  int ret_cmd_to_stdout=yarp::run::impl::pipe(pipe_cmd_to_stdout);
2481 
2482  int pipe_child_to_parent[2];
2483  int ret_child_to_parent=yarp::run::impl::pipe(pipe_child_to_parent);
2484 
2485  if (ret_child_to_parent!=0 || ret_cmd_to_stdout!=0 || ret_stdin_to_cmd!=0)
2486  {
2487  int error=errno;
2488 
2489  std::string out=std::string("ABORTED: server=")+mPortName
2490  +std::string(" alias=")+strAlias
2491  +std::string(" cmd=stdout\n")
2492  +std::string("Can't create pipes ")+strerror(error)
2493  +std::string("\n");
2494 
2495  result.addInt32(YARPRUN_ERROR);
2496  result.addString(out.c_str());
2497  fprintf(stderr, "%s", out.c_str());
2498 
2499  return YARPRUN_ERROR;
2500  }
2501 
2502  int pid_stdout=yarp::run::impl::fork();
2503 
2504  if (IS_INVALID(pid_stdout))
2505  {
2506  int error=errno;
2507 
2508  CLOSE(pipe_stdin_to_cmd[WRITE_TO_PIPE]);
2509  CLOSE(pipe_stdin_to_cmd[READ_FROM_PIPE]);
2510  CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
2511  CLOSE(pipe_cmd_to_stdout[READ_FROM_PIPE]);
2512  CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
2513  CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
2514 
2515  std::string out=std::string("ABORTED: server=")+mPortName
2516  +std::string(" alias=")+strAlias
2517  +std::string(" cmd=stdout\n")
2518  +std::string("Can't fork stdout process because ")+strerror(error)
2519  +std::string("\n");
2520 
2521  result.addInt32(YARPRUN_ERROR);
2522  result.addString(out.c_str());
2523  fprintf(stderr, "%s", out.c_str());
2524 
2525  return YARPRUN_ERROR;
2526  }
2527 
2528  if (IS_NEW_PROCESS(pid_stdout)) // STDOUT IMPLEMENTED HERE
2529  {
2530  REDIRECT_TO(STDIN_FILENO, pipe_cmd_to_stdout[READ_FROM_PIPE]);
2531 
2532  CLOSE(pipe_stdin_to_cmd[WRITE_TO_PIPE]);
2533  CLOSE(pipe_stdin_to_cmd[READ_FROM_PIPE]);
2534  CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
2535  CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
2536 
2537  //Why removing vectors and stop threads?
2538  //exec* never returns and memory is claimed by the system
2539  //furthermore after fork() only the thread which called fork() is forked!
2540  // cleanBeforeExec();
2541 
2542  //yarp::os::impl::signal(SIGPIPE, SIG_DFL);
2543 
2544  int ret = yarp::run::impl::execlp("yarprun", "yarprun", "--write", strStdioUUID.c_str(), static_cast<char*>(nullptr));
2545 
2546  CLOSE(pipe_cmd_to_stdout[READ_FROM_PIPE]);
2547 
2548  if (ret==YARPRUN_ERROR)
2549  {
2550  int error=errno;
2551 
2552  std::string out=std::string("ABORTED: server=")+mPortName
2553  +std::string(" alias=")+strAlias
2554  +std::string(" cmd=stdout\n")
2555  +std::string("Can't execute stdout because ")+strerror(error)
2556  +std::string("\n");
2557 
2558  FILE* out_to_parent=fdopen(pipe_child_to_parent[WRITE_TO_PIPE], "w");
2559  fprintf(out_to_parent, "%s", out.c_str());
2560  fflush(out_to_parent);
2561  fclose(out_to_parent);
2562 
2563  fprintf(stderr, "%s", out.c_str());
2564  }
2565 
2566  CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
2567 
2568  std::exit(ret);
2569  }
2570 
2571  if (IS_PARENT_OF(pid_stdout))
2572  {
2573  CLOSE(pipe_cmd_to_stdout[READ_FROM_PIPE]);
2574 
2575  fprintf(stderr, "STARTED: server=%s alias=%s cmd=stdout pid=%d\n", mPortName.c_str(), strAlias.c_str(), pid_stdout);
2576 
2577  int pid_stdin=yarp::run::impl::fork();
2578 
2579  if (IS_INVALID(pid_stdin))
2580  {
2581  int error=errno;
2582 
2583  CLOSE(pipe_stdin_to_cmd[WRITE_TO_PIPE]);
2584  CLOSE(pipe_stdin_to_cmd[READ_FROM_PIPE]);
2585  CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
2586  CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
2587  CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
2588 
2589  std::string out=std::string("ABORTED: server=")+mPortName
2590  +std::string(" alias=")+strAlias
2591  +std::string(" cmd=stdin\n")
2592  +std::string("Can't fork stdin process because ")+strerror(error)
2593  +std::string("\n");
2594 
2595  result.addInt32(YARPRUN_ERROR);
2596  result.addString(out.c_str());
2597  fprintf(stderr, "%s", out.c_str());
2598 
2599  SIGNAL(pid_stdout, SIGTERM);
2600  fprintf(stderr, "TERMINATING stdout (%d)\n", pid_stdout);
2601 
2602  return YARPRUN_ERROR;
2603  }
2604 
2605  if (IS_NEW_PROCESS(pid_stdin)) // STDIN IMPLEMENTED HERE
2606  {
2607  REDIRECT_TO(STDOUT_FILENO, pipe_stdin_to_cmd[WRITE_TO_PIPE]);
2608  REDIRECT_TO(STDERR_FILENO, pipe_stdin_to_cmd[WRITE_TO_PIPE]);
2609 
2610  CLOSE(pipe_stdin_to_cmd[READ_FROM_PIPE]);
2611  CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
2612  CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
2613 
2614  //Why removing vectors and stop threads?
2615  //exec* never returns and memory is claimed by the system
2616  //furthermore after fork() only the thread which called fork() is forked!
2617  // cleanBeforeExec();
2618 
2619  //yarp::os::impl::signal(SIGPIPE, SIG_DFL);
2620 
2621  int ret = yarp::run::impl::execlp("yarprun", "yarprun", "--read", strStdioUUID.c_str(), static_cast<char*>(nullptr));
2622 
2623  CLOSE(pipe_stdin_to_cmd[WRITE_TO_PIPE]);
2624 
2625  if (ret==YARPRUN_ERROR)
2626  {
2627  int error=errno;
2628 
2629  std::string out=std::string("ABORTED: server=")+mPortName
2630  +std::string(" alias=")+strAlias
2631  +std::string(" cmd=stdin\n")
2632  +std::string("Can't execute stdin because ")+strerror(error)
2633  +std::string("\n");
2634 
2635 
2636  FILE* out_to_parent=fdopen(pipe_child_to_parent[WRITE_TO_PIPE], "w");
2637  fprintf(out_to_parent, "%s", out.c_str());
2638  fflush(out_to_parent);
2639  fclose(out_to_parent);
2640  fprintf(stderr, "%s", out.c_str());
2641  }
2642 
2643  CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
2644 
2645  std::exit(ret);
2646  }
2647 
2648  if (IS_PARENT_OF(pid_stdin))
2649  {
2650  // connect yarp read and write
2651  CLOSE(pipe_stdin_to_cmd[WRITE_TO_PIPE]);
2652 
2653  fprintf(stderr, "STARTED: server=%s alias=%s cmd=stdin pid=%d\n", mPortName.c_str(), strAlias.c_str(), pid_stdin);
2654 
2655  int pid_cmd=yarp::run::impl::fork();
2656 
2657  if (IS_INVALID(pid_cmd))
2658  {
2659  int error=errno;
2660 
2661  CLOSE(pipe_stdin_to_cmd[READ_FROM_PIPE]);
2662  CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
2663  CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
2664 
2665  std::string out=std::string("ABORTED: server=")+mPortName
2666  +std::string(" alias=")+strAlias
2667  +std::string(" cmd=")+strCmd
2668  +std::string("\nCan't fork command process because ")+strerror(error)
2669  +std::string("\n");
2670 
2671  result.addInt32(YARPRUN_ERROR);
2672  result.addString(out.c_str());
2673  fprintf(stderr, "%s", out.c_str());
2674 
2675  FILE* to_yarp_stdout=fdopen(pipe_cmd_to_stdout[WRITE_TO_PIPE], "w");
2676  fprintf(to_yarp_stdout, "%s", out.c_str());
2677  fflush(to_yarp_stdout);
2678  fclose(to_yarp_stdout);
2679 
2680  SIGNAL(pid_stdout, SIGTERM);
2681  fprintf(stderr, "TERMINATING stdout (%d)\n", pid_stdout);
2682  SIGNAL(pid_stdin, SIGTERM);
2683  fprintf(stderr, "TERMINATING stdin (%d)\n", pid_stdin);
2684 
2685  CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
2686 
2687  return YARPRUN_ERROR;
2688  }
2689 
2690  if (IS_NEW_PROCESS(pid_cmd)) // RUN COMMAND HERE
2691  {
2692  CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
2693 
2694  char *cmd_str=new char[strCmd.length()+1];
2695  strcpy(cmd_str, strCmd.c_str());
2696  /*
2697  int nargs=CountArgs(cmd_str);
2698  char **arg_str=new char*[nargs+1];
2699  ParseCmd(cmd_str, arg_str);
2700  arg_str[nargs]=0;
2701  */
2702  int nargs = 0;
2703  char **arg_str = new char*[C_MAXARGS + 1];
2704  parseArguments(cmd_str, &nargs, arg_str);
2705  arg_str[nargs]=nullptr;
2706 
2707  setvbuf(stdout, nullptr, _IONBF, 0);
2708 
2709  REDIRECT_TO(STDIN_FILENO, pipe_stdin_to_cmd[READ_FROM_PIPE]);
2710  REDIRECT_TO(STDOUT_FILENO, pipe_cmd_to_stdout[WRITE_TO_PIPE]);
2711  REDIRECT_TO(STDERR_FILENO, pipe_cmd_to_stdout[WRITE_TO_PIPE]);
2712 
2713  if (msg.check("env"))
2714  {
2715  yarp::os::impl::SplitString ss(msg.find("env").asString().c_str(), ';');
2716  for(int i=0; i<ss.size(); i++) {
2717  char* szenv = new char[strlen(ss.get(i))+1];
2718  strcpy(szenv, ss.get(i));
2719  yarp::os::impl::putenv(szenv); // putenv doesn't make copy of the string
2720  }
2721  //delete [] szenv;
2722  }
2723 
2724  if (msg.check("workdir"))
2725  {
2726  int ret = yarp::os::impl::chdir(msg.find("workdir").asString().c_str());
2727 
2728  if (ret!=0)
2729  {
2730  int error=errno;
2731 
2732  std::string out=std::string("ABORTED: server=")+mPortName
2733  +std::string(" alias=")+strAlias
2734  +std::string(" cmd=")+strCmd
2735  +std::string("\nCan't execute command, cannot set working directory ")+strerror(error)
2736  +std::string("\n");
2737 
2738  FILE* out_to_parent=fdopen(pipe_child_to_parent[WRITE_TO_PIPE], "w");
2739  fprintf(out_to_parent, "%s", out.c_str());
2740  fflush(out_to_parent);
2741  fclose(out_to_parent);
2742  fprintf(stderr, "%s", out.c_str());
2743 
2744  std::exit(ret);
2745  }
2746  }
2747 
2748  int ret=YARPRUN_ERROR;
2749 
2750  char currWorkDirBuff[1024];
2751  char *currWorkDir=yarp::os::impl::getcwd(currWorkDirBuff, 1024);
2752 
2753  if (currWorkDir)
2754  {
2755  char **cwd_arg_str=new char*[nargs+1];
2756  for (int i=1; i<nargs; ++i) cwd_arg_str[i]=arg_str[i];
2757  cwd_arg_str[nargs]=nullptr;
2758  cwd_arg_str[0]=new char[strlen(currWorkDir)+strlen(arg_str[0])+16];
2759 
2760  strcpy(cwd_arg_str[0], currWorkDir);
2761  strcat(cwd_arg_str[0], "/");
2762  strcat(cwd_arg_str[0], arg_str[0]);
2763 
2764  //Why removing vectors and stop threads?
2765  //exec* never returns and memory is claimed by the system
2766  //furthermore after fork() only the thread which called fork() is forked!
2767  // cleanBeforeExec();
2768 
2769  ret = yarp::run::impl::execvp(cwd_arg_str[0], cwd_arg_str);
2770 
2771  delete [] cwd_arg_str[0];
2772  delete [] cwd_arg_str;
2773  }
2774 
2775  if (ret==YARPRUN_ERROR)
2776  {
2777  //Why removing vectors and stop threads?
2778  //exec* never returns and memory is claimed by the system
2779  //furthermore after fork() only the thread which called fork() is forked!
2780  // cleanBeforeExec();
2781 
2782  ret = yarp::run::impl::execvp(arg_str[0], arg_str);
2783  }
2784 
2785  fflush(stdout);
2786 
2787  CLOSE(pipe_stdin_to_cmd[READ_FROM_PIPE]);
2788  CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
2789 
2790  if (ret==YARPRUN_ERROR)
2791  {
2792  int error=errno;
2793 
2794  std::string out=std::string("ABORTED: server=")+mPortName
2795  +std::string(" alias=")+strAlias
2796  +std::string(" cmd=")+strCmd
2797  +std::string("\nCan't execute command because ")+strerror(error)
2798  +std::string("\n");
2799 
2800  FILE* out_to_parent=fdopen(pipe_child_to_parent[WRITE_TO_PIPE], "w");
2801  fprintf(out_to_parent, "%s", out.c_str());
2802  fflush(out_to_parent);
2803  fclose(out_to_parent);
2804  fprintf(stderr, "%s", out.c_str());
2805  }
2806 
2807  delete [] cmd_str;
2808  delete [] arg_str;
2809 
2810  CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
2811 
2812  std::exit(ret);
2813  }
2814 
2815 
2816  if (IS_PARENT_OF(pid_cmd))
2817  {
2818  CLOSE(pipe_stdin_to_cmd[READ_FROM_PIPE]);
2819  CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
2820  CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
2821 
2823  strAlias,
2824  mPortName,
2825  strStdio,
2826  pid_cmd,
2827  strStdioUUID,
2828  mStdioVector,
2829  pid_stdin,
2830  pid_stdout,
2831  pipe_stdin_to_cmd[READ_FROM_PIPE],
2832  pipe_stdin_to_cmd[WRITE_TO_PIPE],
2833  pipe_cmd_to_stdout[READ_FROM_PIPE],
2834  pipe_cmd_to_stdout[WRITE_TO_PIPE],
2835  nullptr,
2836  false
2837  );
2838 
2839  pInf->setCmd(strCmd);
2840 
2841  if (msg.check("env"))
2842  {
2843  pInf->setEnv(msg.find("env").asString());
2844  }
2845 
2846  mProcessVector->Add(pInf);
2847 
2849 
2850  FILE* in_from_child=fdopen(pipe_child_to_parent[READ_FROM_PIPE], "r");
2851  int flags=fcntl(pipe_child_to_parent[READ_FROM_PIPE], F_GETFL, 0);
2852  fcntl(pipe_child_to_parent[READ_FROM_PIPE], F_SETFL, flags|O_NONBLOCK);
2853 
2854  std::string out;
2855 
2856  if (in_from_child)
2857  {
2858  char buff[1024];
2859 
2860  while(true)
2861  {
2862  if (!fgets(buff, 1024, in_from_child) || ferror(in_from_child) || feof(in_from_child)) break;
2863 
2864  out+=std::string(buff);
2865  }
2866 
2867  fclose(in_from_child);
2868  }
2869 
2870  if (out.length()>0)
2871  {
2872  pid_cmd=YARPRUN_ERROR;
2873  }
2874  else
2875  {
2876  out=std::string("STARTED: server=")+mPortName
2877  +std::string(" alias=")+strAlias
2878  +std::string(" cmd=")+strCmd
2879  +std::string(" pid=")+int2String(pid_cmd)
2880  +std::string("\n");
2881  }
2882 
2883  result.addInt32(pid_cmd);
2884  result.addString(out.c_str());
2885  result.addString(strStdioUUID.c_str());
2886 
2887  fprintf(stderr, "%s", out.c_str());
2888 
2889  CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
2890 
2891  return pid_cmd;
2892  }
2893  }
2894  }
2895 
2896  result.addInt32(YARPRUN_ERROR);
2897  result.addString("I should never reach this point!!!\n");
2898 
2899  return YARPRUN_ERROR;
2900 }
2901 
2902 int yarp::run::Run::executeCmdStdout(yarp::os::Bottle& msg, yarp::os::Bottle& result, std::string& loggerName)
2903 {
2904  std::string strAlias=msg.find("as").asString();
2905  std::string strCmd=msg.find("cmd").asString();
2906 
2907  std::string portName="/log";
2908  portName+=mPortName+"/";
2909 
2910  std::string command=strCmd;
2911  size_t space=command.find(' ');
2912  if (space != std::string::npos) {
2913  command=command.substr(0, space);
2914  }
2915  portName+=command;
2916 
2917 
2918 
2919  int pipe_cmd_to_stdout[2];
2920  int ret_cmd_to_stdout=yarp::run::impl::pipe(pipe_cmd_to_stdout);
2921 
2922  int pipe_child_to_parent[2];
2923  int ret_child_to_parent=yarp::run::impl::pipe(pipe_child_to_parent);
2924 
2925  if (ret_child_to_parent!=0 || ret_cmd_to_stdout!=0)
2926  {
2927  int error=errno;
2928 
2929  std::string out=std::string("ABORTED: server=")+mPortName
2930  +std::string(" alias=")+strAlias
2931  +std::string(" cmd=stdout\n")
2932  +std::string("Can't create pipes ")+strerror(error)
2933  +std::string("\n");
2934 
2935  result.addInt32(YARPRUN_ERROR);
2936  result.addString(out.c_str());
2937  fprintf(stderr, "%s", out.c_str());
2938 
2939  return YARPRUN_ERROR;
2940  }
2941 
2942  int pid_stdout=yarp::run::impl::fork();
2943 
2944  if (IS_INVALID(pid_stdout))
2945  {
2946  int error=errno;
2947 
2948  CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
2949  CLOSE(pipe_cmd_to_stdout[READ_FROM_PIPE]);
2950  CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
2951  CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
2952 
2953  std::string out=std::string("ABORTED: server=")+mPortName
2954  +std::string(" alias=")+strAlias
2955  +std::string(" cmd=stdout\n")
2956  +std::string("Can't fork stdout process because ")+strerror(error)
2957  +std::string("\n");
2958 
2959  result.addInt32(YARPRUN_ERROR);
2960  result.addString(out.c_str());
2961  fprintf(stderr, "%s", out.c_str());
2962 
2963  return YARPRUN_ERROR;
2964  }
2965 
2966  if (IS_NEW_PROCESS(pid_stdout)) // STDOUT IMPLEMENTED HERE
2967  {
2968  REDIRECT_TO(STDIN_FILENO, pipe_cmd_to_stdout[READ_FROM_PIPE]);
2969 
2970  CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
2971  CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
2972 
2973  //Why removing vectors and stop threads?
2974  //exec* never returns and memory is claimed by the system
2975  //furthermore after fork() only the thread which called fork() is forked!
2976  // cleanBeforeExec();
2977 
2978  //yarp::os::impl::signal(SIGPIPE, SIG_DFL);
2979 
2980  int ret = yarp::run::impl::execlp("yarprun", "yarprun", "--write", portName.c_str(), "--log", loggerName.c_str(), static_cast<char*>(nullptr));
2981 
2982  CLOSE(pipe_cmd_to_stdout[READ_FROM_PIPE]);
2983 
2984  if (ret==YARPRUN_ERROR)
2985  {
2986  int error=errno;
2987 
2988  std::string out=std::string("ABORTED: server=")+mPortName
2989  +std::string(" alias=")+strAlias
2990  +std::string(" cmd=stdout\n")
2991  +std::string("Can't execute stdout because ")+strerror(error)
2992  +std::string("\n");
2993 
2994  FILE* out_to_parent=fdopen(pipe_child_to_parent[WRITE_TO_PIPE], "w");
2995  fprintf(out_to_parent, "%s", out.c_str());
2996  fflush(out_to_parent);
2997  fclose(out_to_parent);
2998 
2999  fprintf(stderr, "%s", out.c_str());
3000  }
3001 
3002  CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
3003 
3004  std::exit(ret);
3005  }
3006 
3007  if (IS_PARENT_OF(pid_stdout))
3008  {
3009  CLOSE(pipe_cmd_to_stdout[READ_FROM_PIPE]);
3010 
3011  fprintf(stderr, "STARTED: server=%s alias=%s cmd=stdout pid=%d\n", mPortName.c_str(), strAlias.c_str(), pid_stdout);
3012 
3014 
3015  //if (IS_PARENT_OF(pid_stdin))
3016  {
3017  int pid_cmd=yarp::run::impl::fork();
3018 
3019  if (IS_INVALID(pid_cmd))
3020  {
3021  int error=errno;
3022 
3023  CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
3024  CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
3025 
3026  std::string out=std::string("ABORTED: server=")+mPortName
3027  +std::string(" alias=")+strAlias
3028  +std::string(" cmd=")+strCmd
3029  +std::string("\nCan't fork command process because ")+strerror(error)
3030  +std::string("\n");
3031 
3032  result.addInt32(YARPRUN_ERROR);
3033  result.addString(out.c_str());
3034  fprintf(stderr, "%s", out.c_str());
3035 
3036  FILE* to_yarp_stdout=fdopen(pipe_cmd_to_stdout[WRITE_TO_PIPE], "w");
3037  fprintf(to_yarp_stdout, "%s", out.c_str());
3038  fflush(to_yarp_stdout);
3039  fclose(to_yarp_stdout);
3040 
3041  SIGNAL(pid_stdout, SIGTERM);
3042  fprintf(stderr, "TERMINATING stdout (%d)\n", pid_stdout);
3043  CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
3044 
3045  return YARPRUN_ERROR;
3046  }
3047 
3048  if (IS_NEW_PROCESS(pid_cmd)) // RUN COMMAND HERE
3049  {
3050  CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
3051 
3052  char *cmd_str=new char[strCmd.length()+1];
3053  strcpy(cmd_str, strCmd.c_str());
3054  /*
3055  int nargs=CountArgs(cmd_str);
3056  char **arg_str=new char*[nargs+1];
3057  ParseCmd(cmd_str, arg_str);
3058  arg_str[nargs]=0;
3059  */
3060  int nargs = 0;
3061  char **arg_str = new char*[C_MAXARGS + 1];
3062  parseArguments(cmd_str, &nargs, arg_str);
3063  arg_str[nargs]=nullptr;
3064 
3065  setvbuf(stdout, nullptr, _IONBF, 0);
3066 
3067  REDIRECT_TO(STDOUT_FILENO, pipe_cmd_to_stdout[WRITE_TO_PIPE]);
3068  REDIRECT_TO(STDERR_FILENO, pipe_cmd_to_stdout[WRITE_TO_PIPE]);
3069 
3070  if (msg.check("env"))
3071  {
3072  yarp::os::impl::SplitString ss(msg.find("env").asString().c_str(), ';');
3073  for(int i=0; i<ss.size(); i++) {
3074  char* szenv = new char[strlen(ss.get(i))+1];
3075  strcpy(szenv, ss.get(i));
3076  yarp::os::impl::putenv(szenv); // putenv doesn't make copy of the string
3077  }
3078  //delete [] szenv;
3079  }
3080 
3081  if (msg.check("workdir"))
3082  {
3083  int ret = yarp::os::impl::chdir(msg.find("workdir").asString().c_str());
3084 
3085  if (ret!=0)
3086  {
3087  int error=errno;
3088 
3089  std::string out=std::string("ABORTED: server=")+mPortName
3090  +std::string(" alias=")+strAlias
3091  +std::string(" cmd=")+strCmd
3092  +std::string("\nCan't execute command, cannot set working directory ")+strerror(error)
3093  +std::string("\n");
3094 
3095  FILE* out_to_parent=fdopen(pipe_child_to_parent[WRITE_TO_PIPE], "w");
3096  fprintf(out_to_parent, "%s", out.c_str());
3097  fflush(out_to_parent);
3098  fclose(out_to_parent);
3099  fprintf(stderr, "%s", out.c_str());
3100 
3101  std::exit(ret);
3102  }
3103  }
3104 
3105  int ret=YARPRUN_ERROR;
3106 
3107  char currWorkDirBuff[1024];
3108  char *currWorkDir=getcwd(currWorkDirBuff, 1024);
3109 
3110  if (currWorkDir)
3111  {
3112  char **cwd_arg_str=new char*[nargs+1];
3113  for (int i=1; i<nargs; ++i) cwd_arg_str[i]=arg_str[i];
3114  cwd_arg_str[nargs]=nullptr;
3115  cwd_arg_str[0]=new char[strlen(currWorkDir)+strlen(arg_str[0])+16];
3116 
3117  strcpy(cwd_arg_str[0], currWorkDir);
3118  strcat(cwd_arg_str[0], "/");
3119  strcat(cwd_arg_str[0], arg_str[0]);
3120 
3121  //Why removing vectors and stop threads?
3122  //exec* never returns and memory is claimed by the system
3123  //furthermore after fork() only the thread which called fork() is forked!
3124  // cleanBeforeExec();
3125 
3126  ret = yarp::run::impl::execvp(cwd_arg_str[0], cwd_arg_str);
3127 
3128  delete [] cwd_arg_str[0];
3129  delete [] cwd_arg_str;
3130  }
3131 
3132  if (ret==YARPRUN_ERROR)
3133  {
3134  //Why removing vectors and stop threads?
3135  //exec* never returns and memory is claimed by the system
3136  //furthermore after fork() only the thread which called fork() is forked!
3137  // cleanBeforeExec();
3138 
3139  ret = yarp::run::impl::execvp(arg_str[0], arg_str);
3140  }
3141 
3142  fflush(stdout);
3143 
3144  CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
3145 
3146  if (ret==YARPRUN_ERROR)
3147  {
3148  int error=errno;
3149 
3150  std::string out=std::string("ABORTED: server=")+mPortName
3151  +std::string(" alias=")+strAlias
3152  +std::string(" cmd=")+strCmd
3153  +std::string("\nCan't execute command because ")+strerror(error)
3154  +std::string("\n");
3155 
3156  FILE* out_to_parent=fdopen(pipe_child_to_parent[WRITE_TO_PIPE], "w");
3157  fprintf(out_to_parent, "%s", out.c_str());
3158  fflush(out_to_parent);
3159  fclose(out_to_parent);
3160  fprintf(stderr, "%s", out.c_str());
3161  }
3162 
3163  delete [] cmd_str;
3164  delete [] arg_str;
3165 
3166  CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
3167 
3168  std::exit(ret);
3169  }
3170 
3171 
3172  if (IS_PARENT_OF(pid_cmd))
3173  {
3174  CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
3175  CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
3176 
3178  strAlias,
3179  mPortName,
3180  portName,
3181  pid_cmd,
3182  pid_stdout,
3183  pipe_cmd_to_stdout[READ_FROM_PIPE],
3184  pipe_cmd_to_stdout[WRITE_TO_PIPE],
3185  nullptr,
3186  false
3187  );
3188 
3189  pInf->setCmd(strCmd);
3190 
3191  if (msg.check("env"))
3192  {
3193  pInf->setEnv(msg.find("env").asString());
3194  }
3195 
3196  mProcessVector->Add(pInf);
3197 
3199 
3200  FILE* in_from_child=fdopen(pipe_child_to_parent[READ_FROM_PIPE], "r");
3201  int flags=fcntl(pipe_child_to_parent[READ_FROM_PIPE], F_GETFL, 0);
3202  fcntl(pipe_child_to_parent[READ_FROM_PIPE], F_SETFL, flags|O_NONBLOCK);
3203 
3204  std::string out;
3205 
3206  if (in_from_child)
3207  {
3208  char buff[1024];
3209 
3210  while(true)
3211  {
3212  if (!fgets(buff, 1024, in_from_child) || ferror(in_from_child) || feof(in_from_child)) break;
3213 
3214  out+=std::string(buff);
3215  }
3216 
3217  fclose(in_from_child);
3218  }
3219 
3220  if (out.length()>0)
3221  {
3222  pid_cmd=YARPRUN_ERROR;
3223  }
3224  else
3225  {
3226  out=std::string("STARTED: server=")+mPortName
3227  +std::string(" alias=")+strAlias
3228  +std::string(" cmd=")+strCmd
3229  +std::string(" pid=")+int2String(pid_cmd)
3230  +std::string("\n");
3231  }
3232 
3233  result.addInt32(pid_cmd);
3234  result.addString(out.c_str());
3235 
3236  fprintf(stderr, "%s", out.c_str());
3237 
3238  CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
3239 
3240  return pid_cmd;
3241  }
3242  }
3243  }
3244 
3245  result.addInt32(YARPRUN_ERROR);
3246  result.addString("I should never reach this point!!!\n");
3247 
3248  return YARPRUN_ERROR;
3249 }
3250 
3251 int yarp::run::Run::userStdio(yarp::os::Bottle& msg, yarp::os::Bottle& result)
3252 {
3253  std::string strAlias=msg.find("as").asString();
3254  std::string strUUID=msg.find("stdiouuid").asString();
3255 
3256  std::string strCmd;
3257 
3258  if (msg.check("forward"))
3259  {
3260  strCmd=std::string("/bin/bash -l -c \"yarprun --readwrite ")+strUUID
3261  +std::string(" --forward ")+msg.findGroup("forward").get(1).asString()+std::string(" ")+msg.findGroup("forward").get(2).asString()+std::string("\"");
3262  }
3263  else
3264  {
3265  strCmd=std::string("/bin/bash -l -c \"yarprun --readwrite ")+strUUID+"\"";
3266  }
3267 
3268  int pipe_child_to_parent[2];
3269 
3270  if (yarp::run::impl::pipe(pipe_child_to_parent))
3271  {
3272  int error=errno;
3273 
3274  std::string out=std::string("ABORTED: server=")+mPortName
3275  +std::string(" alias=")+strAlias
3276  +std::string(" cmd=stdio\nCan't create pipe ")+strerror(error)
3277  +std::string("\n");
3278 
3279  result.clear();
3280  result.addInt32(YARPRUN_ERROR);
3281  result.addString(out.c_str());
3282  fprintf(stderr, "%s", out.c_str());
3283 
3284  return YARPRUN_ERROR;
3285  }
3286 
3287  int c=0;
3288  char *command[16];
3289  for (int i=0; i<16; ++i) {
3290  command[i] = nullptr;
3291  }
3292 
3293  cmdcpy(command[c++], "xterm");
3294  cmdcpy(command[c++], msg.check("hold")?"-hold":"+hold");
3295 
3296  if (msg.check("geometry"))
3297  {
3298  cmdcpy(command[c++], "-geometry");
3299  cmdcpy(command[c++], msg.find("geometry").asString().c_str());
3300  }
3301 
3302  cmdcpy(command[c++], "-title");
3303  cmdcpy(command[c++], strAlias.c_str());
3304 
3305  cmdcpy(command[c++], "-e");
3306  cmdcpy(command[c++], strCmd.c_str());
3307 
3308  int pid_cmd=yarp::run::impl::fork();
3309 
3310  if (IS_INVALID(pid_cmd))
3311  {
3312  int error=errno;
3313 
3314  std::string out=std::string("ABORTED: server=")+mPortName
3315  +std::string(" alias=")+strAlias
3316  +std::string(" cmd=stdio\nCan't fork stdout process because ")+strerror(error)
3317  +std::string("\n");
3318 
3319  result.clear();
3320  result.addInt32(YARPRUN_ERROR);
3321  result.addString(out.c_str());
3322  fprintf(stderr, "%s", out.c_str());
3323 
3324  CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
3325  CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
3326 
3327  cmdclean(command);
3328 
3329  return YARPRUN_ERROR;
3330  }
3331 
3332  if (IS_NEW_PROCESS(pid_cmd)) // RUN COMMAND HERE
3333  {
3334  //yarp::os::impl::signal(SIGPIPE, SIG_IGN);
3335 
3336  CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
3337 
3338  REDIRECT_TO(STDERR_FILENO, pipe_child_to_parent[WRITE_TO_PIPE]);
3339 
3340  //Why removing vectors and stop threads?
3341  //exec* never returns and memory is claimed by the system
3342  //furthermore after fork() only the thread which called fork() is forked!
3343  // cleanBeforeExec();
3344 
3345  //yarp::os::impl::signal(SIGHUP, rwSighupHandler);
3346 
3347  int ret = yarp::run::impl::execvp("xterm", command);
3348 
3349  cmdclean(command);
3350 
3351  if (ret==YARPRUN_ERROR)
3352  {
3353  int error=errno;
3354 
3355  std::string out=std::string("ABORTED: server=")+mPortName
3356  +std::string(" alias=")+strAlias
3357  +std::string(" cmd=xterm\nCan't execute command because ")+strerror(error)
3358  +std::string("\n");
3359 
3360  FILE* out_to_parent=fdopen(pipe_child_to_parent[WRITE_TO_PIPE], "w");
3361 
3362  fprintf(out_to_parent, "%s", out.c_str());
3363  fflush(out_to_parent);
3364  fclose(out_to_parent);
3365 
3366  fprintf(stderr, "%s", out.c_str());
3367  }
3368 
3369  CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
3370 
3371  std::exit(ret);
3372  }
3373 
3374  if (IS_PARENT_OF(pid_cmd))
3375  {
3376  CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
3377 
3378  mStdioVector->Add(new YarpRunProcInfo(strAlias, mPortName, pid_cmd, nullptr, msg.check("hold")));
3379 
3380  result.clear();
3381 
3382  cmdclean(command);
3383 
3385 
3386  FILE* in_from_child=fdopen(pipe_child_to_parent[READ_FROM_PIPE], "r");
3387  int flags=fcntl(pipe_child_to_parent[READ_FROM_PIPE], F_GETFL, 0);
3388  fcntl(pipe_child_to_parent[READ_FROM_PIPE], F_SETFL, flags|O_NONBLOCK);
3389  std::string out;
3390 
3391  if (in_from_child)
3392  {
3393  char buff[1024];
3394 
3395  while(true)
3396  {
3397  if (!fgets(buff, 1024, in_from_child) || ferror(in_from_child) || feof(in_from_child)) break;
3398 
3399  out+=std::string(buff);
3400  }
3401 
3402  fclose(in_from_child);
3403  }
3404 
3405  result.clear();
3406 
3407  //if (out.length()>0)
3408  if (out.substr(0, 14)=="xterm Xt error" || out.substr(0, 7)=="ABORTED")
3409  {
3410  pid_cmd=YARPRUN_ERROR;
3411  }
3412  else
3413  {
3414  out=std::string("STARTED: server=")+mPortName
3415  +std::string(" alias=")+strAlias
3416  +std::string(" cmd=xterm pid=")+int2String(pid_cmd)
3417  +std::string("\n");
3418 
3419  }
3420 
3421  fprintf(stderr, "%s", out.c_str());
3422 
3423  result.addInt32(pid_cmd);
3424  result.addString(out.c_str());
3425 
3426  CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
3427 
3428  return pid_cmd;
3429  }
3430 
3431  result.clear();
3432  result.addInt32(YARPRUN_ERROR);
3433 
3434  return YARPRUN_ERROR;
3435 }
3436 
3437 int yarp::run::Run::executeCmd(yarp::os::Bottle& msg, yarp::os::Bottle& result)
3438 {
3439  std::string strAlias(msg.find("as").asString());
3440  std::string strCmd(msg.find("cmd").toString());
3441 
3442  int pipe_child_to_parent[2];
3443  int ret_pipe_child_to_parent=yarp::run::impl::pipe(pipe_child_to_parent);
3444 
3445  if (ret_pipe_child_to_parent!=0)
3446  {
3447  int error=errno;
3448 
3449  std::string out=std::string("ABORTED: server=")+mPortName
3450  +std::string(" alias=")+strAlias
3451  +std::string(" cmd=stdio\nCan't create pipe ")+strerror(error)
3452  +std::string("\n");
3453 
3454 
3455  result.addInt32(YARPRUN_ERROR);
3456  result.addString(out.c_str());
3457  fprintf(stderr, "%s", out.c_str());
3458 
3459  return YARPRUN_ERROR;
3460  }
3461 
3462  int pid_cmd=yarp::run::impl::fork();
3463 
3464  if (IS_INVALID(pid_cmd))
3465  {
3466  int error=errno;
3467 
3468  std::string out=std::string("ABORTED: server=")+mPortName
3469  +std::string(" alias=")+strAlias
3470  +std::string(" cmd=")+strCmd
3471  +std::string("\nCan't fork command process because ")+strerror(error)
3472  +std::string("\n");
3473 
3474  result.addInt32(YARPRUN_ERROR);
3475  result.addString(out.c_str());
3476  fprintf(stderr, "%s", out.c_str());
3477 
3478  return YARPRUN_ERROR;
3479  }
3480 
3481  if (IS_NEW_PROCESS(pid_cmd)) // RUN COMMAND HERE
3482  {
3483  int saved_stderr = yarp::run::impl::dup(STDERR_FILENO);
3484  int null_file=open("/dev/null", O_WRONLY);
3485  if (null_file >= 0)
3486  {
3487  REDIRECT_TO(STDOUT_FILENO, null_file);
3488  REDIRECT_TO(STDERR_FILENO, null_file);
3489  close(null_file);
3490  }
3491  char *cmd_str=new char[strCmd.length()+1];
3492  strcpy(cmd_str, strCmd.c_str());
3493  /*
3494  int nargs=CountArgs(cmd_str);
3495  char **arg_str=new char*[nargs+1];
3496  ParseCmd(cmd_str, arg_str);
3497  arg_str[nargs]=0;
3498  */
3499  int nargs = 0;
3500  char **arg_str = new char*[C_MAXARGS + 1];
3501  parseArguments(cmd_str, &nargs, arg_str);
3502  arg_str[nargs]=nullptr;
3503 
3504  if (msg.check("env"))
3505  {
3506  yarp::os::impl::SplitString ss(msg.find("env").asString().c_str(), ';');
3507  for(int i=0; i<ss.size(); i++) {
3508  char* szenv = new char[strlen(ss.get(i))+1];
3509  strcpy(szenv, ss.get(i));
3510  yarp::os::impl::putenv(szenv); // putenv doesn't make copy of the string
3511  }
3512  }
3513 
3514  if (msg.check("workdir"))
3515  {
3516  int ret = yarp::os::impl::chdir(msg.find("workdir").asString().c_str());
3517 
3518  if (ret!=0)
3519  {
3520  int error=errno;
3521 
3522  std::string out=std::string("ABORTED: server=")+mPortName
3523  +std::string(" alias=")+strAlias
3524  +std::string(" cmd=")+strCmd
3525  +std::string("\nCan't execute command, cannot set working directory ")+strerror(error)
3526  +std::string("\n");
3527 
3528  FILE* out_to_parent=fdopen(pipe_child_to_parent[WRITE_TO_PIPE], "w");
3529  fprintf(out_to_parent, "%s", out.c_str());
3530  fflush(out_to_parent);
3531  fclose(out_to_parent);
3532 
3533  REDIRECT_TO(STDERR_FILENO, saved_stderr);
3534  fprintf(stderr, "%s", out.c_str());
3535  }
3536  }
3537 
3538  int ret=YARPRUN_ERROR;
3539 
3540  char currWorkDirBuff[1024];
3541  char *currWorkDir=getcwd(currWorkDirBuff, 1024);
3542 
3543  if (currWorkDir)
3544  {
3545  char **cwd_arg_str=new char*[nargs+1];
3546  for (int i=1; i<nargs; ++i) cwd_arg_str[i]=arg_str[i];
3547  cwd_arg_str[nargs]=nullptr;
3548  cwd_arg_str[0]=new char[strlen(currWorkDir)+strlen(arg_str[0])+16];
3549 
3550 
3551  strcpy(cwd_arg_str[0], currWorkDir);
3552  strcat(cwd_arg_str[0], "/");
3553  strcat(cwd_arg_str[0], arg_str[0]);
3554 
3555  //Why removing vectors and stop threads?
3556  //exec* never returns and memory is claimed by the system
3557  //furthermore after fork() only the thread which called fork() is forked!
3558 // cleanBeforeExec();
3559 
3560  ret = yarp::run::impl::execvp(cwd_arg_str[0], cwd_arg_str);
3561 
3562  delete [] cwd_arg_str[0];
3563  delete [] cwd_arg_str;
3564  }
3565 
3566  if (ret==YARPRUN_ERROR)
3567  {
3568  //Why removing vectors and stop threads?
3569  //exec* never returns and memory is claimed by the system
3570  //furthermore after fork() only the thread which called fork() is forked!
3571  // cleanBeforeExec();
3572  ret = yarp::run::impl::execvp(arg_str[0], arg_str);
3573  }
3574 
3575  if (ret==YARPRUN_ERROR)
3576  {
3577  int error=errno;
3578 
3579  std::string out=std::string("ABORTED: server=")+mPortName
3580  +std::string(" alias=")+strAlias
3581  +std::string(" cmd=")+strCmd
3582  +std::string("\nCan't execute command because ")+strerror(error)
3583  +std::string("\n");
3584 
3585  FILE* out_to_parent=fdopen(pipe_child_to_parent[WRITE_TO_PIPE], "w");
3586  fprintf(out_to_parent, "%s", out.c_str());
3587  fflush(out_to_parent);
3588  fclose(out_to_parent);
3589 
3590  if (saved_stderr >= 0)
3591  {
3592  REDIRECT_TO(STDERR_FILENO, saved_stderr);
3593  }
3594  fprintf(stderr, "%s", out.c_str());
3595  }
3596 
3597  delete [] cmd_str;
3598  delete [] arg_str;
3599 
3600  std::exit(ret);
3601  }
3602 
3603  if (IS_PARENT_OF(pid_cmd))
3604  {
3605  YarpRunProcInfo* pInf = new YarpRunProcInfo(strAlias, mPortName, pid_cmd, nullptr, false);
3606  pInf->setCmd(strCmd);
3607  if (msg.check("env")) pInf->setEnv(msg.find("env").asString());
3608  mProcessVector->Add(pInf);
3609  char pidstr[16];
3610  sprintf(pidstr, "%d", pid_cmd);
3611 
3613 
3614  FILE* in_from_child=fdopen(pipe_child_to_parent[READ_FROM_PIPE], "r");
3615  int flags=fcntl(pipe_child_to_parent[READ_FROM_PIPE], F_GETFL, 0);
3616  fcntl(pipe_child_to_parent[READ_FROM_PIPE], F_SETFL, flags|O_NONBLOCK);
3617 
3618  std::string out;
3619 
3620  if (in_from_child)
3621  {
3622  char buff[1024];
3623 
3624  while(true)
3625  {
3626  if (!fgets(buff, 1024, in_from_child) || ferror(in_from_child) || feof(in_from_child)) break;
3627 
3628  out+=std::string(buff);
3629  }
3630 
3631  fclose(in_from_child);
3632  }
3633 
3634  if (out.length()>0)
3635  {
3636  pid_cmd=YARPRUN_ERROR;
3637  }
3638  else
3639  {
3640  out=std::string("STARTED: server=")+mPortName
3641  +std::string(" alias=")+strAlias
3642  +std::string(" cmd=")+strCmd
3643  +std::string(" pid=")+int2String(pid_cmd)
3644  +std::string("\n");
3645  }
3646 
3647  fprintf(stderr, "%s", out.c_str());
3648 
3649  result.addInt32(pid_cmd);
3650  result.addString(out.c_str());
3651 
3652  CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
3653  CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
3654 
3655  return pid_cmd;
3656  }
3657 
3658  result.addInt32(YARPRUN_ERROR);
3659 
3660  return YARPRUN_ERROR;
3661 }
3662 
3663 #endif
3664 
3666 // API
3668 
3669 int yarp::run::Run::start(const std::string &node, yarp::os::Property &command, std::string &keyv)
3670 {
3671  yarp::os::Bottle msg, grp, response;
3672 
3673  grp.clear();
3674  grp.addString("on");
3675  grp.addString(node.c_str());
3676  msg.addList()=grp;
3677 
3678  std::string dest_srv=node;
3679 
3680  if (command.check("stdio"))
3681  {
3682  dest_srv=std::string(command.find("stdio").asString());
3683 
3684  grp.clear();
3685  grp.addString("stdio");
3686  grp.addString(dest_srv.c_str());
3687  msg.addList()=grp;
3688 
3689  if (command.check("geometry"))
3690  {
3691  grp.clear();
3692  grp.addString("geometry");
3693  grp.addString(command.find("geometry").asString().c_str());
3694  msg.addList()=grp;
3695  }
3696 
3697  if (command.check("hold"))
3698  {
3699  grp.clear();
3700  grp.addString("hold");
3701  msg.addList()=grp;
3702  }
3703  }
3704 
3705  grp.clear();
3706  grp.addString("as");
3707  grp.addString(keyv.c_str());
3708  msg.addList()=grp;
3709 
3710  grp.clear();
3711  grp.addString("cmd");
3712  grp.addString(command.find("name").asString().c_str());
3713  grp.addString(command.find("parameters").asString().c_str());
3714  msg.addList()=grp;
3715 
3716  printf(":: %s\n", msg.toString().c_str());
3717 
3718  response=sendMsg(msg, dest_srv.c_str());
3719 
3720  char buff[16];
3721  sprintf(buff, "%d", response.get(0).asInt32());
3722  keyv=std::string(buff);
3723 
3724  return response.get(0).asInt32()>0?0:YARPRUN_ERROR;
3725 }
3726 
3727 int yarp::run::Run::sigterm(const std::string &node, const std::string &keyv)
3728 {
3729  yarp::os::Bottle msg, grp, response;
3730 
3731  grp.clear();
3732  grp.addString("on");
3733  grp.addString(node.c_str());
3734  msg.addList()=grp;
3735 
3736  grp.clear();
3737  grp.addString("sigterm");
3738  grp.addString(keyv.c_str());
3739  msg.addList()=grp;
3740 
3741  printf(":: %s\n", msg.toString().c_str());
3742 
3743  response=sendMsg(msg, node.c_str());
3744 
3745  return response.get(0).asString()=="sigterm OK"?0:YARPRUN_ERROR;
3746 }
3747 
3748 int yarp::run::Run::sigterm(const std::string &node)
3749 {
3750  yarp::os::Bottle msg, grp, response;
3751 
3752  grp.clear();
3753  grp.addString("on");
3754  grp.addString(node.c_str());
3755  msg.addList()=grp;
3756 
3757  grp.clear();
3758  grp.addString("sigtermall");
3759  msg.addList()=grp;
3760 
3761  printf(":: %s\n", msg.toString().c_str());
3762 
3763  response=sendMsg(msg, node.c_str());
3764 
3765  return response.get(0).asString()=="sigtermall OK"?0:YARPRUN_ERROR;
3766 }
3767 
3768 int yarp::run::Run::kill(const std::string &node, const std::string &keyv, int s)
3769 {
3770  yarp::os::Bottle msg, grp, response;
3771 
3772  grp.clear();
3773  grp.addString("on");
3774  grp.addString(node.c_str());
3775  msg.addList()=grp;
3776 
3777  grp.clear();
3778  grp.addString("kill");
3779  grp.addString(keyv.c_str());
3780  grp.addInt32(s);
3781  msg.addList()=grp;
3782 
3783  printf(":: %s\n", msg.toString().c_str());
3784 
3785  response=sendMsg(msg, node.c_str());
3786 
3787  return response.get(0).asString()=="kill OK"?0:YARPRUN_ERROR;
3788 }
3789 
3790 bool yarp::run::Run::isRunning(const std::string &node, std::string &keyv)
3791 {
3792  yarp::os::Bottle msg, grp, response;
3793 
3794  grp.clear();
3795  grp.addString("on");
3796  grp.addString(node.c_str());
3797  msg.addList()=grp;
3798 
3799  grp.clear();
3800  grp.addString("isrunning");
3801  grp.addString(keyv.c_str());
3802  msg.addList()=grp;
3803 
3804  printf(":: %s\n", msg.toString().c_str());
3805 
3806  response=sendMsg(msg, node.c_str());
3807 
3808  if (!response.size()) return false;
3809 
3810  return response.get(0).asString()=="running";
3811 }
3812 
3813 // end API
int CLOSE(int h)
bool write(const ImageOf< PixelRgb > &src, const std::string &dest, image_fileformat format=FORMAT_PPM)
Definition: ImageFile.cpp:430
static RunTerminator * pTerminator
Definition: Run.cpp:81
void fromString(const std::string &text)
Initializes bottle from a string.
Definition: Bottle.cpp:163
static yarp::os::Bottle parsePaths(const std::string &txt)
Definition: Run.cpp:97
A port that is specialized as an RPC server.
Definition: RpcServer.h:29
void append(const Bottle &alt)
Append the content of the given bottle to the current list.
Definition: Bottle.cpp:339
static int client(yarp::os::Property &config)
Send a property object to a run server, bundling up all the settings usually specified on the command...
Definition: Run.cpp:1253
yarp::os::SystemInfo::MemoryInfo memory
system memory information
bool read(ImageOf< PixelRgb > &dest, const std::string &src, image_fileformat format=FORMAT_ANY)
Definition: ImageFile.cpp:393
std::string toString() const override
Return a standard text representation of the content of the object.
Definition: Value.cpp:343
bool ret
#define C_MAXARGS
Definition: Run.cpp:44
#define RUNLOG(msg)
static NameClient & getNameClient()
Get an instance of the name client.
Definition: NameClient.cpp:128
bool check(const std::string &key) const override
Check if there exists a property of the given name.
Definition: Property.cpp:957
yarp::os::SystemInfo::PlatformInfo platform
operating system information
void setEnv(const std::string &env)
char * getcwd(char *buf, size_t size)
Portable wrapper for the getcwd() function.
Definition: Os.cpp:107
A class for storing options and configuration information.
Definition: Property.h:35
bool start()
Start the new thread running.
Definition: Thread.cpp:98
static bool fileExists(const char *fname)
Definition: Run.cpp:122
int main(int argc, char *argv[])
Definition: yarpros.cpp:225
void addString(const char *str)
Places a string in the bottle, at the end of the list.
Definition: Bottle.cpp:129
virtual std::int32_t asInt32() const
Get 32-bit integer value.
Definition: Value.cpp:206
void parseArguments(char *io_pLine, int *o_pArgc, char **o_pArgv)
Breaks up a line into multiple arguments.
Definition: Run.cpp:2415
bool stop()
Stop the thread.
Definition: Thread.cpp:86
void useSystemClock()
Configure YARP to use system time (this is the default).
Definition: Time.cpp:139
A port that is specialized as an RPC client.
Definition: RpcClient.h:28
void sigstdio_handler(int sig)
Definition: Run.cpp:83
static int sigterm(const std::string &node, const std::string &keyv)
Terminate an application running on a yarprun server.
Definition: Run.cpp:3727
virtual bool write(const PortWriter &writer, const PortWriter *callback=nullptr) const override
Write an object to the port.
std::string toString() const override
Return a standard text representation of the content of the object.
Definition: Property.cpp:987
static char slash
Definition: Run.cpp:95
static int start(const std::string &node, yarp::os::Property &command, std::string &keyv)
Launch a yarprun server.
Definition: Run.cpp:3669
yarp::os::SystemInfo::LoadInfo load
current cpu load information
virtual bool open(const std::string &name) override
Start port operation, with a specific name, with automatically-chosen network parameters.
static bool getLocalMode()
Get current value of flag "localMode", see setLocalMode function.
Definition: Network.cpp:1001
virtual std::string asString() const
Get string value.
Definition: Value.cpp:236
Bottle & findGroup(const std::string &key) const override
Gets a list corresponding to a given keyword.
Definition: Bottle.cpp:261
#define yInfo
Definition: Log.h:99
virtual void close() override
Stop port activity.
float t
virtual bool check(const std::string &key) const override
Check if there exists a property of the given name.
Definition: Bottle.cpp:236
void clear()
Empties the bottle of any objects it contains.
Definition: Bottle.cpp:80
A helper class to pass the SystemInfo object around the YARP network.
void setCmd(const std::string &cmd)
virtual Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
Definition: Property.cpp:969
void splitLine(char *pLine, char **pArgs)
Split a line into separate words.
Definition: Run.cpp:2393
bool persistent
Specify whether a requested connection should be persistent.
Definition: ContactStyle.h:82
void addInt32(std::int32_t x)
Places a 32-bit integer in the bottle, at the end of the list.
Definition: Bottle.cpp:99
Preferences for how to communicate with a contact.
Definition: ContactStyle.h:29
Split a string into pieces.
Definition: SplitString.h:32
int SIGNAL(int pid, int signum)
static std::string getDirectorySeparator()
Get an OS-appropriate directory separator (e.g.
Definition: Network.cpp:1369
static std::string getEnvironment(const char *key, bool *found=nullptr)
Read a variable from the environment.
Definition: Network.cpp:1349
A simple collection of objects that can be described and transmitted in a portable way...
Definition: Bottle.h:70
yarp::os::SystemInfo::ProcessorInfo processor
system processor type information
void unput(const std::string &key)
Remove the association from the given key to a value, if present.
Definition: Property.cpp:963
A class for thread synchronization and mutual exclusion.
Definition: Semaphore.h:28
virtual Bottle & findGroup(const std::string &key) const override
Gets a list corresponding to a given keyword.
Definition: Property.cpp:1059
static bool isRunning(const std::string &node, std::string &keyv)
Get a report of all applications running on a yarprun server.
Definition: Run.cpp:3790
static bool checkNetwork()
Check if the YARP Network is up and running.
Definition: Network.cpp:1320
static std::string getPathSeparator()
Get an OS-appropriate path separator (e.g.
Definition: Network.cpp:1379
Bottle tail() const
Get all but the first element of a bottle.
Definition: Bottle.cpp:347
virtual std::string getName() const override
Get name of port.
Bottle & addList()
Places an empty nested list in the bottle, at the end of the list.
Definition: Bottle.cpp:141
virtual Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
Definition: Bottle.cpp:246
#define REDIRECT_TO(from, to)
Definition: Run.cpp:62
#define yError
Definition: Log.h:101
static bool disconnect(const std::string &src, const std::string &dest, bool quiet=true)
Request that an output port disconnect from an input port.
Definition: Network.cpp:666
#define YARP_UNUSED(var)
Definition: api.h:159
yarp::os::SystemInfo::UserInfo user
current user information
static void delaySystem(double seconds)
Definition: SystemClock.cpp:15
int getpid()
Portable wrapper for the getppid() function.
Definition: Os.cpp:93
void * HANDLE
yarp::os::SystemInfo::StorageInfo storage
system storage information
yarp::os::Property environmentVars
Definition: SystemInfo.h:88
void sigint_handler(int sig)
Definition: Run.cpp:484
#define YARPRUN_ERROR
int fork(void)
Portable wrapper for the fork() function.
Definition: Os.cpp:154
std::string send(const std::string &cmd, bool multi=true, const ContactStyle &style=ContactStyle())
Send a text message to the nameserver, and return the result.
Definition: NameClient.cpp:302
static int kill(const std::string &node, const std::string &keyv, int s)
Send a SIGNAL to an application running on a yarprun server (Linux only).
Definition: Run.cpp:3768
std::string toString() const override
Gives a human-readable textual representation of the bottle.
Definition: Bottle.cpp:170
int loop()
A single value (typically within a Bottle).
Definition: Value.h:40
void setVerbosity(int verbose=0)
Definition: Logger.cpp:132
static bool connect(const std::string &src, const std::string &dest, const std::string &carrier="", bool quiet=true)
Request that an output port connect to an input port.
Definition: Network.cpp:648
virtual bool read(PortReader &reader, bool willReply=true) override
Read an object from the port.
Definition: RpcServer.cpp:47
static void sigchld_handler(int sig)
Definition: Run.cpp:836
int loop()
std::string int2String(int x)
static Logger & get()
Definition: Logger.cpp:45
virtual bool reply(PortWriter &writer) override
Send an object as a reply to an object read from the port.
#define WRITE_TO_PIPE
Definition: Run.cpp:61
size_t size() const
Gets the number of elements in the bottle.
Definition: Bottle.cpp:210
#define READ_FROM_PIPE
Definition: Run.cpp:60
void put(const std::string &key, const std::string &value)
Associate the given key with the given string.
Definition: Property.cpp:931
void fromCommand(int argc, char *argv[], bool skipFirst=true, bool wipe=true)
Interprets a list of command arguments as a list of properties.
Definition: Property.cpp:992
Value & get(size_t index) const
Reads a Value v from a certain part of the list.
Definition: Bottle.cpp:205