Number of child processes in parent process C/C++, LINUX - c++

I am programming in Linux using C/C++. I have a problem, i am trying to find a function or something in order to get number of child processes in parent process.
Help me please
Thanks

I'm not sure if POSIX defines a function for this, but you could always count them in a global variable yourself, just add 1 after every fork on the parent, and set it to 0 on the child..

int globalVariable = 0;
main() {
pid_t pID = fork();
if (pID == 0) { //child
globalVariable = 0;
cout << "Child Process" << end;
}
else if (pID < 0) { //failed to fork
cerr << "Failed to fork" << endl;
exit(1);
// Throw exception
}
else { // parent
cout << "Parent Process:";
++globalVariable;
}
}

Use the procfs : count the number of directories in /proc/[mypid]/task and you have the number of child processes started.
See proc(5) for more information.

You can use the 'ps' command with the --ppid option to list all the child processes and then count them using wc -l
ps --ppid | wc -l

Here is how you can do it in C++11, could easily be adapted to pre-C++11 or C if needed. You need to check every process in the system and see who it's parent is:
#include <dirent.h>
#include <unistd.h>
#include <limits.h>
#include <string>
#include <fstream>
using std::string;
using std::ifstream;
using std::to_string;
bool is_number(const string& s) {
string::const_iterator it = s.begin();
for (; it != s.end() && isdigit(*it); ++it) {
}
return !s.empty() && it == s.end();
}
int count_children(const pid_t pid) {
DIR* dir;
if ((dir = opendir("/proc"))) {
int num_children = 0;
for (struct dirent* ent; (ent = readdir(dir));) {
if (is_number(ent->d_name)) {
ifstream ifs(string("/proc/" + string(ent->d_name) + "/stat").c_str());
string word;
for (int i = 0; i < 4; ++i) {
ifs >> word;
}
if (word == to_string(pid)) {
++num_children;
}
}
}
closedir(dir);
return num_children;
}
perror("could not open directory");
return INT_MAX;
}
Another possible option in the parent process is to create a variable initialised to zero in the parent process and incrementing it every time you fork and decrementing every time you receive a SIGCHLD.

Related

Myshell Segmentation Fault, Possible issue with getting input?

