C - threads and processes - prevent zombies - c

I'm implementing a function which receives a parsed-to-array command lines ("./waiter 20 &" will be parsed, and the function will receive the array
{"./waiter","20","&"} for example).
If the last argument is &, the process should run in the background.
To prevent zombies, I need to use a new thread that will wait for the child process.
The attached code is my working program, and all my efforts to add a new thread that will wait for the child process failed.
Anyone can guide me?
Attaching the code, with some of the leftovers of my unsuccessful tries.
(the function is process_arglist)
update: after a lot of tries using what suggested here, its still failing and im not sure why. updated code attached.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
void func(void* ptr) {
pid_t* mypid = (pid_t*)ptr;
waitpid(*mypid);
pthread_detach(pthread_self());
}
int process_arglist(int count, char** arglist){
int isBackground = 0;
pid_t pid;
int status;
char** parsedList;
if (strcmp(arglist[count-1],"&") == 0) {
printf("###we are in the & situation\n");
parsedList = (char**)malloc((count-1)*sizeof(char*));
if (parsedList == NULL) {
printf( "Error: malloc failed - %s\n", strerror(errno));
}
int i;
for (i=0;i<count-1;i++){
parsedList[i] = arglist[i];
}
/*printf("parsed list:\n");
for (i=0;i<count-1;i++) {
printf(" %d: %s\n", i,parsedList[i]);
}*/
if ((pid = fork()) < 0) { /* fork a child process */
printf( "Error: fork failed");
exit(0);
} else if (pid == 0) { /* for the child process: */
if (execvp(*parsedList,parsedList) < 0) { /* execute the command */
printf( "Error: execvp failed - %s\n", strerror(errno));
exit(0);
}
} else {
pthread_t thread;
pthread_create(&thread, NULL, (void*) &func, (void*) &pid);
}
} else {
if ((pid = fork()) < 0) { /* fork a child process */
printf( "Error: forking child process failed - %s\n", strerror(errno));
exit(0);
}
else if (pid == 0) { /* for the child process: */
if (execvp(*arglist,arglist) < 0) { /* execute the command */
printf( "Error: execvp failed - %s\n", strerror(errno));
exit(0);
}
}
else { /* for the parent: */
while (waitpid(&status) != pid); /* wait for completion */
}
}
}

First, switch from calling wait to calling waitpid. Otherwise, if you have more than one thread waiting, they'll steal each other's notifications.
Second, break the call to waitpid into its own function that takes the PID to wait for as a parameter. Cast it through void *, since that's what's used for thread parameters.
Third, change the call to the function to a call to pthread_create, casting the PID to wait for to a void * to pass to the newly-created thread.
Lastly, have the thread detach itself, since there won't be anything waiting for the thread to terminate.

Related

Need Help Running a Linux Command in the Background and another in the foreground simulataneously

I am writing a C code that acts as a Linux shell. I'm trying to create a program that can run a command such as 'sleep 7 &' in the background while simultaneously running a command like 'ps -l' in the foreground. Currently, my code is triggering my "perror("wait")" error message. Am I not forking at the correct location? Any insight is appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <string.h>
int execute(char *argv[])
/*
* purpose: run a program passing it arguments
* returns: status returned via wait, or -1 on error
* errors: -1 on fork() or wait() errors
*/
{
int i = 0; /* This will be our array iterator */
size_t size = sizeof *(argv) / sizeof *(argv[0]); /* This is the size of the argv array that we will iterate through */
int pid;
int child_info = -1;
/* Check if the first argument exists */
if (argv[0] == NULL)
{ /* nothing succeeds */
return 0;
}
/* Using a for loop to traverse the argvs */
for (i; i < size; i++)
{
/* if the argv exists */
if (argv[i] != NULL)
{
/* check to see if the argv is an ampersand */
if (strcmp(argv[i], "&") == 0)
{
/* Let us know there is infact an ampersand */
printf("We have an ampersand\n");
argv[i] = '\0';
}
}
}
if ((pid = fork()) == -1)
{
perror("fork");
}
else if (pid == 0)
{
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
execvp(argv[0], argv);
perror("cannot execute command");
exit(1);
}
else
{
printf("\nProcess %d has begun in the background.\n", pid);
fork(); !!! <---- Where I'm trying to fork() and allow a new process to run in the foreground.
if (waitpid(pid, &child_info, WNOHANG) == -1)
{
perror("wait");
}
else if (waitpid(pid, &child_info, WNOHANG == 0))
{
printf("Process %d done.\n", pid);
kill(pid, SIGKILL);
}
}
return child_info;
}
Currently, it runs the sleep command but says "Wait: No Child Process".

