I want to pass a int variable to another process after exec*
here is my code:
typedef union{
int i;
char c[4];
}t_t;
/* parent */
int main(int ac, char *av[])
{
t_t tv;
tv.i = 12345;
if(fork() == 0)
execlp("./test", tv.c, "abcd", (char *)0);
return 0;
}
/* child */
int main(int ac, char *av[])
{
t_t tv;
memcpy(tv.c, av[0], sizeof(int));
printf("child: ac=%d, av0: %d, av1: %s\n", ac, tv.i, av[1]);
return 0;
}
here is output:
child: ac=2, av0: 1627402297, av1: abcd
I also try like this:
int i;
execlp("./test", (char *)i, "abcd", (char *)0);
the argv[0] in the child is unexpected always.
I wonder why it can't work like I expected.
The union isn't converting the number to its string representation as you seem to expect. What it's actually doing is allowing access to the individual bytes that make up the int, which is not a string. Passing a character array that is not a string to a function expecting a string invokes undefined behavior.
What you want instead is to use snprintf to convert the integer to a string and pass that string to execlp. Then in the child process, use atoi to convert the string back to an integer.
/* parent */
int main(int argc, char *argv[])
{
char str[50];
snprintf(str, sizeof(str), "%d", 12345);
if(fork() == 0)
execlp("./test", str, "abcd", (char *)0);
return 0;
}
/* child */
int main(int argc, char *argv[])
{
int i = atoi(argv[0]);
printf("child: argc=%d, argv0: %d, argv1: %s\n", argc, i, argv[1]);
return 0;
}
Related
I would like to send an int from one process to another through shared memory.
I tried simply placing the value of the int into the shared memory (&number) - didnt work.
I tired casting the string to bytes into a char array (memcpy) and reading a sizeof(int) from the other process - didn't work.
i tired memcpy the value of the int into a char array, sending it to the other process, copying back it with memcpy : from the char array into an int - didn't work
My last attempt is this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/stat.h> // S_IRUSR
int main(int argc, char *argv[])
{
pid_t gyerek;
key_t kulcs;
int oszt_mem_id;
char *s;
kulcs = ftok(argv[0], 1);
oszt_mem_id = shmget(kulcs, 500, IPC_CREAT | S_IRUSR | S_IWUSR);
s = shmat(oszt_mem_id, NULL, 0);
gyerek = fork();
if (gyerek == 0)
{
//printf("Child read this: %s\n", s);
char szamarr[10];
int szam = 12;
memcpy(&szamarr, &szam, sizeof(int));
strcpy(s, szamarr);
sleep(1);
strcpy(s, &szam);
sleep(3);
shmdt(s);
}
else
{
sleep(2);
int szam;
char szamarr[10];
memcpy(&szamarr, &s, sizeof(int));
printf("Parent read this: %s\n", szamarr);
sleep(1);
int szam2 = (int) s;
printf("Parent read this: %s\n", s);
shmdt(s);
wait(NULL);
shmctl(oszt_mem_id, IPC_RMID, NULL);
}
}
The result is either a random number and nothing
You don't need to involve strings if you only want to pass an int. However generally, it's easier to use structures for this kind of communication:
typedef struct {
int szam;
// ...
} mystruct_t;
int main(int argc, char *argv[])
{
pid_t gyerek;
key_t kulcs;
int oszt_mem_id;
char *s;
kulcs = ftok(argv[0], 1);
oszt_mem_id = shmget(kulcs, sizeof(mystruct_t), IPC_CREAT | S_IRUSR | S_IWUSR);
s = shmat(oszt_mem_id, NULL, 0);
gyerek = fork();
if (gyerek == 0) // child
{
mystruct_t ms={0};
ms.szam = 12;
memcpy(s, &ms, sizeof(mystruct_t));
sleep(3);
shmdt(s);
}
else // parent
{
sleep(1);
mystruct_t ms={0};
memcpy(&ms, s, sizeof(mystruct_t));
printf("Parent read this: %d\n", ms.szam);
shmdt(s);
wait(NULL);
shmctl(oszt_mem_id, IPC_RMID, NULL);
}
}
I am writing a code to interact with an application involving reading and writing to the application. Here is the code: the first one - namely input.c interacts with the second one - namely app.c
//input.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#define WRITE 1
#define READ 0
void error(char* msg){
perror(msg);
exit(-1);
}
void got_here(char* msg){
printf("Got_here:%s\n",msg);
}
int main(int argc, char** argv, char** envp){
int fd_parent[2];
int fd_child[2]; // for parent and child to write respectively
if(pipe(fd_parent) < 0 | pipe(fd_child) < 0){
error("Fail to create a pipe"); /// just an error-handle function
}
pid_t child = fork();
if(child < 0){
error("Fail to create a child");
}
else if(child == 0){
dup2(fd_child[WRITE], STDOUT_FILENO);
dup2(fd_parent[READ], STDIN_FILENO);
close(fd_parent[WRITE]);
close(fd_child[READ]);
char str[100] = "./app";
execve(str, argv,envp);
close(fd_parent[READ]);
close(fd_child[WRITE]);
return 0;
}
else{
close(fd_parent[READ]);
close(fd_child[WRITE]);
FILE* stream = fdopen(fd_child[READ], "r");
FILE* stream_write = fdopen(fd_parent[WRITE], "w");
char str[20];
char menu[4] = "10\n";
fread(str,sizeof(char), 20, stream); // Here is where the problem lies
got_here("after read"); // it does not get here
fwrite(menu, sizeof(char), 3, stream_write);
fflush(stream_write);
fclose(stream);
fclose(stream_write);
printf("Parent Done\n");
return 0;
}
}
Here is the application code (I only include the main for shorter code):
int main(int argc, char** argv, char** envp){
char str[10];
printf("- Select Menu -1\n");
printf("1. Play Lotto\n");
scanf("%s", str);
return 0;
}
After running, my program just paused at the fread() line where it is supposed to finish reading and write to the application. The interesting is if I omit either the scanf() or printf() in the second program it works fine. I try change the place of the fwrite and fread but the problem is still there. I think it is buffer-related problem, but the application I am trying to interact with is not of my permission to change, so I cannot include fflush or something.
Is my guess right or there is another explanation for this? And how to get over this problem?
You can use stdbuf command to modify the buffering options of the program at the other end of a pipe. In order to do this in C, you can write:
char str[100] = "./app";
char **new_argv = malloc (sizeof (char *) * (argc + 9));
new_argv[0] = "stdbuf";
new_argv[1] = "-i";
new_argv[2] = "0";
new_argv[3] = "-o";
new_argv[4] = "L";
new_argv[5] = "-e";
new_argv[6] = "L";
new_argv[7] = str;
memcpy (&new_argv[8], &argv[1], argc - 1);
new_argv[argc + 8] = NULL;
execvp ("stdbuf", new_argv);
error ("execvp");
or if you don't really need to pass the arguments of the parent on to the child, then:
execlp ("stdbuf", "stdbuf", "-i", "0", "-o", "L", "-e", "L", "./app", NULL);
error ("execlp");
The stdbuf command uses LD_PRELOAD to load a library (libstdbuf.so) into the other program. This library does the trick of modifying the buffering options. You can avoid the use of stdbuf and set the preload options yourself before exec(). You can also write your own library and preload that instead. But using the stdbuf is probably the easiest option, if you have this command available.
See also stdbuf source code
Here's the full modified example of your code:
//input.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#define WRITE 1
#define READ 0
void error (char *msg)
{
perror (msg);
exit (-1);
}
void got_here (char *msg)
{
printf ("Got_here: %s\n", msg);
}
int main (int argc, char **argv, char **envp)
{
int fd_parent[2];
int fd_child[2]; // for parent and child to write respectively
pid_t child;
if (pipe (fd_parent) < 0) {
error ("pipe(fd_parent)");
}
if (pipe (fd_child) < 0) {
error ("pipe(fd_child)");
}
child = fork ();
if (child < 0) {
error ("fork");
} else if (child == 0) {
dup2 (fd_child[WRITE], STDOUT_FILENO);
dup2 (fd_parent[READ], STDIN_FILENO);
close (fd_parent[WRITE]);
close (fd_child[READ]);
char str[100] = "./app";
char **new_argv = malloc (sizeof (char *) * (argc + 9));
new_argv[0] = "stdbuf";
new_argv[1] = "-i";
new_argv[2] = "0";
new_argv[3] = "-o";
new_argv[4] = "L";
new_argv[5] = "-e";
new_argv[6] = "L";
new_argv[7] = str;
memcpy (&new_argv[8], &argv[1], argc - 1);
new_argv[argc + 8] = NULL;
execvp ("stdbuf", new_argv);
error ("execvp");
close (fd_parent[READ]);
close (fd_child[WRITE]);
return 0;
} else {
close (fd_parent[READ]);
close (fd_child[WRITE]);
FILE *stream = fdopen (fd_child[READ], "r");
FILE *stream_write = fdopen (fd_parent[WRITE], "w");
char str[20];
char menu[4] = "10\n";
int res = fread (str, sizeof (char), 20, stream); // Here is where the problem lies
printf ("res = %d\n", res);
got_here ("after read"); // it does not get here
fwrite (menu, sizeof (char), 3, stream_write);
fflush (stream_write);
fclose (stream);
fclose (stream_write);
printf ("Parent Done\n");
return 0;
}
}
So I'm trying to create a custom shell for my school project. My method was to create child process, and have that process execute the command using the execvp() function that my professor briefly mentioned in class that we are meant to use. Here's my code, as always, any help is appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#define MAX_LINE 80
int main(int argc, char *argv[])
{
char *input = (char*)malloc(MAX_LINE*sizeof(char));
int should_run = 1;
while(should_run){
printf("osh>");
fflush(stdout);
pid_t pid;
pid = fork();
if(pid < 0){
printf("error with creating chiled process");
return 0;
}
if(pid == 0){
fgets(input, MAX_LINE, stdin);
char *token = strtok(input," ");
if(execvp(token[0], token) < 0){
printf("Error in execution.");
return(0);
}
//should_run = 0;
}
waitpid(pid, 1, 0);
}
return 0;
}
The prototype of execvp is
int execvp(const char *file, char *const argv[]);
It expects a pointer to char as the first argument, and a NULL-terminated
pointer to an array of char*. You are passing completely wrong arguments.
You are passing a single char as first argument and a char* as the second.
Use execlp instead:
int execlp(const char *file, const char *arg, ...
/* (char *) NULL */);
So
char *token = strtok(input," \n");
if(token == NULL)
{
fprintf(stderr, "only delimiters in line\n");
exit(1);
}
if(execlp(token, token, NULL) < 0){
fprintf(stderr, "Error in execution: %s\n", strerror(errno));
exit(1);
}
Also the convention in UNIX is to print error messages to stderr and a process with an error should
have an exit status other than 0.
As Pablo's states, you are passing the wrong arguments to execvp().
You can consider coding by yourself a function (char **strsplit(char *str, char delim)) which takes a string and split it into smaller pieces, returning an array of strings.
Also don't ignore compiler's warnings, they tell you a lot of things, and I suggest you to compile with gcc -Wall -Wextra -Werror to get almost any possible error in your program.
I tell you this because waitpid() takes as second argument a pointer to integer, to get an update of the status of the forked program. With this status you how the program exited (normally, segf, bus error...), you can use it to print an error if something went wrong.
You can consider using execv() instead (I know I'm going off topic, but you can learn useful things doing this), and find by yourself the correct executable(s).
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#define MAX_LINE 255
char **strsplit(char *str, char delim);
char *strjoin(char const *s1, char const *s2);
int isexec(char *path)
{
struct stat buf;
lstat(path, &buf);
if (S_ISREG(buf.st_mode) && (S_IXUSR & buf.st_mode))
return (1);
return (0);
}
static char *find_exec_readdir(char *paths, char *cmd)
{
DIR *dir;
struct dirent *dirent;
char *exec;
exec = NULL;
if ((dir = opendir(paths)) != NULL)
{
while ((dirent = readdir(dir)) != NULL)
{
if (!strcmp(dirent->d_name, cmd))
{
exec = strdup(dirent->d_name);
break ;
}
}
if (closedir(dir))
dprintf(2, "Failed closing dir.\n");
}
return (exec);
}
char *find_exec(char *cmd, char **paths)
{
char *exec;
char *path;
char *tmp;
int i;
i = -1;
exec = NULL;
path = NULL;
if ((cmd[0] == '.' || cmd[0] == '/'))
{
if (isexec(cmd))
return (strdup(cmd));
return (NULL);
}
while (paths[++i])
if ((exec = find_exec_readdir(paths[i], cmd)) != NULL)
{
tmp = strjoin(paths[i], "/");
path = strjoin(tmp, exec);
free(tmp);
free(exec);
break ;
}
return (path);
}
int handle_return_status(int status)
{
int sig;
int i;
if (!WIFEXITED(status) && WIFSIGNALED(status))
{
sig = WTERMSIG(status);
i = -1;
while (++i <= 13)
{
if (print_signal_error(sig))
{
return (-1);
}
}
dprintf(2, "Process terminated with unknown signal: %d\n", sig, NULL);
return (-1);
}
return (0);
}
int main(int argc, char *argv[])
{
char *input = NULL;
char **command = NULL;
int should_run = 1;
int status = 0;
(void)argc;
(void)argv;
if ((input = (char*)malloc(MAX_LINE*sizeof(char))) == NULL)
return (dprintf(2, "Failed to malloc, abort.\n"));
while(should_run){
printf("osh> ");
fflush(stdout);
pid_t pid;
pid = fork();
if(pid < 0)
return (dprintf(2, "error with creating chiled process\n"));
if(pid == 0){
fgets(input, MAX_LINE, stdin);
command = strsplit(input, ' ');
command[0] = find_exec(command[0], strsplit(getenv("PATH"), ':'));
if(execv(command[0], &command[1]) < 0)
return (dprintf(2, "Error in execution.\n"));
//should_run = 0;
}
waitpid(pid, &status, 0);
handle_ret_status(status);
}
return 0;
}
#define SMALL_STACK 131072 //128K for stack
pthread_attr_t thread_attr; //for attr
void* fn(void* arg)
{ //fn fuction
printf("%d", (char *) arg);
return NULL;
}
int main(int argc, char** argv)
{
printf("Have ");
printf(" arguments:"); //checking multiple arguments
for (int i = 0; i < argc; ++i)
{
printf("%s", argv[i]);
}
printf("\n");
pthread_attr_init(&thread_attr);
pthread_attr_setstacksize(&thread_attr, SMALL_STACK);
pthread_t th; //creating thread and stack
/* I Need Help (void*)&argv[1] passing this to void *fn function printing the argument coming from command line arguments */
pthread_create(&th, &thread_attr, fn, (void*) &argv[1]); //creating thread
return 0;
}
In my opinion, you should pass a struct instance to your thread parameter.
Below, an example:
struct MyThreadData
{
int argc,
char** argv;
}
void* fn(void* arg)
{
MyThreadData* data=(MyThreadData*)arg;
/*code*/
return NULL;
}
int main(int argc, char** argv)
{
/*...*/
MyThreadData td={0};
td.argc=argc;
td.argv=argv;
void* ret = NULL;
pthread_create(&th, &thread_attr, fn, (void*)&td);
pthread_join(th,&ret)
}
To pass one argument (here: the 1st) change
pthread_create(&th, &thread_attr, fn, (void*)&argv[1]);
to be
pthread_create(&th, &thread_attr, fn, argv[1]);
To inside the thread function print the string use the correct conversion specifier:
printf("%s", (char *)arg);
or in a "cleaner" manner do
void* fn(void* arg)
{
char * pc = arg;
printf("%s\n", pc); /* add a new-line to flush stdout, to
have this printed immediately. */
To pass all arguments then change
pthread_create(&th, &thread_attr, fn, (void*)&argv[1]);
to be
pthread_create(&th, &thread_attr, fn, argv);
and adjust the thread function as follows:
void* fn(void* arg)
{
char ** ppc = arg;
while (*ppc)
{
printf("%s\n", *ppc);
++ppc;
}
...
Also make sure main() does not return the standard way, as this then ends the process, which in turn ends all threads of the process.
To do so replace
return 0;
by
pthread_exit(NULL);
I'm writing a program in which I use the system call fork() to create a child process, and then create a grandchild, as well as creating a pipe between the child and grandchild. I think my implementation is fairly good, however when I run the program, it simply skips right through the prompts in my code.
Essentially we have this:
-Process starts
Fork() create child
Child creates pipe
Fork() creates grandchild, pipe inherited.
TL;DR- Code skips through UI prompts, not sure if I'm entering data correctly, not sure if I'm reading data into processes correctly.
How do I read inputs down the pipe?
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
void main(int argc, char *argv[])
{
int p[2];
int pid, pid2;
pid = fork();
if(pid == 0)
{
pipe(p);
pid2 = fork();
switch(pid2)
{
case -1:
printf("CASE 1");
exit(-1);
case 0:
close(0);
dup(p[0]);
close(p[0]);
close(p[1]);
execl("./Sort/sort", 0);
break;
default:
close(1);
dup(p[1]);
close(p[1]);
close(p[0]);
execl("./Pre/pre", 0);
break;
}
}
else
{
wait(pid);
printf("Process Completed\n");
exit(0);
}
}
Child process for pre:
#include <stdio.h>
void main (int argc, char *argv[])
{
char n1[20];
int g1;
FILE *ofp, *ifp;
int track;
ofp = fopen("output.txt", "w");
while(track != -1)
{
printf("Please enter the student's grade and then name, ");
printf("separated by a space: ");
scanf("%3d %s", &g1, n1);
if (g1 >= 60)
{
fprintf(ofp, "%s\n", n1);
}
printf("Add another name?(-1 to quit, 0 to continue): ");
scanf("%d", &track);
}
fclose(ofp);
ifp = fopen("output.txt", "r");
printf("Students that made a 60+:\n");
while(fscanf(ifp, "%s", n1) == 1)
printf("%s\n", n1);
fclose(ifp);
Child process for sort:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int stringcmp(const void *a, const void *b)
{
const char **ia = (const char **)a;
const char **ib = (const char **)b;
return strcmp(*ia, *ib);
}
void main(int argc, char *argv[])
{
int i = 0;
int num = 0;
int j = 0;
char name[20];
printf("How many names would you like to enter? ");
scanf("%d", &num);
char **input = malloc(num * sizeof(char*));
for (i=0; i < num; i++)
{
printf("Please input a name(first only): ");
scanf("%s", name);
input[i] = strdup(name);
}
qsort(input, num, sizeof(char *), stringcmp);
printf("Names:\n");
for(j = 0; j < num; j++)
printf("%s\n", input[j]);
for( i = 0; i < num; i++ ) free(input[i]);
free(input);
Observe that pre outputs prompts to stdout. That text will end up in the pipe, which is going to end up in sort's stdin.
You should fprintf all your prompts to stderr.
pre also doesn't output text in the format expected by sort; sort expects an integer n followed by n words (first names). So, that should be the only text that pre outputs on stdout; everything else needs to go to a file or stderr.
P.S. Also, use dup2(p[0], 0) instead of close(0); dup(p[0]) as it makes your intent clearer, as well as potentially avoiding threading issues (of course only relevant if you have threads, but it's worth keeping in mind).
Here's are two examples of how to do it
http://www.gnu.org/software/libc/manual/html_node/Creating-a-Pipe.html
http://tldp.org/LDP/lpg/node11.html
Edit: I can tell that you are trying to pipe the output of "./Pre/pre" to the input of "./Sort/sort" but I'm not sure what you mean by "Code skips through UI prompts" because for case 1: and default: you don't have any prompts. What exactly is the problem? If you want something more specific please explain more of the details in your question.