I have been working on this project for a while. The purpose is to make a functioning shell that can do pretty much all the shell commands (except cd). It does almost everything I want it to do, except for a couple things. The first is that when I put an '&' to signify background processing, it does it, but then doesn't print another myshell> line. I can still input something, but the myshell> never shows up, no matter where I put another cout<<"myshell> ";.
Another issue is if I press enter, making myString empty, many times, it crashes the program with a seg fault. Also after I do the '&' background processing and press enter to get the myshell> to come back up, it prints one myshell> but then seg faults on the next hit of enter. I'm sorry if I didn't explain this well, but it is really driving me crazy. Please let me know if you have any suggestions.
#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <cstring>
#include <sys/types.h>
#include <cstdio>
#include <sys/wait.h>
#include <stdio.h>
/*Function that parses the command the user inputs.
It takes myArgv and myString as inputs.
It returns the value of exitcond, which is used to see if the user wants to exit or not.
Also, this is where myString is tokenized using strok()*/
int parseCommand(char *myArgv[10], char myString[255])
{
int exitcond=0;
if((strcmp(myArgv[0], "exit") == 0)||(strcmp(myArgv[0], "quit")==0))
{
exitcond = 1;
return exitcond;
}
int i;
char *token;
token = strtok(myString," ");
i=0;
while (token != NULL)
{
myArgv[i] = token;
token = strtok(NULL," ");
i++;
}
/*
* Set the last entry our new argv to a null char
* (see man execvp to understand why).
*/
myArgv[i] = '\0';
return exitcond;
}
/*Function that gets the command from the user and sees if they want
background processing or not (presence of '&').
It takes inputs of choose and myString. choose is the variable for
whether background processing is necessary or not, while myString is
an empty character array.
It outputs the value of the choose variable for lter use.*/
int getCommand(int choose, char myString[255])
{
int i;
choose=0;
fgets(myString, 256, stdin);
if (myString[0]=='\0')
{
choose=0;
return choose;
}
for (i=0; myString[i]; i++)
{
if (myString[i]== '&')
{
choose=1;
myString[i]=' ';
}
if (myString[i] == '\n')
{
myString[i] = '\0';
}
}
return choose;
}
/*Main function where all the calling of other functions and processes
is done. This is where the user enters and exits the shell also. All
usage of fork, pid, waitpid and execvp is done here.*/
int main()
{
using namespace std;
int exitCondition=0, i=0, status;
char myString[255];
char *token, *myArgv[10];
pid_t pid, waiting;
int bg=0;
while (!exitCondition)
{
/* print a prompt and allow the user to enter a stream of characters */
cout << "myshell> ";
bg=0;
int choose=0;
bg=getCommand(choose,myString);
exitCondition=parseCommand(myArgv,myString);
if(exitCondition==1)
{
cout<<"Thank you for using my shell.\n";
}
else {
/* while (myString[0]=='\0')
{
cout<<"myshell> ";
bg=getCommand(choose,myString);
}*/
/* The user has a command, so spawn it in a child process */
pid = fork();
if (pid == -1)
{
/* to understand why this is here, see man 2 fork */
cout << "A problem arose, the shell failed to spawn a child process" << endl;
return(1);
}
else if (pid == 0)
{
// Child process
execvp(myArgv[0],myArgv);
cout << "Bad command or file name, please try again!\n" << endl;
return 0;
} else {
/* This makes sure that the spawned process is run in the foreground,
because the user did not choose background */
if(bg==0)
{
waitpid(pid,NULL,0);
}
}
}
}
return 0;
}
Okay, you had three bugs, one of which caused the segfault. Of the others, one would put a garbage argument in the array passed to execvp and the other would leak zombie processes for background jobs.
I've corrected the code and annotated it with where the bugs were along with the fixes [please pardon the gratuitous style cleanup]:
#include <cstdio>
#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define AVCOUNT 100
#define STRBUFLEN 2000
/*Function that parses the command the user inputs.
It takes myArgv and myString as inputs.
It returns the value of exitcond, which is used to see if the user wants to
exit or not.
Also, this is where myString is tokenized using strok()*/
int
parseCommand(char **myArgv, char *myString)
{
char *token;
char *bp;
int exitcond = 0;
int i;
// NOTE/BUG: original check for exit/quit was here -- at this point
// myArgv is undefined (hence the segfault)
// NOTE/BUG: your original loop -- at the end i was one beyond where it
// should have been so that when myArgv gets passed to execvp it would
// have an undefined value at the end
#if 0
token = strtok(myString, " ");
i = 0;
while (token != NULL) {
myArgv[i] = token;
token = strtok(NULL, " ");
i++;
}
#endif
// NOTE/BUGFIX: here is the corrected loop
i = 0;
bp = myString;
while (1) {
token = strtok(bp, " ");
bp = NULL;
if (token == NULL)
break;
myArgv[i++] = token;
}
/*
* Set the last entry our new argv to a null pointer
* (see man execvp to understand why).
*/
// NOTE/BUG: with your code, i was one too high here
myArgv[i] = NULL;
// NOTE/BUGFIX: moved exit/quit check to here now that myArgv is valid
token = myArgv[0];
if (token != NULL) {
if ((strcmp(token, "exit") == 0) || (strcmp(token, "quit") == 0))
exitcond = 1;
}
return exitcond;
}
/*Function that gets the command from the user and sees if they want
background processing or not (presence of '&').
It takes inputs of choose and myString. choose is the variable for
whether background processing is necessary or not, while myString is
an empty character array.
It outputs the value of the choose variable for lter use.*/
int
getCommand(int choose, char *myString)
{
int i;
choose = 0;
fgets(myString, STRBUFLEN, stdin);
if (myString[0] == '\0') {
choose = 0;
return choose;
}
for (i = 0; myString[i]; i++) {
if (myString[i] == '&') {
choose = 1;
myString[i] = ' ';
}
if (myString[i] == '\n') {
myString[i] = '\0';
break;
}
}
return choose;
}
/*Main function where all the calling of other functions and processes
is done. This is where the user enters and exits the shell also. All
usage of fork, pid, waitpid and execvp is done here.*/
int
main()
{
using namespace std;
int exitCondition = 0;
int status;
char myString[STRBUFLEN];
char *myArgv[AVCOUNT];
pid_t pid;
int bg = 0;
while (!exitCondition) {
// NOTE/BUGFIX: without this, any background process that completed
// would become a zombie because it was never waited for [again]
// reap any finished background jobs
while (1) {
pid = waitpid(0,&status,WNOHANG);
if (pid < 0)
break;
}
/* print a prompt and allow the user to enter a stream of characters */
cout << "myshell> ";
bg = 0;
int choose = 0;
bg = getCommand(choose, myString);
exitCondition = parseCommand(myArgv, myString);
if (exitCondition == 1) {
cout << "Thank you for using my shell.\n";
break;
}
/* while (myString[0]=='\0') { cout<<"myshell> "; bg=getCommand(choose,myString); } */
/* The user has a command, so spawn it in a child process */
pid = fork();
if (pid == -1) {
/* to understand why this is here, see man 2 fork */
cout << "A problem arose, the shell failed to spawn a child process" << endl;
return 1;
}
if (pid == 0) {
// Child process
execvp(myArgv[0], myArgv);
cout << "Bad command or file name, please try again!\n" << endl;
return 1;
}
/* This makes sure that the spawned process is run in the
foreground, because the user did not choose background */
if (bg == 0)
waitpid(pid, &status, 0);
}
return 0;
}

