Fork Infinite Loop - c

I am trying to make an directory monitoring program in C. So far it detects the subdirectories of a main directory, however the problem happens when I try to monitor the subdirectories of the subdirectories.
char * const son[] = { argv[0], name, NULL };
pid_t pid = fork();
if (pid == 0) {
execvp(son[0], son);
}
This code should have created a child process which would monitor the subdirectories. name is a string with the subdirectory "Desktop/test", for example.
I tried to print "name" before and it is the subdirectory I want so the problem isn't here.
The program works flawlessly until I add this. Once I add it, it enters an infinite loop, despite working previously. I also want to point out I don't use signals so the problem doesn't come from them.
This of course is just an excerpt of he code. If you think I need to post the full code, which is much bigger, I will add it, although honestly I doubt the problem is in it since it worked perfectly before.
EDIT:
Better add all the code, argv[1] is the directory,argv[2] for how many minutes I want the program to run, argv[3], it's the pause between each scan. It works if I remove the excerpt above and I know it's a bit confusing but if you have any questions just say.
int main(int argc, char *argv[]) {
char** direc;
int direct_pos = 0;
direc = (char**) malloc(2 * sizeof(char*));
double actual_time = 0;
double MAXTIME = atof(argv[2]);
MAXTIME = MAXTIME * 60;
double IterationTime = atof(argv[3]);
time_t start = time(0);
char dot2[100];
char dot[100];
sprintf(dot, "%s/.", argv[1]);
sprintf(dot2, "%s/..", argv[1]);
direct_pos++;
direc[direct_pos - 1] = (char*) malloc(strlen(dot) * sizeof(char));
strcpy(direc[direct_pos - 1], dot);
direct_pos++;
direc[direct_pos - 1] = (char*) malloc(strlen(dot2) * sizeof(char));
strcpy(direc[direct_pos - 1], dot2);
if (argc != 4) {
fprintf(stderr, "Usage: %s dir_name\n", argv[0]);
exit(1);
}
while (actual_time < MAXTIME) {
DIR *dirp;
if ((dirp = opendir(argv[1])) == NULL) {
perror(argv[1]);
exit(2);
}
struct stat stat_buf;
struct dirent *direntp;
while ((direntp = readdir(dirp)) != NULL) {
char name[100];
sprintf(name, "%s/%s", argv[1], direntp->d_name);
if (lstat(name, &stat_buf) == -1)
{
perror("lstat ERROR");
exit(3);
}
if (S_ISDIR(stat_buf.st_mode))
{
int x;
for (x = 0; x <= direct_pos; x++) {
if (x == direct_pos) {
char**newarray;
newarray = (char**) malloc((direct_pos + 1)* sizeof(char*));
int l;
for (l = 0; l < direct_pos; l++) {
//printf("\nxxxx%d\n", sizeof(direc[l]));
newarray[l] = (char*) malloc((strlen(direc[l])+1)
* sizeof(char));
strcpy(newarray[l], direc[l]);
}
direc = newarray;
direc[direct_pos] = (char*) malloc(sizeof(name)
* sizeof(char));
direc[direct_pos] = strcpy(direc[direct_pos], name);
direct_pos++;
double seconds_since_start = difftime(time(0), start);
double new_time = (MAXTIME - seconds_since_start) / 60;
char time_array[10];
sprintf(time_array,"%f",new_time);
char * const son[] = { argv[0], name, time_array,
argv[3], NULL };
printf("\n%s\n",son[1]);
x = direct_pos + 2;
pid_t pid = fork();
if (pid == 0) {
execvp(son[0], son)==-1);
break;
}
} else if (strcmp(name, direc[x]) == 0) {
x = direct_pos + 2;
}
}
}
}
sleep(IterationTime);
actual_time += IterationTime;
closedir(dirp);
}
exit(0);
}

You have a program that forks and then runs a new copy of itself. Think of it as endless recursion. There's no need to exec a new instance, simply write your code so that the program continues down one of two paths depending on the returned process ID.
But that's not the correct solution.
The correct solution is not to fork at all. You gain almost no benefit from having a thousand processes that look at one directory, versus a single process that looks at a thousand directories. Actually, you may be far worse, by putting load on the scheduler.

It looks like you always fork no matter what. I would put a check in there to make sure that if you have no subdirectories in the current directory that you don't fork.

