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