IPC using pipes?

I m trying to implement a program using pipes where parent process accepts a string and passes it to child process. Need to be done with only single pipe. How does the pipe read & write accepts string.
Here is my sample code! all!
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
using namespace std;
int main()
{
int pid[2];
ssize_t fbytes;
pid_t childpid;
char str[20], rev[20];
char buf[20], red[20];
pipe(pid);
if ((childpid = fork()) == -1) {
perror("Fork");
return(1);
}
if (childpid == 0) {
// child process close the input side of the pipe
close(pid[0]);
int i = -1, j = 0;
while (str[++i] != '\0') {
while(i >= 0) {
rev[j++] = str[--i];
}
rev[j] = '\0';
}
// Send reversed string through the output side of pipe
write(pid[1], rev, sizeof(rev));
close(pid[0]);
return(0);
} else {
cout << "Enter a String: ";
cin.getline(str, 20);
// Parent process closing the output side of pipe.
close(pid[1]);
// reading the string from the pipe
fbytes = read(pid[0], buf, sizeof(buf));
cout << "Reversed string: " << buf;
close(pid[0]);
}
return 0;
}
You never pass the string to be reversed to the child, so it reverses some random garbage and sends it to the parent.
Minor issues:
write(pid[1], rev, sizeof(rev));
close(pid[0]); // Should be pid[1]
return(0); // Should be _exit(0)
The reason you don't want to return from main in the child is that you don't know what consequences that will have. You may call exit handlers that manipulate real world objects that the parent expects to remain intact.

how to run same jar file multiple times by forking new child process every time?

