Is there any way to implement system() function - c

I tried to re-implement the system() library function. But I am not getting the output if i pass ps or ls command as an argument from the main. Thanks.
Original code:
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<error.h>
#define buf_size 512
int main(int argc, char *argv[])
{
pid_t pid;
char *buf[buf_size];
int ret = 0;
char ch;
int i = 0;
int j = 0;
if (argc != 2)
error(1, 0, "Too many of less number of arguments\n");
for (i = 1; i < argc; i++) {
*(buf + j) = argv[i];
j++;
}
buf[j] = '\0';
pid = fork();
if (pid == -1) {
error(1, 0, "error in creating the sub-process\n");
} else if (pid == 0) {
execv("bin/sh", buf);
} else {
wait(NULL);
}
}
Edited code after reading some comments in this post:
int main(int argc, char *argv[])
{
pid_t pid;
int ret;
if (argc != 2)
error(1, 0, "Too many of less number of arguments\n");
pid = fork();
if (pid == -1) {
error(1, 0, "error in creating the sub-process\n");
} else if (pid == 0) {
ret = execv("/bin/sh", argv);
if (ret == -1)
error(1, 0, "error in execv() system call\n");
} else {
wait(NULL);
}
}

You were not far from the solution.
The main thing you miss is that you should have launch /bin/sh -c ls instead of bin/sh ls
The corrections:
do not write buf[j] = "\0";, instead I increased the for loop size (notice the i<= argc)
launch /bin/sh (forgot leading /)
add sh and -c to sh options. (see man execv)
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<error.h>
int main(int argc, char *argv[])
{
pid_t pid;
char * buf[4];
if (argc != 2)
error(1, 0, "Too many of less number of arguments\n");
buf[0] = "sh";
buf[1] = "-c";
buf[2] = argv[1];
buf[3] = NULL;
pid = fork();
if (pid == -1) {
error(1, 0, "error in creating the sub-process\n");
} else if (pid == 0) {
execv("/bin/sh", buf);
perror("execv");
} else {
wait(NULL);
}
}

Related

How to accept multiple arguments in system() in Linux

I am trying to implement a system() using fork() and execl(). I am unable to accept multiple arguments like ls -l and ps -a1. The code works for arguments like ls and ps. I am unable to do it. It is not allowed to change the arguments and return type of my_system(). I am a beginner. Thanks:)
int my_system(const char *command)
{
int ret = 0;
ret = execl("/bin/sh", "sh", "-c", command, (char *)NULL);
if (ret == -1)
error(1, 0, "error occcured in the execl() system call\n");
return 0;
}
int main(int argc, char *argv[])
{
pid_t pid;
pid_t ret;
char *command;
int ret_system;
int wstatus;
if (argc < 2)
error(1, 0, "Too few arguments\n");
printf("The number of arguments are: %d", argc);
command = argv[1];
printf("The pid of the parent-process is :%d\n", getpid());
pid = fork();
if (pid == -1) {
error(1, 0, "error in creating the sub-process\n");
} else if (pid == 0) {
printf("The pid of the child- process is :%d\n", getpid());
ret_system = my_system(command);
} else {
ret = waitpid(-1, &wstatus, 0);
printf("The pid of the child that has terminated is %d and the status of exit is %d\n", ret, wstatus);
}
return 0;
}
You need to make 3 changes :
int my_system(char *argv[])
...
ret = execvp(argv[1], &argv[1]);
...
ret_system = my_system(argv);
int my_system(const char *command)
{
int ret = 0;
ret = execl("/bin/sh", "sh", "-c", command, (char *)NULL);
if (ret == -1)
error(1, 0, "error occcured in the execl() system call\n");
return 0;
}
char *get_command(int argc, char **argv)
{
int i = 0;
static char command[size];
strcpy(command, argv[1]);
for (i = 2; i < argc; i++) {
strcat(command, " ");
strcat(command, argv[i]);
}
return command;
}
int main(int argc, char *argv[])
{
pid_t pid;
pid_t ret;
int ret_system;
int i = 0;
int wstatus;
char *command;
if (argc < 2)
error(1, 0, "Too few arguments\n");
printf("The pid of the parent-process is :%d\n", getpid());
pid = fork();
if (pid == -1) {
error(1, 0, "error in creating the sub-process\n");
} else if (pid == 0) {
printf("The pid of the child- process is :%d\n", getpid());
command = get_command(argc, argv);
ret_system = my_system(command);
} else {
ret = waitpid(-1, &wstatus, 0);
printf("The pid of the child that has terminated is %d and the status of exit is %d\n", ret, wstatus);
}
return 0;
}

