I have a simple C/CPP process running on a linux system. This is a.out.
Another process is capable to start a.out inside its code. This is b.out.
What code do I need inside a.out to understand that it is executed from the command line?
Eg ./a.out
Is there a way a process to know if it started from the cmd or started from another process?
You can't find out in general whether a program was started "from the command line" (by a user's explicit command), but you can find out whether its standard input and output are talking to a terminal/command window:
#include <unistd.h>
isatty(fileno(stdin))
and stdout return whether standard input/standard output are terminals.
If you need to know what process starting your program, use the getppid system call to get the parent's process ID (ppid), then read the pseudo-file /proc/ppid/cmdline.
You can check its parent task ID, using getppid()
You can do multiple things, but none will be 100% reliable:
isatty(0) to check whether standard input is a TTY terminal,
check for the parent task ID (getppid()), then lookup the parent's PID to match it against its executable's path (using whatever you want. a call to ps and some parsing could do, or have fun using /proc/)
you could also just have a look at the environment variables set up. do a printout of all the values contained in the env. To do that, either use the extern environ variable:
extern char **environ;
or modify your main() prototype to be:
int main(int ac, char **av, char **environ)
I would set an environment variable, in the parent process, to some value (say the parent pid), and have the child process check for it.
It is unlikely that a shell user would set this variable (call it something unlikely to name-clash), so if this variable is set to the expected value, then you know that it is being started from the parent process.
You can check whether its standard input is a terminal:
if(isatty(0)) { ... }
In short: you can't doing it directly.
In long: look you can check the getppid() value and compare it with the bash PID orb.out PID
TO search for a process inside the process table with Known PID with C you can do this:
1) get the PPID of a.out and search with this value in /porc and then if you find the folder check the cmdline file and check if this process is b.out or shell process.
2) you can deal with sysctl system call and dealing with kernel param's(you can google it)
3)
pid_t ppid = getppid();
system("pidof bash > text.in");
the system will get the pid of any shell process and write the result to text.in file
it contains all bash PID's space separated you can compare this values with getppid() value.
Good Luck.
Related
A post in this (Are system() calls evil?) thread says:
Your program's privileges are inherited by its spawned programs. If your application ever runs as a privileged user, all someone has to do is put their own program with the name of the thing you shell out too, and then can execute arbitrary code (this implies you should never run a program that uses system as root or setuid root).
But system("PAUSE") and system("CLS") shell to the OS, so how could a hacker possibly intervene if it ONLY shells to a specific secure location on the hard-drive?
Does explicitly flush—by using fflush or _flushall—or closing any stream before calling system eliminate all risk?
The system function passes command to the command interpreter, which executes the string as an operating-system command. system uses the COMSPEC and PATH environment variables to locate the command-interpreter file CMD.exe. If command is NULL, the function just checks whether the command interpreter exists.
You must explicitly flush—by using fflush or _flushall—or close any stream before you call system.
https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/system-wsystem
In case, there are any doubts here's the actual snippet from the MS' implementation (very simple and straightforward):
// omitted for brevity
argv[1] = _T("/c");
argv[2] = (_TSCHAR *) command;
argv[3] = NULL;
/* If there is a COMSPEC defined, try spawning the shell */
/* Do not try to spawn the null string */
if (argv[0])
{
// calls spawnve on value of COMSPEC vairable, if present
// omitted for brevity
}
/* No COMSPEC so set argv[0] to what COMSPEC should be. */
argv[0] = _T("cmd.exe");
/* Let the _spawnvpe routine do the path search and spawn. */
retval = (int)_tspawnvpe(_P_WAIT,argv[0],argv,NULL);
// clean-up part omitted
As to concerns of what _tspawnvpe may actually be doing, the answer is: nothing magical. The exact invocation sequence for spawnvpe and friends goes as following (as anybody with licensed version of MSVC can easily learn by inspecting the spanwnvpe.c source file):
Do some sanity checks on parameters
Try to invoke _tspawnve on the passed file name. spawnve will succeed if the file name represents an absolute path to an executable or a valid path relative to the current working directory. No further checks are done - so yes, if a file named cmd.exe exists in current directory it will be invoked first in the context of system() call discussed.
In a loop: obtain the next path element using `_getpath()
Append the file name to the path element
Pass the resulted path to spwanvpe, check if it was successful
That's it. No special tricks/checks involved.
The original question references POSIX not windows. Here there is no COMSPEC (there is SHELL but system() deliberately does not use it); however /bin/sh is completely, utterly vulnerable.
Suppose /opt/vuln/program does system("/bin/ls"); Looks completely harmless, right? Nope!
$ PATH=. IFS='/ ' /opt/vuln/program
This runs the program called bin in the current directory. Oops. Defending against this kind of thing is so difficult it should be left to the extreme experts, like the guys who wrote sudo. Sanitizing environment is extremely hard.
So you might be thinking what is that system() api for. I don't actually know why it was created, but if you wanted to do a feature like ftp has where !command is executed locally in the shell you could do ... else if (terminalline[0] == '!') system(terminalline+1); else ... Since it's going to be completely insecure anyway there's no point in making it secure. Of course a truly modern use case wouldn't do it that way because system() doesn't look at $SHELL but oh well.
I have a program that calls a shell script tool that I made that goes through a directory and zips up files and gets the checksum value and calls some other tools to upload the files. The operation takes roughly 3 to 4 minutes.
I call the script like this:
int result = system("/bin/sh /path/to/my/script");
I've also got the same result by using the exec() family of functions:
int child = fork();
if(child == 0) {
execl( "/bin/sh", "sh", "/path/to/my/script", (char*)0 );
}
I know with exec you can redirect output to the parent program so it can read the output of the command line tools, but other than that when should you use system as opposed to exec?
Ignoring for the time being that use of system is portable while use of exec family of functions is not portable...
When you combine use of exec family of functions with other POSIX functions such as pipe, dup, wait, you get a lot more control over how to pass data between the parent process and the child process.
When you don't need any of those controls, i.e. you just want to execute a command, then using system is preferable, IMO.
The first system call in your question will do the same, what you are doing in the next piece of code (fork and execl)
From documentation:
The system() library function uses fork(2) to create a child process
that executes the shell command specified in command using execl(3)
http://man7.org/linux/man-pages/man3/system.3.html
I wrote a c++ program to check if a process is running or not . this process is independently launched at background . my program works fine when I run it on foreground but when I time schedule it, it do not work .
int PID= ReadCommanOutput("pidof /root/test/testProg1"); /// also tested with pidof -m
I made a script in /etc/cron.d/myscript to time schedule it as follows :-
45 15 * * * root /root/ProgramMonitor/./testBkg > /root/ProgramMonitor/OutPut.txt
what could be the reason for this ?
string ReadCommanOutput(string command)
{
string output="";
int its=system((command+" > /root/ProgramMonitor/macinfo.txt").c_str());
if(its==0)
{
ifstream reader1("/root/ProgramMonitor/macinfo.txt",fstream::in);
if(!reader1.fail())
{
while(!reader1.eof())
{
string line;
getline(reader1,line);
if(reader1.fail())// for last read
break;
if(!line.empty())
{
stringstream ss(line.c_str());
ss>>output;
cout<<command<<" output = ["<<output<<"]"<<endl;
break;
}
}
reader1.close();
remove("/root/ProgramMonitor/macinfo.txt");
}
else
cout<<"/root/ProgramMonitor/macinfo.txt not found !"<<endl;
}
else
cout<<"ERROR: code = "<<its<<endl;
return output;
}
its output coming as "ERROR: code = 256"
thanks in advacee .
If you really wanted to pipe(2), fork(2), execve(2) then read the output of a pidof command, you should at least use popen(3) since ReadCommandOutput is not in the Posix API; at the very least
pid_t thepid = 0;
FILE* fpidof = popen("pidof /root/test/testProg1");
if (fpidof) {
int p=0;
if (fscanf(fpidof, "%d", &p)>0 && p>0)
thepid = (pid_t)p;
pclose(fpidof);
}
BTW, you did not specify what should happen if several processes (or none) are running the testProg1....; you also need to check the result of pclose
But you don't need to; actually you'll want to build, perhaps using snprintf, the pidof command (and you should be scared of code injection into that command, so quote arguments appropriately). You could simply find your command by accessing the proc(5) file system: you would opendir(3) on "/proc/", then loop on readdir(3) and for every entry which has a numerical name like 1234 (starts with a digit) readlink(2) its exe entry like e.g. /proc/1234/exe ...). Don't forget the closedir and test every syscall.
Please read Advanced Linux Programming
Notice that libraries like Poco or toolkits like Qt (which has a layer QCore without any GUI, and providing QProcess ....) could be useful to you.
As to why your pidof is failing, we can't guess (perhaps a permission issue, or perhaps there is no more any process like you want). Try to run it as root in another terminal at least. Test its exit code, and display both its stdout & stderr at least for debugging purposes.
Also, a better way (assuming that testProg1 is some kind of a server application, to be run in at most one single process) might be to define different conventions. Your testProg1 might start by writing its own pid into /var/run/testProg1.pid and your current application might then read the pid from that file and check, with kill(2) and a 0 signal number, that the process is still existing.
BTW, you could also improve your crontab(5) entry. You could make it run some shell script which uses logger(1) and (for debugging) runs pidof with its output redirected elsewhere. You might also read the mail perhaps sent to root by cron.
Finally I solved this problem by using su command
I have used
ReadCommanOutput("su -c 'pidof /root/test/testProg1' - root");
insteadof
ReadCommanOutput("pidof /root/test/testProg1");
What is the best way to prevent a Linux program/daemon from being executed more than once at a given time?
The most common way is to create a PID file: define a location where the file will go (inside /var/run is common). On successful startup, you'll write your PID to this file. When deciding whether to start up, read the file and check to make sure that the referenced process doesn't exist (or if it does, that it's not an instance of your daemon: on Linux, you can look at /proc/$PID/exe). On shutdown, you may remove the file but it's not strictly necessary.
There are scripts to help you do this, you may find start-stop-daemon to be useful: it can use PID files or even just check globally for the existence of an executable. It's designed precisely for this task and was written to help people get it right.
Use the boost interprocess library to create a memory block that will be created by the process. If it already exists, it means that there is another instance of the process. Exit.
The more precise link to what you need would be this one.
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/scoped_ptr.hpp>
int main()
{
using boost::interprocess;
boost::scoped_ptr<shared_memory_object> createSharedMemoryOrDie;
try
{
createSharedMemoryOrDie.reset(
new shared_memory_object(create_only, "shared_memory", read_write));
} catch(...)
{
// executable is already running
return 1;
}
// do your thing here
}
If you have access to the code (i.e. are writing it):
create a temporary file, lock it, remove when done, return 1; if file exists, or,
list processes, return 1; if the process name is in the list
If you don't:
create a launcher wrapper to the program that does one of the above
I do not know what your exact requirement is but I had a similar requirement; in that case I started my daemon from a Shell script ( it was a HP-UX machine) and before starting the daemon I checked if an exec by same name is already running. If it is; then don't start a new one.
By this way I was also able control the number of instances of a process.
I think this scheme should work (and is also robust against crashes):
Precondition: There is a PID file for your application (typically in /var/run/)
1. Try to open the PID file
2. If it does not exist, create it and write your PID to it. Continue with the rest of the program
3. If it exist, read the PID
4. If the PID is still running and is an instance of your program, then exit
5. If the PID does not exist or is used by another program, remove the PID file and go to step 2.
6. At program termination, remove the PID file.
The loop in step 5 ensures that, if two instances are started at the same time, only one will be running in the end.
Have a pid file and on the startup do a 'kill -0 <pid>'. Where is the value read from file. If the response is != 0 then the daemon is not alive and you might restart it
Another approach would be to bind to a port and handle the bind exception on the second attempt to start the daemon. If the port is in use then exit otherwise continue running the daemon.
I believe my solution is the simplest:
(don't use it if racing condition is a possible scenario, but on any other case this is a simple and satisfying solution)
#include <sys/types.h>
#include <unistd.h>
#include <sstream>
void main()
{
// get this process pid
pid_t pid = getpid();
// compose a bash command that:
// check if another process with the same name as yours
// but with different pid is running
std::stringstream command;
command << "ps -eo pid,comm | grep <process name> | grep -v " << pid;
int isRuning = system(command.str().c_str());
if (isRuning == 0) {
cout << "Another process already running. exiting." << endl;
return 1;
}
return 0;
}
I've got a GUI C++ program that takes a shell command from the user, calls forkpty() and execvp() to execute that command in a child process, while the parent (GUI) process reads the child process's stdout/stderr output and displays it in the GUI.
This all works nicely (under Linux and MacOS/X). For example, if the user enters "ls -l /foo", the GUI will display the contents of the /foo folder.
However, bash niceties like output redirection aren't handled. For example, if the user enters "echo bar > /foo/bar.txt", the child process will output the text "bar > /foo/bar.txt", instead of writing the text "bar" to the file "/foo/bar.txt".
Presumably this is because execvp() is running the executable command "echo" directly, instead of running /bin/bash and handing it the user's command to massage/preprocess.
My question is, what is the correct child process invocation to use, in order to make the system behave exactly as if the user had typed in his string at the bash prompt? I tried wrapping the user's command with a /bin/bash invocation, like this: /bin/bash -c the_string_the_user_entered, but that didn't seem to work. Any hints?
ps Just calling system() isn't a good option, since it would cause my GUI to block until the child process exits, and some child processes may not exit for a long time (if ever!)
If you want the shell to do the I/O redirection, you need to invoke the shell so it does the I/O redirection.
char *args[4];
args[0] = "bash";
args[1] = "-c";
args[2] = ...string containing command line with I/O redirection...;
args[4] = 0;
execv("/bin/bash", args);
Note the change from execvp() to execv(); you know where the shell is - at least, I gave it an absolute path - so the path-search is not relevant any more.