Logging to a file in daemon process

I am following a quick guide how to create daemon process in C, that was created as an answer to one of Stack Overflow questions.
And here is a problem, to make this code easier for me I have created a file, where I am logging some debug data, but when I make a second fork(), my new child seems not to log anything. I check the list of processes that exists. I have no idea why it did not print anything to my file. Any ideas? 0.o
My adjusted code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <syslog.h>
#define LOG_FILE "/local_pv/asiwek/daemon_test/daemon_log.log"
static void skeleton_daemon(FILE* file)
{
pid_t pid;
/* Fork off the parent process */
pid = fork();
/* An error occurred */
if (pid < 0)
exit(EXIT_FAILURE);
/* Success: Let the parent terminate */
if (pid > 0)
exit(EXIT_SUCCESS);
fprintf(file ,"I'm a child! \n");
/* On success: The child process becomes session leader */
if (setsid() < 0)
{
fprintf(file ,"ERROR: setsid()! \n");
exit(EXIT_FAILURE);
}
/* Catch, ignore and handle signals */
//TODO: Implement a working signal handler */
signal(SIGCHLD, SIG_IGN);
signal(SIGHUP, SIG_IGN);
/* Fork off for the second time*/
pid = fork();
/* An error occurred */
if (pid < 0)
{
fprintf(file ,"ERROR: fork()! \n");
exit(EXIT_FAILURE);
}
/* Success: Let the parent terminate */
if (pid > 0)
{
fprintf(file, "I'm a parent of the child! pid : %d", pid);
exit(EXIT_SUCCESS);
}
fprintf(file ,"New Child!! \n"); // here program stops logging
/* Set new file permissions */
umask(0);
/* Change the working directory to the root directory */
/* or another appropriated directory */
chdir("/local_pv/asiwek/daemon_test/");
fprintf(file ,"chdir \n");
/* Close all open file descriptors */
int x;
for (x = sysconf(_SC_OPEN_MAX); x>=0; x--)
{
close (x);
}
/* Open the log file */
//openlog ("firstdaemon", LOG_PID, LOG_DAEMON);
fprintf(file ,"skeleton_daemon() end. \n");
}
int main()
{
FILE* f = fopen(LOG_FILE, "w");
skeleton_daemon(f);
fprintf(f ,"Oh boy I am a daemon!!! \n");
while (1)
{
//TODO: Insert daemon code here.
// syslog (LOG_NOTICE, "First daemon started.");
fprintf(f, "Some log.");
sleep (200);
break;
}
//syslog (LOG_NOTICE, "First daemon terminated.");
//closelog();
fclose(f);
return EXIT_SUCCESS;
}

Fork() and Posix Queues. Send and Receive strings

