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