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