i am trying to write a c++ program.
the program is required to run some jar files, run every jar file two times.
the problem is that the program runs every file just one time correctly.
at the second time i got an error message, as if the VM got a wrong command. However, it is the same command that run the jar files the first time !!!
This is the first few lines of the red-colored error message that i got.
Usage: java [-options] class [args...]
(to execute a class)
or java [-options] -jar jarfile [args...]
(to execute a jar file)
where options include:
-d32 use a 32-bit data model if available
-d64 use a 64-bit data model if available
-client to select the "client" VM
-server to select the "server" VM
This is my code.
This is the main file:
#include <iostream>
#include <fstream>
#include <signal.h>
#include <string.h>
#include <time.h>
#include "StringParser.h"
#include "ShellCore.h"
using namespace std;
int main() {
while (1) {
char checkers_command[] = "java -jar /home/samer/Downloads/chkr.jar";
char castle_command[] = "java -jar /home/samer/Downloads/cas.jar";
int child_status;
bool wait_bool = true;
cout << "Run Batch Shell> ";
cin.getline(input_command_line, 256);
if (strcasecmp("exit", input_command_line) == 0) {
cout << "The shell program will terminate\n";
exit(0);
} else {
char* commands;
for (int var = 0; var < 4; ++var) {
if (var % 2 == 0) {
commands = checkers_command;
} else if (var % 2 == 1) {
commands = castle_command;
}
char* arg_list_tokened[50];
parse_command_line(arg_list_tokened, commands);
spawn(arg_list_tokened[0], arg_list_tokened);
if (wait_bool) {
// The parent wait until the child finishes.
cout << "The parent will wait for " << arg_list_tokened[0] << endl;
wait(&child_status);
if (WIFEXITED(child_status)) {
printf("The child process exited normally with exit code %d\n",
WEXITSTATUS(child_status));
} else {
printf("The child process exited abnormally\n");
}
}
}
cout << "done\n";
}
}
return 0;
}
This is the "spawn" method in the Shellcore.cpp file:
The Shellcore.h contains the required includes for the Shellcore.cpp.
#include "ShellCore.h"
pid_t child_pid;
int spawn(char* program_name, char** args) {
child_pid = fork();
if (child_pid != 0) {
return child_pid;
} else {
execvp(program_name, args);
// If the execvp return, this indicate that an error occurred.
printf("From the spawn function in the parent process, execvp ERROR\n");
abort();
}
}
sorry for the long question and long code.
Thanks is advance :)
The parse function:
void parse_command_line(char* output_list[], char* command_line) {
char * pch;
int i = 0;
pch = strtok(command_line, " &\"");
output_list[0] = pch;
while (pch != NULL) {
i++;
pch = strtok(NULL, " &\"");
output_list[i] = pch;
}
output_list[++i] = NULL;
}
strtok() changes your string when you call it. You set the pointer "commands" to either checkers_command or castle_command but strtok is just going to overwrite the memory pointed to at each of the latter. If you copy checkers/castle rather than just point to it before calling your parse function you will have a fresh copy of checkers/castle each time through the loop.
There are much better ways to do this than strdup but for brevity sake you can simply do this. If you keep this method of copying the string (unadvisable) remember to call free() on the returned pointer when you are done with it or you will have a memory leak.
Change to something like this:
for (int var = 0; var < 4; ++var)
{
if (var % 2 == 0)
{
//commands = checkers_command;
commands = strdup(checkers_command);
}
else
if (var % 2 == 1)
{
//commands = castle_command;
commands = strdup(castle_command);
}
char* arg_list_tokened[50];
parse_command_line(arg_list_tokened, commands);
spawn(arg_list_tokened[0], arg_list_tokened);
//............
}

Child doesn't terminate correctly in fork