what I want is this:
1 main process that create 4 children process where:
-> The main process receive messages from the children through the queue and print the message recieved.
-> The children send messages (a string with priority+message) through the queue and finish.
All in a while (1), so, when you CTRL+C, the children finish first (the signal is in the children code) and then, the parent finish.
For the moment, I am having problem with mq_send() and mq_recieve().
Well, this is my code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <mqueue.h>
void sigint_handler()
{
/*do something*/
printf("killing process %d\n",getpid());
exit(0);
}
int main ()
{
mqd_t mqd;
struct mq_attr atributos;
// atributos.mq_maxmsg = 10;
//
// atributos.mq_msgsize = 50;
printf ("This is the parent. PID=%d\n",getpid ());
int num_children = 4;
int i;
int pid;
int status;
char buffer [50];
while (1){
for (i=0; i<num_children ;i++){
if ((pid=fork()==0)){
signal(SIGINT, sigint_handler);
int prio = rand () % 3;
printf ("%d\n",prio);
char * msg= "Hi dude";
char * priority=NULL;
if (prio == 0){
priority = "NORMAL";
}
else {
priority = "URGENT";
}
char* toSend=NULL;
toSend = malloc(strlen(msg)+1+strlen(priority));
strcpy (toSend,priority);
strcat (toSend,msg);
printf ("%s\n",toSend);
if ((mqd=mq_open("/queue.txt", O_CREAT|O_WRONLY, 0777, &atributos))==-1){
printf ("Error mq_open\n");
exit(-1);
}
if (mq_send(mqd, msg , strlen(toSend), prio) == -1) {
printf ("Error mq_send\n");
exit (-1);
}
mq_close(mqd);
printf ("This is children %d\n",getpid());
sleep(1);
exit(0);
}
}
if ((mqd=mq_open("/queue.txt", O_CREAT|O_WRONLY, 0777, &atributos))==-1){
printf ("Error mq_open\n");
exit(-1);
}
//Rest Parent code
if (mq_receive(mqd, buffer, strlen(buffer),0)==-1){
printf ("Error mq_recieve\n");
exit(-1);
}
printf("Received: %s\n",buffer);
sleep (1);
waitpid(pid,&status,0);
printf ("This is the parent again %d, children should have finished\n",getpid());
mq_close(mqd);
}
}
I don't know why both mq_send() and mq_receive() returns -1, what am I doing wrong¿?
And you you see something wrong in my code in order to do what I intend apart from the error I am talking about, let me know.
Thank you in advance, I appreciate any help.
user58697 touched upon the biggest problems.
(1) Your queue opens were failing with EINVAL because you wee passing uninitialized attributes because you commented out assignments.
(2) You were opening both queues for write-only. The parent queue needed to be opened in read mode.
(3) Execute permissions don't mean anything to a queue so 777 permissions while not invalid are unnecessary.
(4) Your sends/receives were failing because of invalid lengths. In many if not most cases it is just easier and safer to allocate your buffers to the length attribute of the queue. In this case you know the length before hand but in programs that don't you can get the value via mq_getattr.
(5) You weren't calling srand to seed the RNG before calling rand.
(6) You had a memory leak where you allocate space (unnecessarily) for the message but never freed it.
(7) What you were trying to do with passing priorities is redundant. POSIX MQs have priorities already built in. You can just use those.
I took out some of the fluff (mainly the loops & signals) to concentrate more on the queue aspects of your program.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
#include <mqueue.h>
int main()
{
srand(time(NULL));
mqd_t mqd;
struct mq_attr atributos = {.mq_maxmsg = 10, .mq_msgsize = 50};
int i;
int pid;
int status;
int num_children = 4;
char buffer[atributos.mq_msgsize];
for (i = 0; i < num_children; i++)
{
if ((pid = fork() == 0))
{
int prio = rand () % 3;
char* msg = "Hi dude";
strncpy (buffer, msg, sizeof(buffer));
if ((mqd = mq_open("/queue.txt", O_CREAT | O_WRONLY, 0666, &atributos)) == -1)
{
perror("child mq_open");
exit(1);
}
if (mq_send(mqd, buffer, sizeof(buffer), prio) == -1)
{
perror("mq_send");
exit(1);
}
mq_close(mqd);
exit(0);
}
}
// parent
if ((mqd = mq_open("/queue.txt", O_CREAT | O_RDONLY, 0666, &atributos)) == -1)
{
perror("parent mq_open");
exit(1);
}
int priority;
for (int i = 0; i < num_children; ++i)
{
if (mq_receive(mqd, buffer, sizeof(buffer), &priority) == -1)
{
perror("mq_recieve");
exit(1);
}
printf("Received (%s): %s\n", (priority == 0) ? "NORMAL" : "URGENT", buffer);
pid_t childpid;
if ((childpid = waitpid(-1, &status, 0)) > 0)
{
if (WIFEXITED(status))
printf("PID %d exited normally. Exit status: %d\n",
childpid, WEXITSTATUS(status));
else
if (WIFSTOPPED(status))
printf("PID %d was stopped by %d\n",
childpid, WSTOPSIG(status));
else
if (WIFSIGNALED(status))
printf("PID %d exited due to signal %d\n.",
childpid,
WTERMSIG(status));
}
}
mq_close(mqd);
}
First and foremost, when a system call fails, print errno (and strerror(errno)).
Now, obvious mistakes:
as was mentioned, you need a read access to be able to mq_receive()
what is strlen(buffer)?
you are passing attributes without initializing them.
To summarize, print errno and see what is wrong.

Wait for a Forked Process when using a Semaphore