You are forking a child-process, but what does the parent process do after the call to fork()? It seems you are wanting to recursively fork processes, but in order for that to work properly, you will have to-do the following:
1) Check to see if there are any sub-directories in the current directory ... if there aren't any, then exit(), otherwise read all the sub-directories in the current directory.
2) For each sub-directory fork a process. If the fork is the child (i.e., pid == 0), then make a call to execvp().
3) If pid != 0, then you're in the parent process. Rather than trying to sleep for some period of time, make a call to wait(), and keep on repeating the call to wait() until there are no child processes left.
4) Once there are no child-processes left (i.e., wait() returns an error status such that errno == ECHILD), then you can make a call to exit() in the parent process.
So if you follow those 4 steps, you should not incurr any infinite loops. Every child process will at some point exit once they reach a directory with no more sub-directories, and every parent will wait for it's children before exiting so you won't end up with any orphaned processes. If you do end up with an infinite loop, then it's because a child process is not exiting, which would then point to the logic used to detect if there are any sub-directories in the current directory, or you're not properly detecting that there are no longer any child left to wait for in a parent process.
Hope this helps,
Jason

Related

libuv: difference between fork and uv_spawn?

Recently I have been playing around with Libuv. I don't get the programming model as far as child processes are concerned.
For example look at the following code:
uv_loop_t *loop;
uv_process_t child_req;
uv_process_options_t options;
void on_exit(uv_process_t* proc, long int io, int hj)
{
std::cout<<"on exit call back"<<std::endl;
}
int main()
{
loop = uv_default_loop();
char* args[3];
args[0] = "mkdir";
args[1] = "test-dir";
args[2] = NULL;
options.exit_cb = on_exit;
options.file = "mkdir";
options.args = args;
int r;
r = uv_spawn(loop, &child_req, &options);
std::cout<<r<<std::endl;
if (r) {
std::cout<<"from line 231"<<std::endl;
fprintf(stderr, "%s\n", uv_strerror(r));
return 1;
} else {
fprintf(stderr, "Launched process with ID %d\n", child_req.pid);
}
return uv_run(loop, UV_RUN_DEFAULT);
}
Here the output printed on console is:
0
Launched process with ID 511168
on exit call back
In my understanding uv_spawn acts like fork(). In child process the value of r is 0 and in parent process it is non-zero. So from line 231 should also be printed. But evidently it is not. I read the documentation end to end but I have no clue.
Any help will be appreciated.
n my understanding uv_spawn acts like fork()
And then like execve and child becomes mkdir. So child executes mkdir, and only parent returns to your code.

fscanf in while loop won't stop iterating

In a file I've got a huge amount of words (10.000) that I'ld like to work with "efficiently", so I've decided to divide them into chunks of 100 words distributed among a max amount of child processes (8) to avoid overhead, but my while statement for reading the file won't become false. Here is my code without the appropriate imports:
FILE* fp = fopen(argv[1], "r");
int index= 0;
int childs_amount = 0;
char* word = malloc(sizeof(char) * 46); /* 45 is the len of the largest word in english */
char** words = malloc(sizeof(char*) * 100); /* 100 is the amount of words I want to assign to a child */
while(fscanf(fp, "%s", word) == 1) {
words[index] = malloc(sizeof(char) * 46);
strcpy(words[index], word);
index++;
if (index == 100) {
index = 0;
pid_t child_pid = fork();
if (child_pid == 0) { /* Child process */
usleep(5000); /* do something */
exit(0);
} else { /* Parent Process */
childs_amount++;
if (childs_amount == 8) { /* 8 is the max amount of childs I want at the same time */
pid_t ended_pid = wait(&status); /* wait for any process to finish */
childs_amount--;
}
}
}
}
fclose(fp);
It's like my children processes are accessing it or maybe I should close the file before every exit(0), but I really don't know, please help.

Thread safe file copy