Creating a pipe in c between two programs

I have been working on creating a pipe in c between two programs, reader.c and writer.c. I haven't been able to get the input for the pipe program to work. The pipe program is supposed to take in a int, send it to the writer program, which then pipes its output into the reader program for the final output. Below is the code for the three classes. I think I am close but can anyone help me get the initial int input argv[2] into the writer class then into the reader class?
pipe program (communicat.c)
int main(int argc, char *argv[])
{
int fd[2];
pid_t childpid;
int result;
if (argc != 2)
{
printf("usage: communicate count\n");
return -1;
}
pipe(fd);
childpid = fork();
if (childpid == -1)
{
printf("Error in fork; program terminated\n");
return -1;
}
if(childpid == 0)
{
close(1);
dup(fd[1]);
execlp("writer", "writer", fd[1],(char *) NULL);
}
else
{
childpid = fork();
}
if( childpid == 0)
{
close(0);
dup(fd[0]);
close(fd[0]);
close(fd[1]);
execlp("reader", "reader", (char *) NULL);
}
else
{
close(fd[0]);
close(fd[1]);
int status;
wait(&status);
}
return(0);
}
Reader.c
int main()
{
int count; /* number of characters in the line */
int c; /* input read */
count = 0;
while ((c = getchar())!= EOF)
{
putchar(c); count++;
if (count == LINELENGTH)
{
putchar('\n'); count = 0;
}
}
if (count > 0)
putchar('\n');
return 0;
}
Writer.c
int main(int argc, char *argv[])
{
int count; /* number of repetitions */
int i; /* loop control variable */
if (argc != 2)
{
printf("usage: writer count\n");
return -1;
}
else count = atoi(argv[1]);
for (i = 0; i < count; i++)
{
printf("Hello");
printf("hello");
}
return 0;
}
Correct the code to exec writer this way:
if(childpid == 0)
{
close(1);
dup(fd[1]);
close(fd[0]);
close(fd[1]);
execlp("writer", "writer", argv[1], (char *) NULL);
}

Shell program with pipes in C