I'm trying to code an exercise in C Linux where I have one semaphore with 2 spots and "n" processes entered by argument. I need that the first 2 processes use the semaphore using the 2 spots for 5 secs each and then leave the semaphore for the other remaining processes to do their stuff. The problem is that not all the other processes wait for the semaphore to be free and some of them show a semaphore error (look at the results at the bottom). I believe the problem is on the waits for the child processes, because I have a waitipid and a wait function, but I need that if there's a free spot in the semaphore, any child process running could use it. Here's the code:
//gcc SemaphoreExample.c -o s
//./s 5
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/sem.h>
void semaphoreTask(int semid, int semnum, int semBusy)
{
struct sembuf data;
data.sem_num = semnum;
data.sem_flg = 0;
data.sem_op = semBusy;
if(semop(semid,&data,1) == -1)
{
printf("\nSemaphore Error\n");
exit(-1);
}
}
int main(int argc, char *argv[])
{
int i, fdSemaphore, quantity, fdsemctl, j;
pid_t pid[15];
system("clear");
if(argc-1 < 1)
{
printf("Some arguments are missing\n");
return EXIT_FAILURE;
}
printf("Number of arguments entered:\n\nargc: %d\n\nValues from the arguments:\n\n",argc-1);
for(i=0;i<argc;i++)
{
printf("argv[%d]: %s\n",i,argv[i]);
}
printf("\n\n");
fdSemaphore = semget(1234,1,IPC_CREAT|0777);
if(fdSemaphore == -1)
{
printf("\nError creating the Semaphore\n");
return EXIT_FAILURE;
}
fdsemctl = semctl(fdSemaphore,0,SETVAL,2);
if(fdsemctl == -1)
{
printf("\nError opening the Semaphore\n");
return EXIT_FAILURE;
}
quantity = atoi(argv[1]);
for(i=0;i<quantity;i++)
{
pid[i] = fork();
if(pid[i] == -1)
{
printf("\nError creating the Child Process\n");
return EXIT_FAILURE;
}
if(pid[i] == 0)
{
semaphoreTask(fdSemaphore,0,-1);
printf("\n[%d] I go to sleep\n",getpid());
sleep(5);
printf("\n[%d] I wake up\n",getpid());
semaphoreTask(fdSemaphore,0,1);
}
else
{
//printf("\nJust wait\n");
waitpid(pid[i],NULL,WNOHANG);
}
}
for(j=0;j<quantity;j++)
{
wait(NULL);
}
semctl(fdSemaphore,0,IPC_RMID);
return EXIT_SUCCESS;
}
This is the result I got:
Result:
Number of arguments entered:
argc: 1
Values from the arguments:
argv[0]: ./s
argv[1]: 5
[2845] I go to sleep
[2844] I go to sleep
[2845] I wake up
[2844] I wake up
Semaphore Error
[2843] I go to sleep
Semaphore Error
Semaphore Error
[2843] I wake up
Semaphore Error
Should I use wait or waitpid only?
The problem is semaphores are getting removed by forked children.
After line
semaphoreTask(fdSemaphore,0,1);
add
exit(0);
It is much simpler to implement what you want if you use sem_post and sem_wait calls. I am on a OpenBSD system and I am assuming that Linux has the same thing.

How to trace a process for system calls?