I'm trying to write a program that backs up multiple files to a folder called .backups. It creates one thread for each file or subdirectory, and that thread is responsible for the copy operation. However it's not working correctly. Sometimes files are never copied, sometimes they are but there are 0 bytes, and sometimes it works correctly. It seems completely random and I have no idea what's causing it. Can anyone help me figure it out?
// Copies the file from source to destination and returns number of bytes written
ssize_t copy_file(char* from, char *to)
{
const int BUFFER_SIZE = 4096;
char buffer[BUFFER_SIZE];
ssize_t n;
ssize_t written = 0;
FILE* file_from = fopen(from, "r");
FILE* file_to = fopen(to, "w");
if (file_from == NULL || file_to == NULL)
return -1;
while ((n = fread(buffer, 1, BUFFER_SIZE, file_from)) > 0) {
if (fwrite(buffer, sizeof(char), n, file_to) != n)
return -1;
written += n;
}
return written;
}
// Thread responsible for handling the backup of a single file or subdirectory
void* backup_thread(void* arg)
{
struct backup_info* info = (struct backup_info*) arg;
ssize_t written;
written = copy_file(info->file, info->destination);
int rc = pthread_detach(pthread_self());
if (rc != 0)
exit(EXIT_FAILURE);
free(info);
return NULL;
}
EDIT: Also, this is how I am creating each of the threads.
struct backup_info* info = malloc(sizeof(struct backup_info));
if ((rc = pthread_create(&thread_id, NULL, backup_thread, info)) != 0)
fprintf(stderr, "pthread_create() failed (%d): %s", rc, strerror(rc));
How does the main thread exit?
If it just returns from main(), then that is the same as calling exit(), and will result in all the other threads being unceremoniously killed in the middle of whatever they happen to be doing.
If instead you call pthread_exit() explicitly in main(), then the detached threads will be allowed to finish before the process exits.
Note also that the exit(EXIT_FAILURE) in backup_thread() has the same problem - if that error case fires, it will tear down the entire process immediately. pthread_exit() may be better used here as well.
I spotted something wrong that may be causing your problem. You never call fclose() on any of your files. That will eventually lead to using up all of your file descriptors (which are shared among your threads). I don't know if that is the only thing wrong, but you should make the fix and see what happens.

Redirecting execvp path

I'm trying to write a simple code which execute a program from subfolders from a input file and print thr result into a output file.
My problem is that when i execute the program it keeps failing on me. since the execvp command is trying to look for an exe named "a.out" on the wrong location. in (desktop rather than searching the correct path address).
here's the code. please help me out :)
pid_t runner;
char enter[] = "/home/demo/Desktop/OS/Ex1/Ex12/code/input.txt"; // input file
char path[] = "/home/demo/Desktop/OS/Ex1/Ex12/Ex1/ronen/"; correct path
char *r [] = {"./a.out", NULL};
int savedFD = dup(0);
int sever2Fd=dup(1);
int fdin = open(enter,O_RDONLY);
int fdout = open ("output.txt", O_CREAT | O_RDWR, 0466);
dup2(fdin, 0);
dup2(fdout, 1);
if ((runner = fork()) < 0) {perror("could not make fork");}
else if (runner == 0) {
if (execvp(r[0],r) < 0 ) {printf("Failed!\n");}
} else if (runner != 0) {
waitpid(runner,0,0);
dup2(savedFD, 0);
dup2(sever2Fd, 1);
printf("done\n");
}
close(fdin);close(fdout);
The answer was simple.
"chdir(wanted path)"
int dirchange = chdir(argv[1]);

Segmentation fault (core dumped)

