How does execl deal with "/bin/sh" in Linux? - linux

I read about APUE 3rd, 8.13, system Function, and I saw a version of system function implementation without signal handling.Code is like below:
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h>
int system(const char *cmdstring) /* version without signal handling */
{
pid_t pid;
int status;
if (cmdstring == NULL)
return(1); /* always a command processor with UNIX */
if ((pid = fork()) < 0) {
status = -1; /* probably out of processes */
} else if (pid == 0) { /* child */
execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
_exit(127); /* execl error */
} else { /* parent */
while (waitpid(pid, &status, 0) < 0) {
if (errno != EINTR) {
status = -1; /* error other than EINTR from waitpid() */
break;
}
}
}
return(status);
}
And the code used to test system function of this version is like below:
int main(void)
{
int status;
if ((status = system("date")) < 0)
err_sys("system() error");
pr_exit(status);
if ((status = system("nosuchcommand")) < 0)
err_sys("system() error");
pr_exit(status);
if ((status = system("who; exit 44")) < 0)
err_sys("system() error");
pr_exit(status);
exit(0);
}
And the result of the test code is shown by the picture(just ignore the Chinese in the result if you can't understand):
I wonder why will execl return if "nosuchcommand", which is not valid for /bin/sh, is given to /bin/sh. In my point of view, execl just replace the code of current process and then run from entry point, even though "nosuchcommand" is not valid for /bin/sh, it has nothing to do with execl but /bin/sh. So, how execl know "nosuchcommand" is not valid for /bin/sh to execute and return? Does execl treat /bin/sh differently by checking the command given to /bin/sh before executing /bin/sh so that it will know the invalid argument given to /bin/sh in advance? I know execl won't treat /bin/sh differently, so, how does execl know "nosuchcommand" is not valid for /bin/sh to execute and return?

sh -c nosuchcommand itself returns 127. It's one of those return codes with a special meaning.
So I don't think you're seeing execl actually returning in this case.

It doesn't "know". It simply executes what you tell it to. /bin/sh then reports that it cannot find it, after which /bin/sh exits with non-zero exit code, in this case 127.
Also note that you cannot depend on it returning exactly 127 as that is shell-specific. Some shells (including /bin/sh on some OSes) will return 1 instead.

Related

How to execute a bash-skript from c without STDIN and STDOUT

I'm in the proccess of writing a deamon, which runs a shell-skript or any other executable upon a buzzer-press. Most of what I need works quite fine, but I'm facing a curious issue:
I do the call of the executable via execlp. And, when I do have STDIN and STDOUT open, this works just beautifully.
However, as this is supposed to be handled completely deamonized, thus in the background, I would like to run this without any console-interface. But, as soon as I close the standard interface identifiers, execlp does not work anymore.
I tried it with the snippet below: When it is run with a d as argument for debug, the identifiers will be kept open and it works. Otherwise, it does not. Thus, the question is: How to run an executable (by any means), without using STDIN and STDOUT.
Some remarks:
The call to execlp does not return. Which means, that the syslog-call is never done and which is as expected.
When leaving STDERR open, nothing comes up.
The script to be called returns with an error-code (consciously for debugging reasons).
When executing with file-handlers open, I do see the toggling of the pins and the wait-call returns the error-code of the sript.
When executing without the file-handlers, the wait call returns the exit-status success.
Note, that the c call to execlp does not return. Thus, inside this little programm, it looks like success.
Here is the c-code:
/** Global Includes: ****************************************************************/
#include <stdio.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <unistd.h>
#include <syslog.h>
#include <sys/wait.h>
/** Main-Function: ******************************************************************/
int main (int argc, char **argv) {
/** Variables: */
pid_t pid, sid;
/** Set up the demon: ***********************************************************/
pid = fork();
if (pid < 0) {
return -2;
}
/** If we got a good PID, then we can exit the parent process: */
if (pid > 0) {
printf("Sturting Deamon as PID %i.\n", pid);
int iStatus;
pid_t pid;
pid = waitpid(-1, &iStatus, 0);
if ((pid == 0) || (pid == -1)) {
printf("Client exited unknown!\n");
}else{
if (WEXITSTATUS(iStatus) == 0) {
printf("Client %i exited success!\n", pid);
}else{
printf("Client %i exited with error!\n", pid);
}
}
return 0;
}
/** Close out the standard file descriptors: */
if ((argv[1][0]) != 'd') {
close(STDIN_FILENO);
close(STDOUT_FILENO);
//close(STDERR_FILENO);
}
/** Open syslog: */
openlog( "BuzzerD", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_LOCAL0 );
/** Try to run: */
execlp("bash", "bash", "/home/pi/TexPrint", "/home/pi/SoLieb.tex", NULL);
syslog(LOG_ERR | LOG_DAEMON, "FAILURE running execlp!");
_exit(1);
}
Here is the sript to be called:
#SOURCE=$1
#TARGET=${SOURCE/tex/pdf}
#echo Compiling $SOURCE to $TARGET and print!
#echo pdflatex $SOURCE
#echo Trying to print $TARGET ...
#echo lp -d Brother_MFC_J5930DW $TARGET
#echo .
/home/pi/BuzzerD/buzzerd -l off
sleep 3
/home/pi/BuzzerD/buzzerd -l alive
exit 1

How to make system() function unblocking?

I am calling an executable from another executable in android Linux. Following is the relevant code:
...
int status = system("/system/bin/executable");
...
My requirement is not to wait for the executable to complete its execution. Means I want to run executable independent of the executable that calls it.
I have searched over the internet and didn't find how to make this system call non-blocking. Please help me to resolve it.
The system() function, without error handling, looks like this:
int system(char const *cmdline)
{
pid_t pid = fork();
if(pid == 0)
{
char const *argv[] = { "sh", "-c", cmdline, NULL };
execve("/bin/sh", argv, NULL);
_exit(1);
}
else
{
int status;
waitpid(pid, &status, 0);
return status;
}
}
The command itself is parsed by the shell, so you can use the normal & suffix to send the command into the background. The shell then terminates immediately, the background program is reparented to PID 1 (so your program isn't responsible for collecting the zombie), and system() returns.
I am able to achieve non-blocking with following code:
if (fork() == 0)
{
char *args[] = {..., NULL};
char *env[] = {..., NULL};
if (execve("/system/bin/executable", args, env) == -1)
print("Error: [%d]", errno);
}
There are few importants thing here:
fork() will create a new process. So from line if(fork() == 0), there will be 2 process running in the same space of main program.
Both processes continue executing from the point where the fork( ) calls returns execution to the main program..
fork() == 0 will let only child process in the if condition.
execve(..) will replace child process program(which is its parent program from which it copied by fork command) with /system/bin/executable.
execve(..) will not return if it get success in runing the executable else return -1.
In case of execve(..) failure the errno will be filled with the actual error.
Please correct me if I am wrong. I hope it will help someone.

What's the intention of waitpid

The sample code below is from linux man page waitpid function. Can the last else if be replaced with else? When I write code, I would write like:if, else if, and end with else. So I think it is strange in the sample code.
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
pid_t cpid, w;
int status;
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Code executed by child */
printf("Child PID is %ld\n", (long) getpid());
if (argc == 1)
pause(); /* Wait for signals */
_exit(atoi(argv[1]));
} else { /* Code executed by parent */
do {
w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
if (w == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if (WIFEXITED(status)) {
printf("exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("killed by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stopped by signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) { /* can this be
*replaced with else ???
*/
printf("continued\n");
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
exit(EXIT_SUCCESS);
}
}
Here's the question I think you are asking:
Is it possible for waitpid to return a status such that none of
WIFEXITED(status), WIFSIGNALED(status), WIFSTOPPED(status), or
WIFCONTINUED(status) returns nonzero?
The answer is almost certainly "no", and the Linux man page implies as much without (unfortunately) explicitly saying it.
The UNIX standard says more here, and specifically does guarantee that one of those macros will return nonzero in certain cases. But Linux is not (necessarily) compliant to this standard.
But I think the best solution in code would be to have an else clause after those four options, and (depending on your application) take this to mean that the status is unknown. This could happen even if it's not the case now - maybe in some future version of Linux there is another kind of exit condition not covered here, and you don't want your code to crash in such a case.
The standard does seem to have evolved over time. For example, earlier versions didn't have the WIFCONTINUED case, and I also found some references online to a WIFCORED in some other systems. So it would be good to make your code flexible if you're concerned about it.

Creating three children and connecting pipes between them

I am in need of some help of understanding how to create one parent and three children and connecting pipes between the childrens.
My task is to get the first child to run ls -l /bin/?? and send it to the second child that will run grep rwxr-xr-x and send that to the third child that will run sort.
It wil look like this if typed in to bash:
ls -l /bin/?? | grep rwxr-xr-x | sort
My code right now:
#include <sys/wait.h>
#include <sys/types.h>
#inlcude <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define READ 0
#define WRITE 1
int main()
{
int fds[2], i;
pid_t pid;
pipe(fds);
for(i = 0; i < 3; i++)
{
pid = fork();
if(pid == (pid_t) 0)
if(i == 0)
{
/* First child */
}
else if(i == 1)
{
/* second child */
}
else if(i == 2)
{
/* Third child */
}
break;
else
{
/* This is the parent */
}
}
}
The problem is that i don't really know if this is the correct way of doing it.
Please avoid telling me to do this with threads as I am trying to learn pipes and communication between processes.
You are running a fork() in a loop. Every fork() will result in two processes. So total you are creating 8 processes. Need to take that fork() call out of the loop.
This is how fork works,
fork() [Process 1]
/\
/ \
[Process 1]fork() fork()[Process 2]
/\
/ \
[Process 2]fork() fork()[Process 3]
To achieve what you aspire try following code,
int main()
{
pid_t pid[3];
pid[0] = fork();
if( pid[0] == 0)
{
/* First Process */
pid[1] = fork();
if(pid[1] == 0)
{
/* First Process Continued. */
}
else
{
/* Second Process */
}
}
else
{
/* 3rd Process */
}
return 0;
}

OS-X Linux intercept process call

how do I intercept calls made from other process which I have called from my process. (say - I call make and I would like to intercept and modify call to gcc from make).
Here is a small example with ptrace:
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sys/user.h>
#include <sys/prctl.h>
const char *sys_call_name(long num);
int main()
{
pid_t pid = fork();
struct user_regs_struct regs;
if (!pid) {
/* child */
while (1) { printf("C\n"); sleep(1); }
}
else { /* parent */
int status = 0;
ptrace(PTRACE_ATTACH, pid, NULL, 0);
ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_SYSCALL) ;
while (1) {
printf("waiting\n");
pid = wait(&status);
/* child gone */
//if (WIFEXITED(status)) { break; }
ptrace(PTRACE_GETREGS, pid, 0, &regs);
/* regs.orig_eax is the system call number */
printf("A system call: %d : %s\n", regs.orig_eax, sys_call_name(regs.orig_eax));
/* let child continue */
ptrace(PTRACE_SYSCALL, pid, NULL, 0);
}
}
return 0;
}
const char *sys_call_name(long num) {
switch(num) {
case 4: return "write";
case 162: return "nanosleep";
case 165: return "getresuid";
case 174: return "rt_sigaction";
case 175: return "rt_sigprocmask";
default: return "unknown";
}
}
It sound from your question that you are looking for Makefile help, specifically you are looking for doing something for all call to the c-compiler.
make allows for any command to be redefined locally -- all you have to do is redefine the macro in make -- for gcc you would simply redefine the CC macros.
You could do that from the command like, like
make CC=echo
which would substitute all call from gcc to echo (not very useful, but you get the idea).
Or you can do it in the Makefile by adding a line like
CC=echo
testprogram: testprogram.o
and when you do make testprogram the make will echo something rather than invoking gcc
You don't easily. The facility in question is the ptrace function, not for the faint of heart.

Resources