I am trying to code a program that traces itself for system calls. I am having a difficult time making this work. I tried calling a fork() to create an instance of itself (the code), then monitor the resulting child process.
The goal is for the parent process to return the index of every system call made by the child process and output it to the screen. Somehow it is not working as planned.
Here is the code:
#include <unistd.h> /* for read(), write(), close(), fork() */
#include <fcntl.h> /* for open() */
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <sys/wait.h>
#include <sys/types.h>
int main(int argc, char *argv[]) {
pid_t child;
long orig_eax;
child = fork();
if (0 == child)
{
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
if (argc != 3) {
fprintf(stderr, "Usage: copy <filefrom> <fileto>\n");
return 1;
}
int c;
size_t file1_fd, file2_fd;
if ((file1_fd = open(argv[1], O_RDONLY)) < 0) {
fprintf(stderr, "copy: can't open %s\n", argv[1]);
return 1;
}
if ((file2_fd = open(argv[2], O_WRONLY | O_CREAT)) < 0) {
fprintf(stderr, "copy: can't open %s\n", argv[2]);
return 1;
}
while (read(file1_fd, &c, 1) > 0)
write(file2_fd, &c, 1);
}
else
{
wait(NULL);
orig_eax = ptrace (PTRACE_PEEKUSER, child, 4 * ORIG_EAX, NULL);
printf("copy made a system call %ld\n", orig_eax);
ptrace(PTRACE_CONT, child, NULL, NULL);
}
return 0;
}
This code was based on this code:
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/user.h> /* For constants
ORIG_EAX etc */
int main()
{
pid_t child;
long orig_eax;
child = fork();
if(child == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execl("/bin/ls", "ls", NULL);
}
else {
wait(NULL);
orig_eax = ptrace(PTRACE_PEEKUSER,
child, 4 * ORIG_EAX,
NULL);
printf("The child made a "
"system call %ld\n", orig_eax);
ptrace(PTRACE_CONT, child, NULL, NULL);
}
return 0;
}
The output of this one is:
The child made a system call 11
which is the index for the exec system call.
According to the man pages for wait():
All of these system calls are used to wait for state changes in a child
of the calling process, and obtain information about the child whose
state has changed. A state change is considered to be: the child terminated;
the child was stopped by a signal; or the child was resumed by
a signal.
The way I understand it is that every time a system call is invoked by a user program, the kernel will first inspect if the process is being traced prior to executing the system call routine and pauses that process with a signal and returns control to the parent. Wouldn't that be a state change already?
The problem is that when the child calls ptrace(TRACEME) it sets itself up for tracing but doesn't actually stop -- it keeps going until it calls exec (in which case it stops with a SIGTRAP), or it gets some other signal. So in order for you to have the parent see what it does WITHOUT an exec call, you need to arrange for the child to receive a signal. The easiest way to do that is probably to have the child call raise(SIGCONT); (or any other signal) immediately after calling ptrace(TRACEME)
Now in the parent you just wait (once) and assume that the child is now stopped at a system call. This won't be the case if it stopped at a signal, so you instead need to call wait(&status) to get the child status and call WIFSTOPPED(status) and WSTOPSIG(status) to see WHY it has stopped. If it has stopped due to a syscall, the signal will be SIGTRAP.
If you want to see multiple system calls in the client, you'll need to do all of this in a loop; something like:
while(1) {
wait(&status);
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
// stopped before or after a system call -- query the child and print out info
}
if (WIFEXITED(status) || WIFSIGNALED(status)) {
// child has exited or terminated
break;
}
ptrace(PTRACE_SYSCALL, childpid, 0, 0); // ignore any signal and continue the child
}
Note that it will stop TWICE for each system call -- once before the system call and a second time just after the system call completes.
you are basically trying to write strace binary in linux, which traces the system calls of the process. Linux provides ptrace(2) system call for this. ptrace system call takes 4 arguement and the first arguement tells what you need to do. OS communicates with the parent process with signals and child process is stopped by sending SIGSTOP. broadly you need to follow below steps.
if(fork() == 0 )
{
//child process
ptrace(PTRACE_TRACEME, 0,0, 0);
exec(...);
}
else
{
start:
wait4(...);
if (WIFSIGNALED(status)) {
//done
}
if (WIFEXITED(status)) {
//done
}
if(flag == startup)
{
flag = startupdone;
ptrace(PTRACE_SYSCALL, pid,0, 0) ;
goto start;
}
if (if (WSTOPSIG(status) == SIGTRAP) {) {
//extract the register
ptrace(PTRACE_GETREGS,pid,(char *)&regs,0)
}
Note the register reading and interpretation will depend on your architecture. The above code is just an example to get it right you need to dig deeper. have a look at strace code for further understanding.
In your parent how many calls do you want to monitor? If you want more than one you're going to need some kind of loop.
Note the line in the example, it's important:
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
Looking at the man page the child needs to either do a PTRACE_TRACEME and an exec, or the parent needs to trace using PTRACE_ATTACH. I don't see either in your code:
The parent can initiate a trace by calling fork(2) and having the resulting child do a PTRACE_TRACEME, followed (typically) by an exec(3). Alternatively, the parent may commence trace of an existing process using PTRACE_ATTACH.
Just putting together what Chris Dodd said:
#include <unistd.h> /* for read(), write(), close(), fork() */
#include <fcntl.h> /* for open() */
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <sys/wait.h>
#include <sys/types.h>
int main(int argc, char *argv[]) {
pid_t child;
int status;
long orig_eax;
child = fork();
if (0 == child)
{
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
raise(SIGCONT);
if (argc != 3) {
fprintf(stderr, "Usage: copy <filefrom> <fileto>\n");
return 1;
}
int c;
size_t file1_fd, file2_fd;
if ((file1_fd = open(argv[1], O_RDONLY)) < 0) {
fprintf(stderr, "copy: can't open %s\n", argv[1]);
return 1;
}
if ((file2_fd = open(argv[2], O_WRONLY | O_CREAT)) < 0) {
fprintf(stderr, "copy: can't open %s\n", argv[2]);
return 1;
}
while (read(file1_fd, &c, 1) > 0)
write(file2_fd, &c, 1);
}
else
{
while(1){
wait(&status);
if(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP){
orig_eax = ptrace(PTRACE_PEEKUSER, child, sizeof(long) * ORIG_EAX, NULL);
printf("copy made a system call %ld\n", orig_eax);
}
if(WIFEXITED(status) || WIFSIGNALED(status)){
break;
}
ptrace(PTRACE_SYSCALL, child, 0, 0);
}
}
return 0;
}

Resources