I'm writing a program in c that basically copies files, but I'm getting this error: Segmentation fault (core dumped). From what I'm reading I think it's because I'm trying to access memory that hasn't been allocated yet. I'm a newbie when it comes to c and I suck at pointers, so I was wondering if you guys could tell me which pointer is causing this and how to fix it if possible. Btw, this program is supposed to be a daemon, but I haven't put anything inside the infinite while loop at the bottom.
Here is my code:
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#include <dirent.h>
int main(int c, char *argv[]) {
char *source, *destination;
char *list1[30], *list2[30], *listDif[30];
unsigned char buffer[4096];
int i=0, x=0, sizeSource=0, sizeDest=0, sizeDif=0;
int outft, inft,fileread;
int sleeper;
struct dirent *ent, *ent1;
//Check number of arguments
if(c<3)
{
printf("Daemon wrongly called\n");
printf("How to use: <daemon name> <orginDirectory> <destinationDirectory> \n");
printf("or : <daemon name> <orginDirectory> <destinationDirectory> <sleeperTime(seconds)>");
return 0;
}
//Checks if sleeper time is given or will be the default 5minutes
/*if(c=4)
{
char *p;
errno = 0;
long conv = strtol(argv[3], &p, 10);
if(errno != 0 || *p != '\0')
{
printf("Number given for sleeper incorrect, it has to be an integer value.\n");
return(0);
} else
{
sleeper = conv;
}
} else
{
sleeper = 300;
}*/
//Get path of directories from arguments
source = argv[1];
destination = argv[2];
//Check if directories exist
DIR* dirSource = opendir(source);
if (!dirSource)
{
printf("Source directory incorrect\n");
return 0;
}
DIR* dirDest = opendir(destination);
if (!dirDest)
{
printf("Destination directory incorrect\n");
return 0;
}
/* save all the files and directories within directory */
while ((ent = readdir (dirSource)) != NULL) {
list1[sizeSource] = strdup(ent->d_name);
sizeSource++;
if(sizeSource>=30){break;}
}
closedir(dirSource);
while((ent1 = readdir (dirDest)) != NULL) {
list2[sizeDest] = strdup(ent1->d_name);
sizeDest++;
if(sizeDest>=30){break;}
}
closedir(dirDest);
/* Verify the diferences between the directories and save them */
int z;
int dif = 0; //0 - False | 1 - True
printf("Diferenças:\n");
for(i=0;i<sizeSource;i++){
dif = 0;
for(z=0;z<sizeDest;z++){
if(strcmp(list1[i],list2[z])==0){ //If there is no match, it saves the name of the file to listDif[]
dif = 1;
break;
}
}
if(dif==0) {
printf("%s\n",list1[i]);
listDif[sizeDif] = list1[i];
sizeDif++;
}
}
/* This code will copy the files */
z=0;
while(z!=sizeDif){
// output file opened or created
char *pathSource, *pathDest;
strcpy(pathSource, source);
strcat(pathSource, "/");
strcat(pathSource, listDif[z]);
strcpy(pathDest, destination);
strcat(pathDest, "/");
strcat(pathDest, listDif[z]);
// output file opened or created
if((outft = open(pathDest, O_CREAT | O_APPEND | O_RDWR))==-1){
perror("open");
}
// lets open the input file
inft = open(pathSource, O_RDONLY);
if(inft >0){ // there are things to read from the input
fileread = read(inft, buffer, sizeof(buffer));
printf("%s\n", buffer);
write(outft, buffer, fileread);
close(inft);
}
close(outft);
}
/* Our process ID and Session ID */
pid_t pid, sid;
/* Fork off the parent process */
pid = fork();
if (pid < 0) {
exit(EXIT_FAILURE);
}
/* If we got a good PID, then
we can exit the parent process. */
if (pid > 0) {
exit(EXIT_SUCCESS);
}
/* Change the file mode mask */
umask(0);
/* Open any logs here */
/* Create a new SID for the child process */
sid = setsid();
if (sid < 0) {
/* Log the failure */
exit(EXIT_FAILURE);
}
/* Change the current working directory */
if ((chdir("/")) < 0) {
/* Log the failure */
exit(EXIT_FAILURE);
}
/* Close out the standard file descriptors */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
/* Daemon-specific initialization goes here */
/* The Big Loop */
while (1) {
//sleep(5); /* wait 5 seconds */
}
exit(EXIT_SUCCESS);
}
The result of ls is:
ubuntu#ubuntu:~/Desktop$ ls
Concatenar_Strings.c core D2 daemon.c examples.desktop
Concatenar_Strings.c~ D1 daemon daemon.c~ ubiquity.desktop
D1 and D2 are folders, and in D1 are three text documents that I want to copy into D2.
One other question, is this a delayed error or an immediate one? Because I doubt this message would appear on a code line that with two integers.
Thanks in advance guys.
This loop is wrong:
while ((ent = readdir (dirSource)) != NULL) {
list1[sizeSource] = ent->d_name;
Probably, ent points to the same memory block every time, and the readdir function updates it. So when you save that pointer, you end up with your list containing invalid pointers (probably end up all pointing to the same string). Further, the string may be deallocated once you got to the end of the directory.
If you want to use the result of readdir after closing the directory or after calling readdir again you will need to take a copy of the data. In this case you can use strdup and it is usually good style to free the string at the end of the operation.
This may or may not have been the cause of your segfault. Another thing to check is that you should break out of your loops if sizeSource or sizeDest hits 30.
In the strcmp loop, you should really set dif = 0 at the start of the i loop, instead of in an else block.
Update: (more code shown by OP)
char *pathSource, *pathDest;
strcpy(pathSource, source);
You are copying to a wild pointer, which is a likely cause of segfaults. strcpy does not allocate any memory, it expects that you have already allocated enough.
One possible fix would be:
char pathSource[strlen(source) + 1 + strlen(listDif[z]) + 1];
sprintf(pathSource, "%s/%s", source, listDif[z]);
Alternatively (without using VLA):
char pathSource[MAX_PATH]; // where MAX_PATH is some large number
snprintf(pathSource, MAX_PATH, "%s/%s", source, listDif[z]);
Do the same thing for pathDest.
NB. Consider moving the closedir lines up to after the readdir loops; generally speaking you should open and close a resource as close as possible to the times you start and finish using them respectively; this makes your code easier to maintain.

Resources