YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
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 yarp::conf::environment::set_string("YARP_QUIET", "1");
2619 REDIRECT_TO(STDOUT_FILENO, pipe_stdin_to_cmd[WRITE_TO_PIPE]);
2620 REDIRECT_TO(STDERR_FILENO, pipe_stdin_to_cmd[WRITE_TO_PIPE]);
2621
2622 CLOSE(pipe_stdin_to_cmd[READ_FROM_PIPE]);
2623 CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
2624 CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
2625
2626 //Why removing vectors and stop threads?
2627 //exec* never returns and memory is claimed by the system
2628 //furthermore after fork() only the thread which called fork() is forked!
2629 // cleanBeforeExec();
2630
2631 //yarp::os::impl::signal(SIGPIPE, SIG_DFL);
2632
2633 int ret = yarp::run::impl::execlp("yarprun", "yarprun", "--read", strStdioUUID.c_str(), static_cast<char*>(nullptr));
2634
2635 CLOSE(pipe_stdin_to_cmd[WRITE_TO_PIPE]);
2636
2637 if (ret==YARPRUN_ERROR)
2638 {
2639 int error=errno;
2640
2641 std::string out=std::string("ABORTED: server=")+mPortName
2642 +std::string(" alias=")+strAlias
2643 +std::string(" cmd=stdin\n")
2644 +std::string("Can't execute stdin because ")+strerror(error)
2645 +std::string("\n");
2646
2647
2648 FILE* out_to_parent=fdopen(pipe_child_to_parent[WRITE_TO_PIPE], "w");
2649 fprintf(out_to_parent, "%s", out.c_str());
2650 fflush(out_to_parent);
2651 fclose(out_to_parent);
2652 fprintf(stderr, "%s", out.c_str());
2653 }
2654
2655 CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
2656
2657 std::exit(ret);
2658 }
2659
2660 if (IS_PARENT_OF(pid_stdin))
2661 {
2662 // connect yarp read and write
2663 CLOSE(pipe_stdin_to_cmd[WRITE_TO_PIPE]);
2664
2665 fprintf(stderr, "STARTED: server=%s alias=%s cmd=stdin pid=%d\n", mPortName.c_str(), strAlias.c_str(), pid_stdin);
2666
2667 int pid_cmd=yarp::run::impl::fork();
2668
2669 if (IS_INVALID(pid_cmd))
2670 {
2671 int error=errno;
2672
2673 CLOSE(pipe_stdin_to_cmd[READ_FROM_PIPE]);
2674 CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
2675 CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
2676
2677 std::string out=std::string("ABORTED: server=")+mPortName
2678 +std::string(" alias=")+strAlias
2679 +std::string(" cmd=")+strCmd
2680 +std::string("\nCan't fork command process because ")+strerror(error)
2681 +std::string("\n");
2682
2683 result.addInt32(YARPRUN_ERROR);
2684 result.addString(out.c_str());
2685 fprintf(stderr, "%s", out.c_str());
2686
2687 FILE* to_yarp_stdout=fdopen(pipe_cmd_to_stdout[WRITE_TO_PIPE], "w");
2688 fprintf(to_yarp_stdout, "%s", out.c_str());
2689 fflush(to_yarp_stdout);
2690 fclose(to_yarp_stdout);
2691
2692 SIGNAL(pid_stdout, SIGTERM);
2693 fprintf(stderr, "TERMINATING stdout (%d)\n", pid_stdout);
2694 SIGNAL(pid_stdin, SIGTERM);
2695 fprintf(stderr, "TERMINATING stdin (%d)\n", pid_stdin);
2696
2697 CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
2698
2699 return YARPRUN_ERROR;
2700 }
2701
2702 if (IS_NEW_PROCESS(pid_cmd)) // RUN COMMAND HERE
2703 {
2704 CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
2705
2706 char *cmd_str=new char[strCmd.length()+1];
2707 strcpy(cmd_str, strCmd.c_str());
2708 /*
2709 int nargs=CountArgs(cmd_str);
2710 char **arg_str=new char*[nargs+1];
2711 ParseCmd(cmd_str, arg_str);
2712 arg_str[nargs]=0;
2713 */
2714 int nargs = 0;
2715 char **arg_str = new char*[C_MAXARGS + 1];
2716 parseArguments(cmd_str, &nargs, arg_str);
2717 arg_str[nargs]=nullptr;
2718
2719 setvbuf(stdout, nullptr, _IONBF, 0);
2720
2721 REDIRECT_TO(STDIN_FILENO, pipe_stdin_to_cmd[READ_FROM_PIPE]);
2722 REDIRECT_TO(STDOUT_FILENO, pipe_cmd_to_stdout[WRITE_TO_PIPE]);
2723 REDIRECT_TO(STDERR_FILENO, pipe_cmd_to_stdout[WRITE_TO_PIPE]);
2724
2725 // Set the YARP_IS_YARPRUN environment variable to 1, so that the child
2726 // process will now that is running inside yarprun.
2727 yarp::conf::environment::set_string("YARP_IS_YARPRUN", "1");
2728
2729 // Set the YARPRUN_IS_FORWARDING_LOG environment variable to 1, so that
2730 // the child process will now that yarprun is not logging the output.
2731 yarp::conf::environment::set_string("YARPRUN_IS_FORWARDING_LOG", "1");
2732
2733 if (msg.check("env"))
2734 {
2735 auto ss = yarp::conf::string::split(msg.find("env").asString(), ';');
2736 for (const auto& s : ss) {
2737 char* szenv = new char[s.size()+1];
2738 strcpy(szenv, s.c_str());
2739 yarp::run::impl::putenv(szenv); // putenv doesn't make copy of the string
2740 }
2741 //delete [] szenv;
2742 }
2743
2744 if (msg.check("workdir"))
2745 {
2746 int ret = yarp::os::impl::chdir(msg.find("workdir").asString().c_str());
2747
2748 if (ret!=0)
2749 {
2750 int error=errno;
2751
2752 std::string out=std::string("ABORTED: server=")+mPortName
2753 +std::string(" alias=")+strAlias
2754 +std::string(" cmd=")+strCmd
2755 +std::string("\nCan't execute command, cannot set working directory ")+strerror(error)
2756 +std::string("\n");
2757
2758 FILE* out_to_parent=fdopen(pipe_child_to_parent[WRITE_TO_PIPE], "w");
2759 fprintf(out_to_parent, "%s", out.c_str());
2760 fflush(out_to_parent);
2761 fclose(out_to_parent);
2762 fprintf(stderr, "%s", out.c_str());
2763
2764 std::exit(ret);
2765 }
2766 }
2767
2768 int ret=YARPRUN_ERROR;
2769
2770 char currWorkDirBuff[1024];
2771 char *currWorkDir=yarp::os::impl::getcwd(currWorkDirBuff, 1024);
2772
2773 if (currWorkDir)
2774 {
2775 char **cwd_arg_str=new char*[nargs+1];
2776 for (int i = 1; i < nargs; ++i) {
2777 cwd_arg_str[i] = arg_str[i];
2778 }
2779 cwd_arg_str[nargs]=nullptr;
2780 cwd_arg_str[0]=new char[strlen(currWorkDir)+strlen(arg_str[0])+16];
2781
2782 strcpy(cwd_arg_str[0], currWorkDir);
2783 strcat(cwd_arg_str[0], "/");
2784 strcat(cwd_arg_str[0], arg_str[0]);
2785
2786 //Why removing vectors and stop threads?
2787 //exec* never returns and memory is claimed by the system
2788 //furthermore after fork() only the thread which called fork() is forked!
2789 // cleanBeforeExec();
2790
2791 ret = yarp::run::impl::execvp(cwd_arg_str[0], cwd_arg_str);
2792
2793 delete [] cwd_arg_str[0];
2794 delete [] cwd_arg_str;
2795 }
2796
2797 if (ret==YARPRUN_ERROR)
2798 {
2799 //Why removing vectors and stop threads?
2800 //exec* never returns and memory is claimed by the system
2801 //furthermore after fork() only the thread which called fork() is forked!
2802 // cleanBeforeExec();
2803
2804 ret = yarp::run::impl::execvp(arg_str[0], arg_str);
2805 }
2806
2807 fflush(stdout);
2808
2809 CLOSE(pipe_stdin_to_cmd[READ_FROM_PIPE]);
2810 CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
2811
2812 if (ret==YARPRUN_ERROR)
2813 {
2814 int error=errno;
2815
2816 std::string out=std::string("ABORTED: server=")+mPortName
2817 +std::string(" alias=")+strAlias
2818 +std::string(" cmd=")+strCmd
2819 +std::string("\nCan't execute command because ")+strerror(error)
2820 +std::string("\n");
2821
2822 FILE* out_to_parent=fdopen(pipe_child_to_parent[WRITE_TO_PIPE], "w");
2823 fprintf(out_to_parent, "%s", out.c_str());
2824 fflush(out_to_parent);
2825 fclose(out_to_parent);
2826 fprintf(stderr, "%s", out.c_str());
2827 }
2828
2829 delete [] cmd_str;
2830 delete [] arg_str;
2831
2832 CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
2833
2834 std::exit(ret);
2835 }
2836
2837
2838 if (IS_PARENT_OF(pid_cmd))
2839 {
2840 CLOSE(pipe_stdin_to_cmd[READ_FROM_PIPE]);
2841 CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
2842 CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
2843
2844 auto* pInf = new YarpRunCmdWithStdioInfo(
2845 strAlias,
2846 mPortName,
2847 strStdio,
2848 pid_cmd,
2849 strStdioUUID,
2850 mStdioVector,
2851 pid_stdin,
2852 pid_stdout,
2853 pipe_stdin_to_cmd[READ_FROM_PIPE],
2854 pipe_stdin_to_cmd[WRITE_TO_PIPE],
2855 pipe_cmd_to_stdout[READ_FROM_PIPE],
2856 pipe_cmd_to_stdout[WRITE_TO_PIPE],
2857 nullptr,
2858 false
2859 );
2860
2861 pInf->setCmd(strCmd);
2862
2863 if (msg.check("env"))
2864 {
2865 pInf->setEnv(msg.find("env").asString());
2866 }
2867
2868 mProcessVector->Add(pInf);
2869
2871
2872 FILE* in_from_child=fdopen(pipe_child_to_parent[READ_FROM_PIPE], "r");
2873 int flags=fcntl(pipe_child_to_parent[READ_FROM_PIPE], F_GETFL, 0);
2874 fcntl(pipe_child_to_parent[READ_FROM_PIPE], F_SETFL, flags|O_NONBLOCK);
2875
2876 std::string out;
2877
2878 if (in_from_child)
2879 {
2880 char buff[1024];
2881
2882 while(true)
2883 {
2884 if (!fgets(buff, 1024, in_from_child) || ferror(in_from_child) || feof(in_from_child)) {
2885 break;
2886 }
2887
2888 out+=std::string(buff);
2889 }
2890
2891 fclose(in_from_child);
2892 }
2893
2894 if (out.length()>0)
2895 {
2896 pid_cmd=YARPRUN_ERROR;
2897 }
2898 else
2899 {
2900 out=std::string("STARTED: server=")+mPortName
2901 +std::string(" alias=")+strAlias
2902 +std::string(" cmd=")+strCmd
2903 +std::string(" pid=")+int2String(pid_cmd)
2904 +std::string("\n");
2905 }
2906
2907 result.addInt32(pid_cmd);
2908 result.addString(out.c_str());
2909 result.addString(strStdioUUID.c_str());
2910
2911 fprintf(stderr, "%s", out.c_str());
2912
2913 CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
2914
2915 return pid_cmd;
2916 }
2917 }
2918 }
2919
2920 result.addInt32(YARPRUN_ERROR);
2921 result.addString("I should never reach this point!!!\n");
2922
2923 return YARPRUN_ERROR;
2924}
2925
2926int yarp::run::Run::executeCmdStdout(yarp::os::Bottle& msg, yarp::os::Bottle& result, std::string& loggerName)
2927{
2928 std::string proc_label = getProcLabel(msg);
2929
2930 std::string strAlias=msg.find("as").asString();
2931 std::string strCmd=msg.find("cmd").asString();
2932
2933 std::string portName="/log";
2934 portName+=mPortName+"/";
2935
2936 std::string command = strCmd;
2937 command = command.substr(0, command.find(' '));
2938 command = command.substr(command.find_last_of("\\/") + 1);
2939
2940 portName+=command;
2941 if (proc_label != "") { portName += "[" + proc_label + "]"; }
2942
2943
2944 int pipe_cmd_to_stdout[2];
2945 int ret_cmd_to_stdout=yarp::run::impl::pipe(pipe_cmd_to_stdout);
2946
2947 int pipe_child_to_parent[2];
2948 int ret_child_to_parent=yarp::run::impl::pipe(pipe_child_to_parent);
2949
2950 if (ret_child_to_parent!=0 || ret_cmd_to_stdout!=0)
2951 {
2952 int error=errno;
2953
2954 std::string out=std::string("ABORTED: server=")+mPortName
2955 +std::string(" alias=")+strAlias
2956 +std::string(" cmd=stdout\n")
2957 +std::string("Can't create pipes ")+strerror(error)
2958 +std::string("\n");
2959
2960 result.addInt32(YARPRUN_ERROR);
2961 result.addString(out.c_str());
2962 fprintf(stderr, "%s", out.c_str());
2963
2964 return YARPRUN_ERROR;
2965 }
2966
2967 int pid_stdout=yarp::run::impl::fork();
2968
2969 if (IS_INVALID(pid_stdout))
2970 {
2971 int error=errno;
2972
2973 CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
2974 CLOSE(pipe_cmd_to_stdout[READ_FROM_PIPE]);
2975 CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
2976 CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
2977
2978 std::string out=std::string("ABORTED: server=")+mPortName
2979 +std::string(" alias=")+strAlias
2980 +std::string(" cmd=stdout\n")
2981 +std::string("Can't fork stdout process because ")+strerror(error)
2982 +std::string("\n");
2983
2984 result.addInt32(YARPRUN_ERROR);
2985 result.addString(out.c_str());
2986 fprintf(stderr, "%s", out.c_str());
2987
2988 return YARPRUN_ERROR;
2989 }
2990
2991 if (IS_NEW_PROCESS(pid_stdout)) // STDOUT IMPLEMENTED HERE
2992 {
2993 REDIRECT_TO(STDIN_FILENO, pipe_cmd_to_stdout[READ_FROM_PIPE]);
2994
2995 CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
2996 CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
2997
2998 //Why removing vectors and stop threads?
2999 //exec* never returns and memory is claimed by the system
3000 //furthermore after fork() only the thread which called fork() is forked!
3001 // cleanBeforeExec();
3002
3003 //yarp::os::impl::signal(SIGPIPE, SIG_DFL);
3004
3005 int ret = yarp::run::impl::execlp("yarprun", "yarprun", "--write", portName.c_str(), "--log", loggerName.c_str(), static_cast<char*>(nullptr));
3006
3007 CLOSE(pipe_cmd_to_stdout[READ_FROM_PIPE]);
3008
3009 if (ret==YARPRUN_ERROR)
3010 {
3011 int error=errno;
3012
3013 std::string out=std::string("ABORTED: server=")+mPortName
3014 +std::string(" alias=")+strAlias
3015 +std::string(" cmd=stdout\n")
3016 +std::string("Can't execute stdout because ")+strerror(error)
3017 +std::string("\n");
3018
3019 FILE* out_to_parent=fdopen(pipe_child_to_parent[WRITE_TO_PIPE], "w");
3020 fprintf(out_to_parent, "%s", out.c_str());
3021 fflush(out_to_parent);
3022 fclose(out_to_parent);
3023
3024 fprintf(stderr, "%s", out.c_str());
3025 }
3026
3027 CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
3028
3029 std::exit(ret);
3030 }
3031
3032 if (IS_PARENT_OF(pid_stdout))
3033 {
3034 CLOSE(pipe_cmd_to_stdout[READ_FROM_PIPE]);
3035
3036 fprintf(stderr, "STARTED: server=%s alias=%s cmd=stdout pid=%d\n", mPortName.c_str(), strAlias.c_str(), pid_stdout);
3037
3039
3040 //if (IS_PARENT_OF(pid_stdin))
3041 {
3042 int pid_cmd=yarp::run::impl::fork();
3043
3044 if (IS_INVALID(pid_cmd))
3045 {
3046 int error=errno;
3047
3048 CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
3049 CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
3050
3051 std::string out=std::string("ABORTED: server=")+mPortName
3052 +std::string(" alias=")+strAlias
3053 +std::string(" cmd=")+strCmd
3054 +std::string("\nCan't fork command process because ")+strerror(error)
3055 +std::string("\n");
3056
3057 result.addInt32(YARPRUN_ERROR);
3058 result.addString(out.c_str());
3059 fprintf(stderr, "%s", out.c_str());
3060
3061 FILE* to_yarp_stdout=fdopen(pipe_cmd_to_stdout[WRITE_TO_PIPE], "w");
3062 fprintf(to_yarp_stdout, "%s", out.c_str());
3063 fflush(to_yarp_stdout);
3064 fclose(to_yarp_stdout);
3065
3066 SIGNAL(pid_stdout, SIGTERM);
3067 fprintf(stderr, "TERMINATING stdout (%d)\n", pid_stdout);
3068 CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
3069
3070 return YARPRUN_ERROR;
3071 }
3072
3073 if (IS_NEW_PROCESS(pid_cmd)) // RUN COMMAND HERE
3074 {
3075 CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
3076
3077 char *cmd_str=new char[strCmd.length()+1];
3078 strcpy(cmd_str, strCmd.c_str());
3079 /*
3080 int nargs=CountArgs(cmd_str);
3081 char **arg_str=new char*[nargs+1];
3082 ParseCmd(cmd_str, arg_str);
3083 arg_str[nargs]=0;
3084 */
3085 int nargs = 0;
3086 char **arg_str = new char*[C_MAXARGS + 1];
3087 parseArguments(cmd_str, &nargs, arg_str);
3088 arg_str[nargs]=nullptr;
3089
3090 setvbuf(stdout, nullptr, _IONBF, 0);
3091
3092 REDIRECT_TO(STDOUT_FILENO, pipe_cmd_to_stdout[WRITE_TO_PIPE]);
3093 REDIRECT_TO(STDERR_FILENO, pipe_cmd_to_stdout[WRITE_TO_PIPE]);
3094
3095 // Set the YARP_IS_YARPRUN environment variable to 1, so that the child
3096 // process will now that is running inside yarprun.
3097 yarp::conf::environment::set_string("YARP_IS_YARPRUN", "1");
3098
3099 // Set the YARPRUN_IS_FORWARDING_LOG environment variable to 1, so that
3100 // the child process will now that yarprun is not logging the output.
3101 yarp::conf::environment::set_string("YARPRUN_IS_FORWARDING_LOG", "1");
3102
3103 if (msg.check("env"))
3104 {
3105 auto ss = yarp::conf::string::split(msg.find("env").asString(), ';');
3106 for (const auto& s : ss) {
3107 char* szenv = new char[s.size()+1];
3108 strcpy(szenv, s.c_str());
3109 yarp::run::impl::putenv(szenv); // putenv doesn't make copy of the string
3110 }
3111 //delete [] szenv;
3112 }
3113
3114 if (msg.check("workdir"))
3115 {
3116 int ret = yarp::os::impl::chdir(msg.find("workdir").asString().c_str());
3117
3118 if (ret!=0)
3119 {
3120 int error=errno;
3121
3122 std::string out=std::string("ABORTED: server=")+mPortName
3123 +std::string(" alias=")+strAlias
3124 +std::string(" cmd=")+strCmd
3125 +std::string("\nCan't execute command, cannot set working directory ")+strerror(error)
3126 +std::string("\n");
3127
3128 FILE* out_to_parent=fdopen(pipe_child_to_parent[WRITE_TO_PIPE], "w");
3129 fprintf(out_to_parent, "%s", out.c_str());
3130 fflush(out_to_parent);
3131 fclose(out_to_parent);
3132 fprintf(stderr, "%s", out.c_str());
3133
3134 std::exit(ret);
3135 }
3136 }
3137
3138 int ret=YARPRUN_ERROR;
3139
3140 char currWorkDirBuff[1024];
3141 char *currWorkDir=getcwd(currWorkDirBuff, 1024);
3142
3143 if (currWorkDir)
3144 {
3145 char **cwd_arg_str=new char*[nargs+1];
3146 for (int i = 1; i < nargs; ++i) {
3147 cwd_arg_str[i] = arg_str[i];
3148 }
3149 cwd_arg_str[nargs]=nullptr;
3150 cwd_arg_str[0]=new char[strlen(currWorkDir)+strlen(arg_str[0])+16];
3151
3152 strcpy(cwd_arg_str[0], currWorkDir);
3153 strcat(cwd_arg_str[0], "/");
3154 strcat(cwd_arg_str[0], arg_str[0]);
3155
3156 //Why removing vectors and stop threads?
3157 //exec* never returns and memory is claimed by the system
3158 //furthermore after fork() only the thread which called fork() is forked!
3159 // cleanBeforeExec();
3160
3161 ret = yarp::run::impl::execvp(cwd_arg_str[0], cwd_arg_str);
3162
3163 delete [] cwd_arg_str[0];
3164 delete [] cwd_arg_str;
3165 }
3166
3167 if (ret==YARPRUN_ERROR)
3168 {
3169 //Why removing vectors and stop threads?
3170 //exec* never returns and memory is claimed by the system
3171 //furthermore after fork() only the thread which called fork() is forked!
3172 // cleanBeforeExec();
3173
3174 ret = yarp::run::impl::execvp(arg_str[0], arg_str);
3175 }
3176
3177 fflush(stdout);
3178
3179 CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
3180
3181 if (ret==YARPRUN_ERROR)
3182 {
3183 int error=errno;
3184
3185 std::string out=std::string("ABORTED: server=")+mPortName
3186 +std::string(" alias=")+strAlias
3187 +std::string(" cmd=")+strCmd
3188 +std::string("\nCan't execute command because ")+strerror(error)
3189 +std::string("\n");
3190
3191 FILE* out_to_parent=fdopen(pipe_child_to_parent[WRITE_TO_PIPE], "w");
3192 fprintf(out_to_parent, "%s", out.c_str());
3193 fflush(out_to_parent);
3194 fclose(out_to_parent);
3195 fprintf(stderr, "%s", out.c_str());
3196 }
3197
3198 delete [] cmd_str;
3199 delete [] arg_str;
3200
3201 CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
3202
3203 std::exit(ret);
3204 }
3205
3206
3207 if (IS_PARENT_OF(pid_cmd))
3208 {
3209 CLOSE(pipe_cmd_to_stdout[WRITE_TO_PIPE]);
3210 CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
3211
3212 auto* pInf = new YarpRunCmdWithStdioInfo(
3213 strAlias,
3214 mPortName,
3215 portName,
3216 pid_cmd,
3217 pid_stdout,
3218 pipe_cmd_to_stdout[READ_FROM_PIPE],
3219 pipe_cmd_to_stdout[WRITE_TO_PIPE],
3220 nullptr,
3221 false
3222 );
3223
3224 pInf->setCmd(strCmd);
3225
3226 if (msg.check("env"))
3227 {
3228 pInf->setEnv(msg.find("env").asString());
3229 }
3230
3231 mProcessVector->Add(pInf);
3232
3234
3235 FILE* in_from_child=fdopen(pipe_child_to_parent[READ_FROM_PIPE], "r");
3236 int flags=fcntl(pipe_child_to_parent[READ_FROM_PIPE], F_GETFL, 0);
3237 fcntl(pipe_child_to_parent[READ_FROM_PIPE], F_SETFL, flags|O_NONBLOCK);
3238
3239 std::string out;
3240
3241 if (in_from_child)
3242 {
3243 char buff[1024];
3244
3245 while(true)
3246 {
3247 if (!fgets(buff, 1024, in_from_child) || ferror(in_from_child) || feof(in_from_child)) {
3248 break;
3249 }
3250
3251 out+=std::string(buff);
3252 }
3253
3254 fclose(in_from_child);
3255 }
3256
3257 if (out.length()>0)
3258 {
3259 pid_cmd=YARPRUN_ERROR;
3260 }
3261 else
3262 {
3263 out=std::string("STARTED: server=")+mPortName
3264 +std::string(" alias=")+strAlias
3265 +std::string(" cmd=")+strCmd
3266 +std::string(" pid=")+int2String(pid_cmd)
3267 +std::string("\n");
3268 }
3269
3270 result.addInt32(pid_cmd);
3271 result.addString(out.c_str());
3272
3273 fprintf(stderr, "%s", out.c_str());
3274
3275 CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
3276
3277 return pid_cmd;
3278 }
3279 }
3280 }
3281
3282 result.addInt32(YARPRUN_ERROR);
3283 result.addString("I should never reach this point!!!\n");
3284
3285 return YARPRUN_ERROR;
3286}
3287
3288int yarp::run::Run::userStdio(yarp::os::Bottle& msg, yarp::os::Bottle& result)
3289{
3290 std::string strAlias=msg.find("as").asString();
3291 std::string strUUID=msg.find("stdiouuid").asString();
3292
3293 std::string strCmd;
3294
3295 if (msg.check("forward"))
3296 {
3297 strCmd=std::string("/bin/bash -l -c \"yarprun --readwrite ")+strUUID
3298 +std::string(" --forward ")+msg.findGroup("forward").get(1).asString()+std::string(" ")+msg.findGroup("forward").get(2).asString()+std::string("\"");
3299 }
3300 else
3301 {
3302 strCmd=std::string("/bin/bash -l -c \"yarprun --readwrite ")+strUUID+"\"";
3303 }
3304
3305 int pipe_child_to_parent[2];
3306
3307 if (yarp::run::impl::pipe(pipe_child_to_parent))
3308 {
3309 int error=errno;
3310
3311 std::string out=std::string("ABORTED: server=")+mPortName
3312 +std::string(" alias=")+strAlias
3313 +std::string(" cmd=stdio\nCan't create pipe ")+strerror(error)
3314 +std::string("\n");
3315
3316 result.clear();
3317 result.addInt32(YARPRUN_ERROR);
3318 result.addString(out.c_str());
3319 fprintf(stderr, "%s", out.c_str());
3320
3321 return YARPRUN_ERROR;
3322 }
3323
3324 int c=0;
3325 char *command[16];
3326 for (auto & i : command) {
3327 i = nullptr;
3328 }
3329
3330 cmdcpy(command[c++], "xterm");
3331 cmdcpy(command[c++], msg.check("hold")?"-hold":"+hold");
3332
3333 if (msg.check("geometry"))
3334 {
3335 cmdcpy(command[c++], "-geometry");
3336 cmdcpy(command[c++], msg.find("geometry").asString().c_str());
3337 }
3338
3339 cmdcpy(command[c++], "-title");
3340 cmdcpy(command[c++], strAlias.c_str());
3341
3342 cmdcpy(command[c++], "-e");
3343 cmdcpy(command[c++], strCmd.c_str());
3344
3345 int pid_cmd=yarp::run::impl::fork();
3346
3347 if (IS_INVALID(pid_cmd))
3348 {
3349 int error=errno;
3350
3351 std::string out=std::string("ABORTED: server=")+mPortName
3352 +std::string(" alias=")+strAlias
3353 +std::string(" cmd=stdio\nCan't fork stdout process because ")+strerror(error)
3354 +std::string("\n");
3355
3356 result.clear();
3357 result.addInt32(YARPRUN_ERROR);
3358 result.addString(out.c_str());
3359 fprintf(stderr, "%s", out.c_str());
3360
3361 CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
3362 CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
3363
3364 cmdclean(command);
3365
3366 return YARPRUN_ERROR;
3367 }
3368
3369 if (IS_NEW_PROCESS(pid_cmd)) // RUN COMMAND HERE
3370 {
3371 //yarp::os::impl::signal(SIGPIPE, SIG_IGN);
3372
3373 CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
3374
3375 REDIRECT_TO(STDERR_FILENO, pipe_child_to_parent[WRITE_TO_PIPE]);
3376
3377 //Why removing vectors and stop threads?
3378 //exec* never returns and memory is claimed by the system
3379 //furthermore after fork() only the thread which called fork() is forked!
3380 // cleanBeforeExec();
3381
3382 //yarp::os::impl::signal(SIGHUP, rwSighupHandler);
3383
3384 int ret = yarp::run::impl::execvp("xterm", command);
3385
3386 cmdclean(command);
3387
3388 if (ret==YARPRUN_ERROR)
3389 {
3390 int error=errno;
3391
3392 std::string out=std::string("ABORTED: server=")+mPortName
3393 +std::string(" alias=")+strAlias
3394 +std::string(" cmd=xterm\nCan't execute command because ")+strerror(error)
3395 +std::string("\n");
3396
3397 FILE* out_to_parent=fdopen(pipe_child_to_parent[WRITE_TO_PIPE], "w");
3398
3399 fprintf(out_to_parent, "%s", out.c_str());
3400 fflush(out_to_parent);
3401 fclose(out_to_parent);
3402
3403 fprintf(stderr, "%s", out.c_str());
3404 }
3405
3406 CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
3407
3408 std::exit(ret);
3409 }
3410
3411 if (IS_PARENT_OF(pid_cmd))
3412 {
3413 CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
3414
3415 mStdioVector->Add(new YarpRunProcInfo(strAlias, mPortName, pid_cmd, nullptr, msg.check("hold")));
3416
3417 result.clear();
3418
3419 cmdclean(command);
3420
3422
3423 FILE* in_from_child=fdopen(pipe_child_to_parent[READ_FROM_PIPE], "r");
3424 int flags=fcntl(pipe_child_to_parent[READ_FROM_PIPE], F_GETFL, 0);
3425 fcntl(pipe_child_to_parent[READ_FROM_PIPE], F_SETFL, flags|O_NONBLOCK);
3426 std::string out;
3427
3428 if (in_from_child)
3429 {
3430 char buff[1024];
3431
3432 while(true)
3433 {
3434 if (!fgets(buff, 1024, in_from_child) || ferror(in_from_child) || feof(in_from_child)) {
3435 break;
3436 }
3437
3438 out+=std::string(buff);
3439 }
3440
3441 fclose(in_from_child);
3442 }
3443
3444 result.clear();
3445
3446 //if (out.length()>0)
3447 if (out.substr(0, 14)=="xterm Xt error" || out.substr(0, 7)=="ABORTED")
3448 {
3449 pid_cmd=YARPRUN_ERROR;
3450 }
3451 else
3452 {
3453 out=std::string("STARTED: server=")+mPortName
3454 +std::string(" alias=")+strAlias
3455 +std::string(" cmd=xterm pid=")+int2String(pid_cmd)
3456 +std::string("\n");
3457
3458 }
3459
3460 fprintf(stderr, "%s", out.c_str());
3461
3462 result.addInt32(pid_cmd);
3463 result.addString(out.c_str());
3464
3465 CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
3466
3467 return pid_cmd;
3468 }
3469
3470 result.clear();
3471 result.addInt32(YARPRUN_ERROR);
3472
3473 return YARPRUN_ERROR;
3474}
3475
3476int yarp::run::Run::executeCmd(yarp::os::Bottle& msg, yarp::os::Bottle& result)
3477{
3478 std::string strAlias(msg.find("as").asString());
3479 std::string strCmd(msg.find("cmd").toString());
3480
3481 int pipe_child_to_parent[2];
3482 int ret_pipe_child_to_parent=yarp::run::impl::pipe(pipe_child_to_parent);
3483
3484 if (ret_pipe_child_to_parent!=0)
3485 {
3486 int error=errno;
3487
3488 std::string out=std::string("ABORTED: server=")+mPortName
3489 +std::string(" alias=")+strAlias
3490 +std::string(" cmd=stdio\nCan't create pipe ")+strerror(error)
3491 +std::string("\n");
3492
3493
3494 result.addInt32(YARPRUN_ERROR);
3495 result.addString(out.c_str());
3496 fprintf(stderr, "%s", out.c_str());
3497
3498 return YARPRUN_ERROR;
3499 }
3500
3501 int pid_cmd=yarp::run::impl::fork();
3502
3503 if (IS_INVALID(pid_cmd))
3504 {
3505 int error=errno;
3506
3507 std::string out=std::string("ABORTED: server=")+mPortName
3508 +std::string(" alias=")+strAlias
3509 +std::string(" cmd=")+strCmd
3510 +std::string("\nCan't fork command process because ")+strerror(error)
3511 +std::string("\n");
3512
3513 result.addInt32(YARPRUN_ERROR);
3514 result.addString(out.c_str());
3515 fprintf(stderr, "%s", out.c_str());
3516
3517 return YARPRUN_ERROR;
3518 }
3519
3520 if (IS_NEW_PROCESS(pid_cmd)) // RUN COMMAND HERE
3521 {
3522 int saved_stderr = yarp::run::impl::dup(STDERR_FILENO);
3523 int null_file=open("/dev/null", O_WRONLY);
3524 if (null_file >= 0)
3525 {
3526 REDIRECT_TO(STDOUT_FILENO, null_file);
3527 REDIRECT_TO(STDERR_FILENO, null_file);
3528 close(null_file);
3529 }
3530 char *cmd_str=new char[strCmd.length()+1];
3531 strcpy(cmd_str, strCmd.c_str());
3532 /*
3533 int nargs=CountArgs(cmd_str);
3534 char **arg_str=new char*[nargs+1];
3535 ParseCmd(cmd_str, arg_str);
3536 arg_str[nargs]=0;
3537 */
3538 int nargs = 0;
3539 char **arg_str = new char*[C_MAXARGS + 1];
3540 parseArguments(cmd_str, &nargs, arg_str);
3541 arg_str[nargs]=nullptr;
3542
3543 // Set the YARP_IS_YARPRUN environment variable to 1, so that the child
3544 // process will now that is running inside yarprun.
3545 yarp::conf::environment::set_string("YARP_IS_YARPRUN", "1");
3546
3547 // Set the YARPRUN_IS_FORWARDING_LOG environment variable to 0, so that
3548 // the child process will now that yarprun is not logging the output.
3549 yarp::conf::environment::set_string("YARPRUN_IS_FORWARDING_LOG", "0");
3550
3551 if (msg.check("env"))
3552 {
3553 auto ss = yarp::conf::string::split(msg.find("env").asString(), ';');
3554 for (const auto& s : ss) {
3555 char* szenv = new char[s.size()+1];
3556 strcpy(szenv, s.c_str());
3557 yarp::run::impl::putenv(szenv); // putenv doesn't make copy of the string
3558 }
3559 }
3560
3561 if (msg.check("workdir"))
3562 {
3563 int ret = yarp::os::impl::chdir(msg.find("workdir").asString().c_str());
3564
3565 if (ret!=0)
3566 {
3567 int error=errno;
3568
3569 std::string out=std::string("ABORTED: server=")+mPortName
3570 +std::string(" alias=")+strAlias
3571 +std::string(" cmd=")+strCmd
3572 +std::string("\nCan't execute command, cannot set working directory ")+strerror(error)
3573 +std::string("\n");
3574
3575 FILE* out_to_parent=fdopen(pipe_child_to_parent[WRITE_TO_PIPE], "w");
3576 fprintf(out_to_parent, "%s", out.c_str());
3577 fflush(out_to_parent);
3578 fclose(out_to_parent);
3579
3580 REDIRECT_TO(STDERR_FILENO, saved_stderr);
3581 fprintf(stderr, "%s", out.c_str());
3582 }
3583 }
3584
3585 int ret=YARPRUN_ERROR;
3586
3587 char currWorkDirBuff[1024];
3588 char *currWorkDir=getcwd(currWorkDirBuff, 1024);
3589
3590 if (currWorkDir)
3591 {
3592 char **cwd_arg_str=new char*[nargs+1];
3593 for (int i = 1; i < nargs; ++i) {
3594 cwd_arg_str[i] = arg_str[i];
3595 }
3596 cwd_arg_str[nargs]=nullptr;
3597 cwd_arg_str[0]=new char[strlen(currWorkDir)+strlen(arg_str[0])+16];
3598
3599
3600 strcpy(cwd_arg_str[0], currWorkDir);
3601 strcat(cwd_arg_str[0], "/");
3602 strcat(cwd_arg_str[0], arg_str[0]);
3603
3604 //Why removing vectors and stop threads?
3605 //exec* never returns and memory is claimed by the system
3606 //furthermore after fork() only the thread which called fork() is forked!
3607// cleanBeforeExec();
3608
3609 ret = yarp::run::impl::execvp(cwd_arg_str[0], cwd_arg_str);
3610
3611 delete [] cwd_arg_str[0];
3612 delete [] cwd_arg_str;
3613 }
3614
3615 if (ret==YARPRUN_ERROR)
3616 {
3617 //Why removing vectors and stop threads?
3618 //exec* never returns and memory is claimed by the system
3619 //furthermore after fork() only the thread which called fork() is forked!
3620 // cleanBeforeExec();
3621 ret = yarp::run::impl::execvp(arg_str[0], arg_str);
3622 }
3623
3624 if (ret==YARPRUN_ERROR)
3625 {
3626 int error=errno;
3627
3628 std::string out=std::string("ABORTED: server=")+mPortName
3629 +std::string(" alias=")+strAlias
3630 +std::string(" cmd=")+strCmd
3631 +std::string("\nCan't execute command because ")+strerror(error)
3632 +std::string("\n");
3633
3634 FILE* out_to_parent=fdopen(pipe_child_to_parent[WRITE_TO_PIPE], "w");
3635 fprintf(out_to_parent, "%s", out.c_str());
3636 fflush(out_to_parent);
3637 fclose(out_to_parent);
3638
3639 if (saved_stderr >= 0)
3640 {
3641 REDIRECT_TO(STDERR_FILENO, saved_stderr);
3642 }
3643 fprintf(stderr, "%s", out.c_str());
3644 }
3645
3646 delete [] cmd_str;
3647 delete [] arg_str;
3648
3649 std::exit(ret);
3650 }
3651
3652 if (IS_PARENT_OF(pid_cmd))
3653 {
3654 auto* pInf = new YarpRunProcInfo(strAlias, mPortName, pid_cmd, nullptr, false);
3655 pInf->setCmd(strCmd);
3656 if (msg.check("env")) {
3657 pInf->setEnv(msg.find("env").asString());
3658 }
3659 mProcessVector->Add(pInf);
3660 char pidstr[16];
3661 sprintf(pidstr, "%d", pid_cmd);
3662
3664
3665 FILE* in_from_child=fdopen(pipe_child_to_parent[READ_FROM_PIPE], "r");
3666 int flags=fcntl(pipe_child_to_parent[READ_FROM_PIPE], F_GETFL, 0);
3667 fcntl(pipe_child_to_parent[READ_FROM_PIPE], F_SETFL, flags|O_NONBLOCK);
3668
3669 std::string out;
3670
3671 if (in_from_child)
3672 {
3673 char buff[1024];
3674
3675 while(true)
3676 {
3677 if (!fgets(buff, 1024, in_from_child) || ferror(in_from_child) || feof(in_from_child)) {
3678 break;
3679 }
3680
3681 out+=std::string(buff);
3682 }
3683
3684 fclose(in_from_child);
3685 }
3686
3687 if (out.length()>0)
3688 {
3689 pid_cmd=YARPRUN_ERROR;
3690 }
3691 else
3692 {
3693 out=std::string("STARTED: server=")+mPortName
3694 +std::string(" alias=")+strAlias
3695 +std::string(" cmd=")+strCmd
3696 +std::string(" pid=")+int2String(pid_cmd)
3697 +std::string("\n");
3698 }
3699
3700 fprintf(stderr, "%s", out.c_str());
3701
3702 result.addInt32(pid_cmd);
3703 result.addString(out.c_str());
3704
3705 CLOSE(pipe_child_to_parent[READ_FROM_PIPE]);
3706 CLOSE(pipe_child_to_parent[WRITE_TO_PIPE]);
3707
3708 return pid_cmd;
3709 }
3710
3711 result.addInt32(YARPRUN_ERROR);
3712
3713 return YARPRUN_ERROR;
3714}
3715
3716#endif
3717
3719// API
3721
3722int yarp::run::Run::start(const std::string &node, yarp::os::Property &command, std::string &keyv)
3723{
3724 yarp::os::Bottle msg, grp, response;
3725
3726 grp.clear();
3727 grp.addString("on");
3728 grp.addString(node.c_str());
3729 msg.addList()=grp;
3730
3731 std::string dest_srv=node;
3732
3733 if (command.check("stdio"))
3734 {
3735 dest_srv=std::string(command.find("stdio").asString());
3736
3737 grp.clear();
3738 grp.addString("stdio");
3739 grp.addString(dest_srv.c_str());
3740 msg.addList()=grp;
3741
3742 if (command.check("geometry"))
3743 {
3744 grp.clear();
3745 grp.addString("geometry");
3746 grp.addString(command.find("geometry").asString().c_str());
3747 msg.addList()=grp;
3748 }
3749
3750 if (command.check("hold"))
3751 {
3752 grp.clear();
3753 grp.addString("hold");
3754 msg.addList()=grp;
3755 }
3756 }
3757
3758 grp.clear();
3759 grp.addString("as");
3760 grp.addString(keyv.c_str());
3761 msg.addList()=grp;
3762
3763 grp.clear();
3764 grp.addString("cmd");
3765 grp.addString(command.find("name").asString().c_str());
3766 grp.addString(command.find("parameters").asString().c_str());
3767 msg.addList()=grp;
3768
3769 printf(":: %s\n", msg.toString().c_str());
3770
3771 response=sendMsg(msg, dest_srv);
3772
3773 char buff[16];
3774 sprintf(buff, "%d", response.get(0).asInt32());
3775 keyv=std::string(buff);
3776
3777 return response.get(0).asInt32()>0?0:YARPRUN_ERROR;
3778}
3779
3780int yarp::run::Run::sigterm(const std::string &node, const std::string &keyv)
3781{
3782 yarp::os::Bottle msg, grp, response;
3783
3784 grp.clear();
3785 grp.addString("on");
3786 grp.addString(node.c_str());
3787 msg.addList()=grp;
3788
3789 grp.clear();
3790 grp.addString("sigterm");
3791 grp.addString(keyv.c_str());
3792 msg.addList()=grp;
3793
3794 printf(":: %s\n", msg.toString().c_str());
3795
3796 response=sendMsg(msg, node);
3797
3798 return response.get(0).asString()=="sigterm OK"?0:YARPRUN_ERROR;
3799}
3800
3801int yarp::run::Run::sigterm(const std::string &node)
3802{
3803 yarp::os::Bottle msg, grp, response;
3804
3805 grp.clear();
3806 grp.addString("on");
3807 grp.addString(node.c_str());
3808 msg.addList()=grp;
3809
3810 grp.clear();
3811 grp.addString("sigtermall");
3812 msg.addList()=grp;
3813
3814 printf(":: %s\n", msg.toString().c_str());
3815
3816 response=sendMsg(msg, node);
3817
3818 return response.get(0).asString()=="sigtermall OK"?0:YARPRUN_ERROR;
3819}
3820
3821int yarp::run::Run::kill(const std::string &node, const std::string &keyv, int s)
3822{
3823 yarp::os::Bottle msg, grp, response;
3824
3825 grp.clear();
3826 grp.addString("on");
3827 grp.addString(node.c_str());
3828 msg.addList()=grp;
3829
3830 grp.clear();
3831 grp.addString("kill");
3832 grp.addString(keyv.c_str());
3833 grp.addInt32(s);
3834 msg.addList()=grp;
3835
3836 printf(":: %s\n", msg.toString().c_str());
3837
3838 response=sendMsg(msg, node);
3839
3840 return response.get(0).asString()=="kill OK"?0:YARPRUN_ERROR;
3841}
3842
3843bool yarp::run::Run::isRunning(const std::string &node, std::string &keyv)
3844{
3845 yarp::os::Bottle msg, grp, response;
3846
3847 grp.clear();
3848 grp.addString("on");
3849 grp.addString(node.c_str());
3850 msg.addList()=grp;
3851
3852 grp.clear();
3853 grp.addString("isrunning");
3854 grp.addString(keyv.c_str());
3855 msg.addList()=grp;
3856
3857 printf(":: %s\n", msg.toString().c_str());
3858
3859 response=sendMsg(msg, node);
3860
3861 if (!response.size()) {
3862 return false;
3863 }
3864
3865 return response.get(0).asString()=="running";
3866}
3867
3868// end API
std::string toString(const T &value)
convert an arbitrary type to string.
bool ret
#define yInfo(...)
Definition Log.h:319
#define yError(...)
Definition Log.h:361
#define RUNLOG(msg)
int SIGNAL(int pid, int signum)
int CLOSE(int h)
#define YARPRUN_ERROR
std::string int2String(int x)
static yarp::os::Bottle parsePaths(const std::string &txt)
Definition Run.cpp:101
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 sigchld_handler(int)
An error handler that reaps the zombies.
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:353
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:293
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:361
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
A mini-server for performing network communication in the background.
Preferences for how to communicate with a contact.
bool persistent
Specify whether a requested connection should be persistent.
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:1370
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.
std::string toString() const override
Return a standard text representation of the content of the object.
void put(const std::string &key, const std::string &value)
Associate the given key with the given string.
Definition Property.cpp:987
bool check(const std::string &key) const override
Check if there exists a property of the given name.
Bottle & findGroup(const std::string &key) const override
Gets a list corresponding to a given keyword.
void unput(const std::string &key)
Remove the association from the given key to a value, if present.
void fromCommand(int argc, char *argv[], bool skipFirst=true, bool wipe=true)
Interprets a list of command arguments as a list of properties.
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)
A helper class to pass the SystemInfo object around the YARP network.
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.
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:3821
static int start(const std::string &node, yarp::os::Property &command, std::string &keyv)
Launch a yarprun server.
Definition Run.cpp:3722
static bool isRunning(const std::string &node, std::string &keyv)
Get a report of all applications running on a yarprun server.
Definition Run.cpp:3843
static int sigterm(const std::string &node, const std::string &keyv)
Terminate an application running on a yarprun server.
Definition Run.cpp:3780
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
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.
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:137
char * getcwd(char *buf, size_t size)
Portable wrapper for the getcwd() function.
Definition Os.cpp:105
int getpid()
Portable wrapper for the getppid() function.
Definition Os.cpp:84
bool read(ImageOf< PixelRgb > &dest, const std::string &src, image_fileformat format=FORMAT_ANY)
bool write(const ImageOf< PixelRgb > &src, const std::string &dest, image_fileformat format=FORMAT_PPM)
The main, catch-all namespace for YARP.
Definition dirs.h:16
#define YARP_UNUSED(var)
Definition api.h:162