I have a problem with pipes. My program is a Shell program in C. I want to execute for example ls | wc, but what I get after running is:
ls: cannot access |: no such file or directory ls: cannot access wc: no such file or directory.
What am I doing wrong?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#define MAX_CMD_LENGTH 100
#define MAX_NUM_PARAMS 10
int parsecmd(char* cmd, char** params) { //split cmd into array of params
int i,n=-1;
for(i=0; i<MAX_NUM_PARAMS; i++) {
params[i] = strsep(&cmd, " ");
n++;
if(params[i] == NULL) break;
}
return(n);
};
int executecmd(char** params) {
pid_t pid = fork(); //fork process
if (pid == -1) { //error
char *error = strerror(errno);
printf("error fork!!\n");
return 1;
} else if (pid == 0) { // child process
execvp(params[0], params); //exec cmd
char *error = strerror(errno);
printf("unknown command\n");
return 0;
} else { // parent process
int childstatus;
waitpid(pid, &childstatus, 0);
return 1;
}
};
int execpipe (char ** argv1, char ** argv2) {
int fds[2];
pipe(fds);
int i;
pid_t pid = fork();
for (i=0; i<2; i++) {
if (pid == -1) { //error
char *error = strerror(errno);
printf("error fork!!\n");
return 1;
} else
if (pid == 0) {
if(i ==0){
close(fds[1]);
dup2(fds[0], 0);
close(fds[0]);
execvp(argv1[0], argv1);
char *error = strerror(errno);
printf("unknown command\n");
return 0;
} else if(i == 1) {
close(fds[0]);
dup2(fds[1], 1);
close(fds[1]);
execvp(argv2[0], argv2);
char *error = strerror(errno);
printf("unknown command\n");
return 0;
}
} else { // parent process
int childstatus;
waitpid(pid, &childstatus, 0);
return 1;
}
} // end for
};
int main() {
char cmd[MAX_CMD_LENGTH+1];
char * params[MAX_NUM_PARAMS+1];
char * argv1[MAX_NUM_PARAMS+1];
char * argv2[MAX_NUM_PARAMS+1];
int k, y, x;
int f = 1;
while(1) {
printf("$"); //prompt
if(fgets(cmd, sizeof(cmd), stdin) == NULL) break; //read command, ctrl+D exit
if(cmd[strlen(cmd)-1] == '\n') { //remove newline char
cmd[strlen(cmd)-1] = '\0';
}
int j=parsecmd(cmd, params); //split cmd into array of params
if (strcmp(params[0], "exit") == 0) break; //exit
for (k=0; k <j; k++) { //elegxos gia uparksi pipes
if (strcmp(params[k], "|") == 0) {
f = 0; y = k;
printf("pipe found\n");
}
}
if (f==0) {
for (x=0; x<k; x++) {
argv1[x]=params[x];
}
int z = 0;
for (x=k+1; x< j; x++) {
argv2[z]=params[x];
z++;
}
if (execpipe(argv1, argv2) == 0) break;
} else if (f==1) {
if (executecmd(params) == 0) break;
}
} // end while
return 0;
}
Updated your code with following corrections.
Removed for() loop that iterated two times after fork() call.
Removed incorrect close of pipe FDs after dup2 calls for both parent and child processes.
Aligned the command that needed to be run as per the file descriptors that were duplicated in dup2() calls for parent and child. Basically I needed to swap execvp(argv2[0], argv2) and execvp(argv1[0], argv1) calls.
Added a break; statement in the for loop that searched for pipe character.
The updated code is as below.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAX_CMD_LENGTH 100
#define MAX_NUM_PARAMS 10
int parsecmd(char* cmd, char** params) { //split cmd into array of params
int i,n=-1;
for(i=0; i<MAX_NUM_PARAMS; i++) {
params[i] = strsep(&cmd, " ");
n++;
if(params[i] == NULL) break;
}
return(n);
};
int executecmd(char** params) {
pid_t pid = fork(); //fork process
if (pid == -1) { //error
char *error = strerror(errno);
printf("error fork!!\n");
return 1;
} else if (pid == 0) { // child process
execvp(params[0], params); //exec cmd
char *error = strerror(errno);
printf("unknown command\n");
return 0;
} else { // parent process
int childstatus;
waitpid(pid, &childstatus, 0);
return 1;
}
};
int execpipe (char ** argv1, char ** argv2) {
int fds[2];
pipe(fds);
int i;
pid_t pid = fork();
if (pid == -1) { //error
char *error = strerror(errno);
printf("error fork!!\n");
return 1;
}
if (pid == 0) { // child process
close(fds[1]);
dup2(fds[0], 0);
//close(fds[0]);
execvp(argv2[0], argv2); // run command AFTER pipe character in userinput
char *error = strerror(errno);
printf("unknown command\n");
return 0;
} else { // parent process
close(fds[0]);
dup2(fds[1], 1);
//close(fds[1]);
execvp(argv1[0], argv1); // run command BEFORE pipe character in userinput
char *error = strerror(errno);
printf("unknown command\n");
return 0;
}
};
int main() {
char cmd[MAX_CMD_LENGTH+1];
char * params[MAX_NUM_PARAMS+1];
char * argv1[MAX_NUM_PARAMS+1] = {0};
char * argv2[MAX_NUM_PARAMS+1] = {0};
int k, y, x;
int f = 1;
while(1) {
printf("$"); //prompt
if(fgets(cmd, sizeof(cmd), stdin) == NULL) break; //read command, ctrl+D exit
if(cmd[strlen(cmd)-1] == '\n') { //remove newline char
cmd[strlen(cmd)-1] = '\0';
}
int j=parsecmd(cmd, params); //split cmd into array of params
if (strcmp(params[0], "exit") == 0) break; //exit
for (k=0; k <j; k++) { //elegxos gia uparksi pipes
if (strcmp(params[k], "|") == 0) {
f = 0; y = k;
printf("pipe found\n");
break;
}
}
if (f==0) {
for (x=0; x<k; x++) {
argv1[x]=params[x];
}
int z = 0;
for (x=k+1; x< j; x++) {
argv2[z]=params[x];
z++;
}
if (execpipe(argv1, argv2) == 0) break;
} else if (f==1) {
if (executecmd(params) == 0) break;
}
} // end while
return 0;
}
If you are interested only in changes I made, here is the diff between your code and the above updated code:
--- original.c
+++ updated.c
## -4,6 +4,7 ##
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
+#include <sys/wait.h>
#define MAX_CMD_LENGTH 100
## -43,44 +44,36 ##
pipe(fds);
int i;
pid_t pid = fork();
- for (i=0; i<2; i++) {
if (pid == -1) { //error
char *error = strerror(errno);
printf("error fork!!\n");
return 1;
- } else
- if (pid == 0) {
- if(i ==0){
+ }
+ if (pid == 0) { // child process
close(fds[1]);
dup2(fds[0], 0);
- close(fds[0]);
- execvp(argv1[0], argv1);
+ //close(fds[0]);
+ execvp(argv2[0], argv2); // run command AFTER pipe character in userinput
char *error = strerror(errno);
printf("unknown command\n");
return 0;
- } else if(i == 1) {
+ } else { // parent process
close(fds[0]);
dup2(fds[1], 1);
- close(fds[1]);
- execvp(argv2[0], argv2);
+ //close(fds[1]);
+ execvp(argv1[0], argv1); // run command BEFORE pipe character in userinput
char *error = strerror(errno);
printf("unknown command\n");
return 0;
}
- } else { // parent process
- int childstatus;
- waitpid(pid, &childstatus, 0);
- return 1;
- }
- } // end for
};
int main() {
char cmd[MAX_CMD_LENGTH+1];
char * params[MAX_NUM_PARAMS+1];
- char * argv1[MAX_NUM_PARAMS+1];
- char * argv2[MAX_NUM_PARAMS+1];
+ char * argv1[MAX_NUM_PARAMS+1] = {0};
+ char * argv2[MAX_NUM_PARAMS+1] = {0};
int k, y, x;
int f = 1;
while(1) {
## -95,6 +88,7 ##
if (strcmp(params[k], "|") == 0) {
f = 0; y = k;
printf("pipe found\n");
+ break;
}
}
if (f==0) {
execv* procedure doesn't interpret shell script string. It merely starts an executable file and passes an array of arguments to it. Thus, it cannot organize a pipeline.
If you need "normal" shell command execution, you may want to use system(char*) procedure instead of execvp.
Otherwise, if you need to do the pipes yourself, you may want to parse the string with '|' special characters and use pipe(), fork() and I/O redirection. Like here How to run a command using pipe?

Error when process run an instance of xterm with fork

I am given the task of forking n processes.
For each process, it must start an instance of /bin/xterm
I am done with the part of generating n processes and opening the xterm instance.
I got this output when I tried running the program. (Error in bold)
Number of process to open is 1.
Child (1): 3457
/bin/xterm: Xt error: Can't open display:
/bin/xterm: DISPLAY is not set
My code is below.
I tried googleing for the error but I have no luck so far.
Any solutions?
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char *argv[])
{
int num = atoi(argv[1]);
printf("Number of process to open is %d.\n", num);
int pid;
int i;
for(i = 0; i < num; i++)
{
pid = fork();
if(pid < 0) {
printf("Error");
exit(1);
} else if (pid == 0) {
printf("Child (%d): %d\n", i + 1, getpid());
char * const argv[] = {"/bin/xterm", NULL};
char * const envp[] = {NULL};
int rc = execve ("/bin/xterm", argv, envp);
exit(0);
} else {
wait(NULL);
}
}
return 0;
}
This little changed code works perfectly fine on my system:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main(int argc, char *argv[])
{
int num = atoi(argv[1]);
printf("Number of process to open is %d.\n", num);
int pid;
int i;
for(i = 0; i < num; i++)
{
pid = fork();
if(pid < 0) {
printf("Error");
exit(1);
} else if (pid == 0) {
//printf("Child (%d): %d\n", i + 1, getpid());
//char * const argv[] = {"/bin/xterm", NULL};
//char * const envp[] = {NULL};
execl("/usr/bin/xterm", "/usr/bin/xterm", NULL);
//exit(0);
}else {
wait(NULL);
}
}
return 0;
}
The error was explained in the output you pasted:
/bin/xterm: DISPLAY is not set
You need to set DISPLAY appropriately. Otherwise, it will have no way to know where to put its display.
Also, did you really want to wait for each child after creating it?
Use
char *envp[] = {"TERM=vt100", "PATH=/bin:/usr/bin", "DISPLAY=:0.0",(char *) 0 };
Doing so you set the display on your machine.
Sorry I'm late.

Run N concurrent processes in C

I am trying to run N concurrent processes in a C program. I've built a simple example that takes commands as arguments, creates a fork for each one, and executes it.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int i;
for(i = 1; i < argc; i++)
{
pid_t pid = fork();
if(pid < 0)
{
fprintf(stderr, "forking error\n");
exit(1);
}
else if(pid > 0)
{
int status;
waitpid(pid, &status, 0);
printf("Command %s has completed successfully by PID=%d\n", argv[i], pid);
}
else
{
char cmd[1024];
sprintf(cmd, "%s", argv[i], i);
system(cmd);
_exit(1);
}
}
printf("Finished\n");
return 0;
}
This seems to run the processes correctly, but not concurrently. Any ideas as to what am I doing wrong?
EDIT: I've edited based on suggestions, but this also does not seem to work.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int i;
pid_t *pids = malloc( sizeof(pid_t) * (argc) );
int *statuses = malloc( sizeof(int) * (argc) );
for(i = 1; i < argc; i++)
{
pid_t pid = fork();
if(pid < 0)
{
fprintf(stderr, "forking error\n");
exit(1);
}
else if(pid > 0)
{
//int status;
//waitpid(pid, &status, 0);
//printf("Command %s has completed successfully by PID=%d\n", argv[i], pid);
pids[i] = pid;
}
else
{
char cmd[1024];
sprintf(cmd, "%s > out.%d", argv[i], i);
system(cmd);
_exit(1);
}
}
int needtowait = 0;
do
{
needtowait = 0;
for(i = 1; i < argc; i++)
{
if(pids[i] > 0)
{
if(waitpid(pids[i], &statuses[i], 0) != 0)
{
pids[i] = 0;
char *successstr = "successfully";
if(statuses[i])
{
successstr = "unsuccessfully";
}
printf("Command %s has completed %s by PID=%d\n", argv[i], successstr, pids[i]);
}
}
else
{
needtowait = 1;
}
sleep(0);
}
} while(needtowait);
printf("Finished!\n");
return 0;
}
The reason you are not running these processes concurrently is in this line:
waitpid(pid, &status, 0);
The main process that forks out the child process waits for the child process to exit before continuing with the loop, and starting the next process.
Since you want to run your processes concurrently, you can do this: allocate an array of pid_t for process IDs, and fill it in inside the loop. Once you are out of the loop, you can wait for the individual processes to complete by executing waitpid calls in a loop.
pid_t *pids = malloc(argc * sizeof(pid_t));
for (int i = 0 ; i < argc ; i++) { // Start i at 0, not at 1
pid_t pid = fork();
if (pid < 0) {
...
} else if (pid > 0) {
pids[i] = pid;
} else {
char cmd[1024];
sprintf(cmd, "%s", argv[i+1], i+1);
system(cmd);
_exit(1);
}
}
for (int i = 0 ; i < argc ; i++) {
int status;
waitpid(pids[i], &status, 0);
printf("Command %s has completed successfully by PID=%d\n", argv[i+1], pids[i]);
}
Sure. Your parent process is waiting for the child process to finish executing before forking again. You're just running cmd sequentially N times.

Resources