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