I am writing a c program for a class that is a small shell. The user inputs a command, and the code executes it using the exec() function.
I need to have a fork in the process so all the work is done in the child process. The only problem is that the child won't terminate properly and execute the command. When I run the code without the fork, it executes commands perfectly.
The problem seems to be coming from where I am creating the string to be used in the execv call. It's the line of code where I call strcpy. If I comment that out, things work fine. I also tried changing it to strncat with the same problem. I'm clueless as to what's causing this and welcome any help.
#include <sys/wait.h>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <unistd.h>
using namespace std;
string *tokenize(string line);
void setCommand(string *ary);
string command;
static int argument_length;
int main() {
string argument;
cout << "Please enter a unix command:\n";
getline(cin, argument);
string *ary = tokenize(argument);
//begin fork process
pid_t pID = fork();
if (pID == 0) { // child
setCommand(ary);
char *full_command[argument_length];
for (int i = 0; i <= argument_length; i++) {
if (i == 0) {
full_command[i] = (char *) command.c_str();
// cout<<"full_command " <<i << " = "<<full_command[i]<<endl;
} else if (i == argument_length) {
full_command[i] = (char *) 0;
} else {
full_command[i] = (char *) ary[i].c_str();
// cout<<"full_command " <<i << " = "<<full_command[i]<<endl;
}
}
char* arg1;
const char *tmpStr=command.c_str();
strcpy(arg1, tmpStr);
execv((const char*) arg1, full_command);
cout<<"I'm the child"<<endl;
} else if (pID < 0) { //error
cout<<"Could not fork"<<endl;
} else { //Parent
int childExitStatus;
pid_t wpID = waitpid(pID, &childExitStatus, WCONTINUED);
cout<<"wPID = "<< wpID<<endl;
if(WIFEXITED(childExitStatus))
cout<<"Completed "<<ary[0]<<endl;
else
cout<<"Could not terminate child properly."<<WEXITSTATUS(childExitStatus)<<endl;
}
// cout<<"Command = "<<command<<endl;
return 0;
}
string *tokenize(string line) //splits lines of text into seperate words
{
int counter = 0;
string tmp = "";
istringstream first_ss(line, istringstream::in);
istringstream second_ss(line, istringstream::in);
while (first_ss >> tmp) {
counter++;
}
argument_length = counter;
string *ary = new string[counter];
int i = 0;
while (second_ss >> tmp) {
ary[i] = tmp;
i++;
}
return ary;
}
void setCommand(string *ary) {
command = "/bin/" + ary[0];
// codeblock paste stops here
You said:
Its the line of code where I call
strcpy.
You haven't allocated any memory to store your string. The first parameter to strcpy is the destination pointer, and you're using an uninitialized value for that pointer. From the strcpy man page:
char *strcpy(char *s1, const char *s2);
The stpcpy() and strcpy() functions copy the string s2 to s1 (including
the terminating `\0' character).
There may be other issues, but this is the first thing I picked up on.

How to give Line feed to GNU readline in c++

I am very new to C++. In my code i am using readline to get the user input which is a command and that input will be processed accordingly. When user enters a command named "setflag", i should set a flag to TRUE in all the active sessions of my processes.
The code works just fine. I am able to update the flag in all the processes simultaneously using signals.
Problem:
Please compile the code as: g++ -lreadline -lncurses alex123.cpp -o alex123
Spawn three processes (am refering to them as P1, P2, P3) by executing the binary "alex123" on separate terminals. In P1 issue "setflag" command. You can see that "MYFLAG" is set to TRUE in P1. Also you can see that P2 and P3 are able to receive the signal. But in P2 and P3 you wont see the command prompt. Only if you press the "enter" key on P2 and P3, you will get the command prompt back.
I want this in such a way that command prompt should automatically come. Pls help me.
alex123.cpp
## Heading ##
#include "stdio.h"
#include "iostream"
#include "signal.h"
#include "sys/time.h"
#include "string"
#include "stdlib.h"
#include "sstream"
#include "sys/types.h"
#include "unistd.h"
#include "/usr/include/readline/readline.h"
#include "/usr/include/readline/history.h"
using namespace std;
bool myFlag = false;
void updateFlag(int i)
{
cout << "\nGot the signal.";
myFlag= true;
//To give line feed from within the code itself. I need the fix here.
putc(10,stdout); // This doesn't work.
}
int getOtherPids(string &pidList)
{
char pid[10];
string pidStr;
FILE *stream;
//Command the search the process alex123
std::string cmd = "pgrep -x alex123";
stream = popen(cmd.c_str(),"r");
if (stream == NULL)
{
cout << "\nWhat the hell\n";
return 0;
}
while (fgets(pid, 10, stream) != NULL)
{
for(int i=0;i<10;i++)
{
int p = (int)pid[i] - 48;
if ((p >= 0) && (p <= 9))
pidStr.append(1,pid[i]);
}
pidStr.append(1,' ');
pidList.append(pidStr);
pidStr.clear();
}
int status = pclose(stream);
if (status == -1)
{
cout << "\nWhat the hell!! AGAIN !!\n"; return 0;
}
return 1;
}
void notifyOthers()
{
string pidList;
string notifyCmd;
//Convert pid of type int to a string
int my_pid = getpid();
ostringstream os;
os << my_pid;
string myPid = os.str();
//Get other existing alex123 process list to which notification has to be sent.
if (!getOtherPids(pidList))
{
cout << "!!WARNING!! Couldn't get active pids\n";
return;
}
size_t pos = pidList.find(myPid.c_str());
if (pos == string::npos)
{
cout << "!!WARNING!! Other Active process list is empty.\n";
return;
}
//Remove current session pid from the pid list string.
pidList.replace(pos,myPid.length()+1,"");
//If there are no other existing alex123 processes, return from the function.
if(strcmp(pidList.c_str(),"") == 0) return;
pidList.replace(pidList.length()-1,1,"\0");
//Send SIGUSR1 signal to others.
notifyCmd = "kill -SIGUSR1 " + pidList;
system(notifyCmd.c_str());
}
int main()
{
char *foo;
for(;;)
{
//If SIGUSR1 is caught it means that some other process has set the myFlag to TRUE by issuing a "setflag" command.
//So it should be set here also.
signal(SIGUSR1, updateFlag);
cout << "\nMYFLAG:"<< myFlag <<endl;
foo = readline("<alex> ");
if(strcmp(foo,"exit") ==0) { return 0; }
if(strcmp(foo,"setflag") == 0)
{
//Set myFlag to TRUE in the current process from where "setflag" command was issued.
myFlag= true;
//Inform all other processes that myFlag has been updated.
notifyOthers();
}
}
return 0;
}