I want to get the exit status of a pipe in C++, both on Linux and on Windows, to check whether a command ran successfully.
On Linux (or POSIX more generally), it appears that the macros in <sys/wait.h> are needed to get the correct exit status, such as in the first answer to the question
Does pclose() return pipe's termination status shifted left by eight bits on all platforms?
#include <cstdio>
#include <iostream>
#ifdef _WIN32
#define popen _popen
#define pclose _pclose
#else
#include <sys/wait.h>
#endif
int main(){
FILE* pipe {nullptr};
pipe = popen( "echo 123", "r" );
int status {0};
status = pclose(pipe);
#ifndef _WIN32
/* ask how the process ended to clean up the exit code. */
if ( WIFEXITED(status) ){
/* Add code here if needed after pipe exited normally */
status = WEXITSTATUS(status);
} else if ( WIFSIGNALED(status) ){
/* Add code here if needed after pipe process was terminated */
status = WTERMSIG(status);
} else if ( WIFSTOPPED(status) ){
/* Add code here if needed after pipe stopped */
status = WSTOPSIG(status);
}
#else
/* but what about windows? */
#endif
std::cout << "Exit status: " << status << '\n';
return 0;
}
I couldn't find anything about Windows though. The C runtime lib reference for _pclose includes a remark about _cwait and states that
"The format of the return value [of _pclose] is the same as for _cwait, except the low-order and high-order bytes are swapped".
So how do I get the correct exit status on Windows?
Related
Given single string cmd representing program command line arguments, how to get array of strings argv, that can be passed to posix_spawn or execve.
Various forms of quoting (and escaping quotes) should be processed appropriately (resulting invocation should be same as in POSIX-compatible shell). Support for other escape characters would be desirable. Examples: #1, #2, #3.
As Shawn commented, in Linux and other POSIXy systems, you can use wordexp(), which is provided as part of the standard C library on such systems. For example, run.h:
#ifdef __cplusplus
extern "C" {
#endif
/* Execute binary 'bin' with arguments from string 'args';
'args' must not be NULL or empty.
Command substitution (`...` or $(...)$) is NOT performed.
If 'bin' is NULL or empty, the first token in 'args' is used.
Only returns if fails. Return value:
-1: error in execv()/execvp(); see errno.
-2: out of memory. errno==ENOMEM.
-3: NULL or empty args.
-4: args contains a command substitution. errno==EINVAL.
-5: args has an illegal newline or | & ; < > ( ) { }. errno==EINVAL.
-6: shell syntax error. errno==EINVAL.
In all cases, you can use strerror(errno) for a descriptive string.
*/
int run(const char *bin, const char *args);
#ifdef __cplusplus
}
#endif
and compile the following C source to an object file you link into your C or C++ program or library:
#define _XOPEN_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <wordexp.h>
#include <string.h>
#include <errno.h>
int run(const char *bin, const char *args)
{
/* Empty or NULL args is an invalid parameter. */
if (!args || !*args) {
errno = EINVAL;
return -3;
}
wordexp_t w;
switch (wordexp(args, &w, WRDE_NOCMD)) {
case 0: break; /* No error */
case WRDE_NOSPACE: errno = ENOMEM; return -2;
case WRDE_CMDSUB: errno = EINVAL; return -4;
case WRDE_BADCHAR: errno = EINVAL; return -5;
default: errno = EINVAL; return -6;
}
if (w.we_wordc < 1) {
errno = EINVAL;
return -3;
}
if (!bin || !*bin)
bin = w.we_wordv[0];
if (!bin || !*bin) {
errno = ENOENT;
return -1;
}
/* Note: w.ve_wordv[w.we_wordc] == NULL, per POSIX. */
if (strchr(bin, '/'))
execv(bin, w.we_wordv);
else
execvp(bin, w.we_wordv);
return -1;
}
For example, run(NULL, "ls -laF $HOME"); will list the contents of the current user's home directory. Environment variables will be expanded.
run("bash", "sh -c 'date && echo'"); executes bash, with argv[0]=="sh", argv[1]=="-c", and argv[2]=="date && echo". This lets you control what binary will be executed.
I am trying to run a C/C++ application on MINIX3 which is supposed to send a messages between two processes using msgsnd() and msgget() using msg.h.
This is the error I am getting:
send.cpp:(.text+0x7f): undefined reference to `msgget'
send.cpp:(.text+0x1c1): undefined reference to `msgsnd'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I am using clang++ to compile the code:
clang++ send.cpp -o send.out
This is the send.cpp code:
#include <lib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MSGSZ 128
/*
* Declare the message structure.
*/
typedef struct msgbufer {
long mtype;
char mtext[MSGSZ];
} message_buf;
int main()
{
int msqid;
int msgflg = IPC_CREAT | 0666;
key_t key;
message_buf sbuf;
size_t buf_length;
/*
* Get the message queue id for the
* "name" 1234, which was created by
* the server.
*/
key = 1234;
(void)fprintf(stderr, "\nmsgget: Calling msgget(%i,\
%#o)\n",
key, msgflg);
if ((msqid = msgget(key, msgflg)) < 0) {
perror("msgget");
exit(1);
}
else
(void)fprintf(stderr, "msgget: msgget succeeded: msqid = %d\n", msqid);
/*
* We'll send message type 1
*/
sbuf.mtype = 1;
(void)fprintf(stderr, "msgget: msgget succeeded: msqid = %d\n", msqid);
(void)strcpy(sbuf.mtext, "Hello other process 2.");
(void)fprintf(stderr, "msgget: msgget succeeded: msqid = %d\n", msqid);
buf_length = strlen(sbuf.mtext) + 1;
/*
* Send a message.
*/
if (msgsnd(msqid, &sbuf, buf_length, IPC_NOWAIT) < 0) {
printf("%d, %li, %s, %lu\n", msqid, sbuf.mtype, sbuf.mtext, buf_length);
perror("msgsnd");
exit(1);
}
else
printf("Message: \"%s\" Sent\n", sbuf.mtext);
exit(0);
}
You aren't linking with the library that contains the msgsnd and msgget functions, so your linker step fails. I'm not familiar with Minix so I'm not sure where the library is stored or what it is called. Basically, you need to a -l<msg> flag to your linking step. Where <msg> is the name of the library that contains the implementation.
(Context) I'm developing a cross-platform (Windows and Linux) application for distributing files among computers, based on BitTorrent Sync. I've made it in C# already, and am now porting to C++ as an exercise.
BTSync can be started in API mode, and for such, one must start the 'btsync' executable passing the name and location of a config file as arguments.
At this point, my greatest problem is getting my application to deal with the executable. I've come to found Boost.Process when searching for a cross-platform process management library, and decided to give it a try. It seems that v0.5 is it's latest working release, as some evidence suggests, and it can be infered there's a number of people using it.
I implemented the library as follows (relevant code only):
File: test.hpp
namespace testingBoostProcess
{
class Test
{
void StartSyncing();
};
}
File: Test.cpp
#include <string>
#include <vector>
#include <iostream>
#include <boost/process.hpp>
#include <boost/process/mitigate.hpp>
#include "test.hpp"
using namespace std;
using namespace testingBoostProcess;
namespace bpr = ::boost::process;
#ifdef _WIN32
const vector<wstring> EXE_NAME_ARGS = { L"btsync.exe", L"/config", L"conf.json" };
#else
const vector<string> EXE_NAME_ARGS = { "btsync", "--config", "conf.json" };
#endif
void Test::StartSyncing()
{
cout << "Starting Server...";
try
{
bpr::child exeServer = bpr::execute(bpr::initializers::set_args(EXE_NAME_ARGS),
bpr::initializers::throw_on_error(), bpr::initializers::inherit_env());
auto exitStatus = bpr::wait_for_exit(exeServer); // type will be either DWORD or int
int exitCode = BOOST_PROCESS_EXITSTATUS(exitStatus);
cout << " ok" << "\tstatus: " << exitCode << "\n";
}
catch (const exception& excStartExeServer)
{
cout << "\n" << "Error: " << excStartExeServer.what() << "\n";
}
}
(Problem) On Windows, the above code will start btsync and wait (block) until the process is terminated (either by using Task Manager or by the API's shutdown method), just like desired.
But on Linux, it finishes execution immediately after starting the process, as if wait_for_exit() isn't there at all, though the btsync process isn't terminated.
In an attempt to see if that has something to do with the btsync executable itself, I replaced it by this simple program:
File: Fake-Btsync.cpp
#include <cstdio>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define SLEEP Sleep(20000)
#include <Windows.h>
#else
#include <unistd.h>
#define SLEEP sleep(20)
#endif
using namespace std;
int main(int argc, char* argv[])
{
for (int i = 0; i < argc; i++)
{
printf(argv[i]);
printf("\n");
}
SLEEP;
return 0;
}
When used with this program, instead of the original btsync downloaded from the official website, my application works as desired. It will block for 20 seconds and then exit.
Question: What is the reason for the described behavior? The only thing I can think of is that btsync restarts itself on Linux. But how to confirm that? Or what else could it be?
Update: All I needed to do was to know about what forking is and how it works, as pointed in sehe's answer (thanks!).
Question 2: If I use the System Monitor to send an End command to the child process 'Fake-Btsync' while my main application is blocked, wait_for_exit() will throw an exception saying:
waitpid(2) failed: No child processes
Which is a different behavior than on Windows, where it simply says "ok" and terminates with status 0.
Update 2: sehe's answer is great, but didn't quite address Question 2 in a way I could actually understand. I'll write a new question about that and post the link here.
The problem is your assumption about btsync. Let's start it:
./btsync
By using this application, you agree to our Privacy Policy, Terms of Use and End User License Agreement.
http://www.bittorrent.com/legal/privacy
http://www.bittorrent.com/legal/terms-of-use
http://www.bittorrent.com/legal/eula
BitTorrent Sync forked to background. pid = 24325. default port = 8888
So, that's the whole story right there: BitTorrent Sync forked to background. Nothing more. Nothing less. If you want to, btsync --help tells you to pass --nodaemon.
Testing Process Termination
Let's pass --nodaemon run btsync using the test program. In a separate subshell, let's kill the child btsync process after 5 seconds:
sehe#desktop:/tmp$ (./test; echo exit code $?) & (sleep 5; killall btsync)& time wait
[1] 24553
[2] 24554
By using this application, you agree to our Privacy Policy, Terms of Use and End User License Agreement.
http://www.bittorrent.com/legal/privacy
http://www.bittorrent.com/legal/terms-of-use
http://www.bittorrent.com/legal/eula
[20141029 10:51:16.344] total physical memory 536870912 max disk cache 2097152
[20141029 10:51:16.344] Using IP address 192.168.2.136
[20141029 10:51:16.346] Loading config file version 1.4.93
[20141029 10:51:17.389] UPnP: Device error "http://192.168.2.1:49000/l2tpv3.xml": (-2)
[20141029 10:51:17.407] UPnP: ERROR mapping TCP port 43564 -> 192.168.2.136:43564. Deleting mapping and trying again: (403) Unknown result code (UPnP protocol violation?)
[20141029 10:51:17.415] UPnP: ERROR removing TCP port 43564: (403) Unknown result code (UPnP protocol violation?)
[20141029 10:51:17.423] UPnP: ERROR mapping TCP port 43564 -> 192.168.2.136:43564: (403) Unknown result code (UPnP protocol violation?)
[20141029 10:51:21.428] Received shutdown request via signal 15
[20141029 10:51:21.428] Shutdown. Saving config sync.dat
Starting Server... ok status: 0
exit code 0
[1]- Done ( ./test; echo exit code $? )
[2]+ Done ( sleep 5; killall btsync )
real 0m6.093s
user 0m0.003s
sys 0m0.026s
No problem!
A Better Fake Btsync
This should still be portable and be (much) better behaved when killed/terminated/interrupted:
#include <boost/asio/signal_set.hpp>
#include <boost/asio.hpp>
#include <iostream>
int main(int argc, char* argv[])
{
boost::asio::io_service is;
boost::asio::signal_set ss(is);
boost::asio::deadline_timer timer(is, boost::posix_time::seconds(20));
ss.add(SIGINT);
ss.add(SIGTERM);
auto stop = [&]{
ss.cancel(); // one of these will be redundant
timer.cancel();
};
ss.async_wait([=](boost::system::error_code ec, int sig){
std::cout << "Signal received: " << sig << " (ec: '" << ec.message() << "')\n";
stop();
});
timer.async_wait([&](boost::system::error_code ec){
std::cout << "Timer: '" << ec.message() << "'\n";
stop();
});
std::copy(argv, argv+argc, std::ostream_iterator<std::string>(std::cout, "\n"));
is.run();
return 0;
}
You can test whether it is well-behaved
(./btsync --nodaemon; echo exit code $?) & (sleep 5; killall btsync)& time wait
The same test can be run with "official" btsync and "fake" btsync. Output on my linux box:
sehe#desktop:/tmp$ (./btsync --nodaemon; echo exit code $?) & (sleep 5; killall btsync)& time wait
[1] 24654
[2] 24655
./btsync
--nodaemon
Signal received: 15 (ec: 'Success')
Timer: 'Operation canceled'
exit code 0
[1]- Done ( ./btsync --nodaemon; echo exit code $? )
[2]+ Done ( sleep 5; killall btsync )
real 0m5.014s
user 0m0.001s
sys 0m0.014s
How can I retrieve a process's fully-qualified path from its PID using C++ on Windows?
Call OpenProcess to get a handle to the process associated with your PID. Once you have a handle to the process, call GetModuleFileNameEx to get its fully-qualified path. Don't forget to call CloseHandle when you're finished using the process handle.
Here's a sample program that performs the required calls (replace 1234 with your PID):
#include <windows.h>
#include <psapi.h> // For access to GetModuleFileNameEx
#include <tchar.h>
#include <iostream>
using namespace std;
#ifdef _UNICODE
#define tcout wcout
#define tcerr wcerr
#else
#define tcout cout
#define tcerr cerr
#endif
int _tmain(int argc, TCHAR * argv[])
{
HANDLE processHandle = NULL;
TCHAR filename[MAX_PATH];
processHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, 1234);
if (processHandle != NULL) {
if (GetModuleFileNameEx(processHandle, NULL, filename, MAX_PATH) == 0) {
tcerr << "Failed to get module filename." << endl;
} else {
tcout << "Module filename is: " << filename << endl;
}
CloseHandle(processHandle);
} else {
tcerr << "Failed to open process." << endl;
}
return 0;
}
Some notes to Emerick Rogul's solution:
Don't forget to add 'psapi.lib' to linker (additional dependencies).
I also changed PROCESS_ALL_ACCESS to PROCESS_QUERY_INFORMATION | PROCESS_VM_READ because I got:
Failed to open process.
If it's compiled as a 32 bit application it will fail to get the name of 64 bit processes ("Failed to get module filename.")
I didn't have very much luck with GetModuleFileNameEx and QueryFullProcessImageName is only available on Vista or higher. I was however able to get the path for a process by using GetProcessImageFilename. It returns the windows kernel path but you can use QueryDosDevice to compare the device path returned by GetProcessImageFilename with its proper drive path.
This page shows how to normalize an windows kernel path returned by GetProcessImageFilename (see NormalizeNTPath function):
http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/c48bcfb3-5326-479b-8c95-81dc742292ab/
Have you tried QueryFullProcessImageName?
Sometimes GetModuleFileNameEx returns the 299 error code (I don't know why)
The only method that works for all versions of Windows, including XP is in Nathan Moinvaziri answer:
check the provided url:
Windows API to Get a Full Process Path
I have an application where I need to write a new getpid function to replace the original one of the OS. The implementation would be similar to:
pid_t getpid(void)
{
if (gi_PID != -1)
{
return gi_PID;
}
else
{
// OS level getpid() function
}
}
How can I call the original getpid() implementation of the OS through this function?
EDIT: I tried:
pid_t getpid(void)
{
if (gi_PID != -1)
{
return gi_PID;
}
else
{
return _getpid();
}
}
as Jonathan has suggested. This gave me the following errors when compiling with g++:
In function pid_t getpid()':
SerendibPlugin.cpp:882: error:
_getpid' undeclared (first use this
function) SerendibPlugin.cpp:882:
error: (Each undeclared identifier is
reported only once for each function
it appears in.)
EDIT 2: I've managed to get this to work by using a function pointer and setting it to the next second symbol with the id "getpid", using dlsym(RTLD_NEXT, "getpid").
Here's my sample code:
vi xx.c
"xx.c" 23 lines, 425 characters
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <iostream>
#include <dlfcn.h>
using namespace std;
pid_t(*___getpid)();
pid_t getpid(void)
{
cout << "My getpid" << endl;
cout << "PID :" << (*___getpid)() << endl;
return (*___getpid)();
}
int main(void)
{
___getpid = (pid_t(*)())dlsym(RTLD_NEXT, "getpid");
pid_t p1 = getpid();
printf("%d \n", (int)p1);
return(0);
}
g++ xx.c -o xout
My getpid
PID :7802
7802
On many systems, you will find that getpid() is a 'weak symbol' for _getpid(), which can be called in lieu of getpid().
The first version of the answer mentioned __getpid(); the mention was removed swiftly since it was erroneous.
This code works for me on Solaris 10 (SPARC) - with a C++ compiler:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
extern "C" pid_t _getpid();
pid_t getpid(void)
{
return(-1);
}
int main(void)
{
pid_t p1 = getpid();
pid_t p2 = _getpid();
printf("%d vs %d\n", (int)p1, (int)p2);
return(0);
}
This code works for me on Solaris 10 (SPARC) - with a C compiler:
Black JL: cat xx.c
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
pid_t getpid(void)
{
return(-1);
}
int main(void)
{
pid_t p1 = getpid();
pid_t p2 = _getpid();
printf("%d vs %d\n", (int)p1, (int)p2);
return(0);
}
Black JL: make xx && ./xx
cc xx.c -o xx
"xx.c", line 13: warning: implicit function declaration: _getpid
-1 vs 29808
Black JL:
You can use a macro:
in a .h, included in every file where you want to replace the getpid function
#define getpid() mygetpid()
Then, put your own implementation in a .cpp
pid_t mygetpid() {
// do what you want
return (getpid)();
}
You're using the terminology a bit incorrectly. It's not possible to override getpid() because it's not a virtual function. All you can do is attempt to replace getpid with a different function by various evil means.
But I must ask, why are you doing this? Replacing getpid means that any component which was depending on the return of getpid will now be receiving you're presumably modified result. This change has a very high risk of changing some other component.
What you're offering is a new functionality and hence should be a different function.
That being said if you truly want to take this approach the best way is to dynamic loading of the function. The original DLL will still contain the getpid function and you can access that via a combination of LoadLibrary/GetProcAddress on Windows or dlopen/dlsym on Linux. If you're using a different OS please specify.
EDIT Responding to comments that getpid needs to be testable
If testing is the concern then why not instead have a custom getpid method for you're application. For example, applicationGetPid(). For normal execution this could be forwarded off to the system getpid function. But during Unit Testing it could be used to produce more predictable values.
pid_t applicationGetPid() {
#if UNIT_TEST
return SomeCodeForUnitTests;
#else
return getpid();
#endif
}